@contentful/field-editor-reference 5.19.0 → 5.20.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.
Files changed (115) hide show
  1. package/dist/cjs/__fixtures__/FakeSdk.js +3 -3
  2. package/dist/cjs/__fixtures__/asset/index.js +10 -10
  3. package/dist/cjs/__fixtures__/content-type/index.js +1 -1
  4. package/dist/cjs/__fixtures__/entry/index.js +7 -7
  5. package/dist/cjs/__fixtures__/fixtures.js +8 -6
  6. package/dist/cjs/__fixtures__/locale/index.js +2 -2
  7. package/dist/cjs/__fixtures__/space/index.js +1 -1
  8. package/dist/cjs/assets/MultipleMediaEditor.js +7 -5
  9. package/dist/cjs/assets/SingleMediaEditor.js +6 -4
  10. package/dist/cjs/assets/WrappedAssetCard/AssetCardActions.js +21 -19
  11. package/dist/cjs/assets/WrappedAssetCard/FetchingWrappedAssetCard.js +18 -11
  12. package/dist/cjs/assets/WrappedAssetCard/WrappedAssetCard.js +20 -11
  13. package/dist/cjs/assets/WrappedAssetCard/WrappedAssetLink.js +12 -9
  14. package/dist/cjs/assets/index.js +3 -3
  15. package/dist/cjs/common/EntityStore.js +53 -53
  16. package/dist/cjs/common/MultipleReferenceEditor.js +20 -11
  17. package/dist/cjs/common/ReferenceEditor.js +7 -5
  18. package/dist/cjs/common/SingleReferenceEditor.js +11 -7
  19. package/dist/cjs/common/SortableLinkList.js +14 -14
  20. package/dist/cjs/common/customCardTypes.js +4 -2
  21. package/dist/cjs/common/queryClient.js +102 -0
  22. package/dist/cjs/common/useContentTypePermissions.js +3 -1
  23. package/dist/cjs/common/useEditorPermissions.js +15 -3
  24. package/dist/cjs/common/useEditorPermissions.spec.js +13 -12
  25. package/dist/cjs/components/AssetThumbnail/AssetThumbnail.js +5 -3
  26. package/dist/cjs/components/CreateEntryLinkButton/CreateEntryLinkButton.js +13 -9
  27. package/dist/cjs/components/CreateEntryLinkButton/CreateEntryLinkButton.spec.js +17 -15
  28. package/dist/cjs/components/CreateEntryLinkButton/CreateEntryMenuTrigger.js +29 -19
  29. package/dist/cjs/components/CreateEntryLinkButton/CreateEntryMenuTrigger.spec.js +14 -12
  30. package/dist/cjs/components/LinkActions/CombinedLinkActions.js +28 -21
  31. package/dist/cjs/components/LinkActions/LinkActions.js +17 -15
  32. package/dist/cjs/components/LinkActions/LinkEntityActions.js +26 -17
  33. package/dist/cjs/components/LinkActions/NoLinkPermissionsInfo.js +5 -3
  34. package/dist/cjs/components/LinkActions/helpers.js +10 -5
  35. package/dist/cjs/components/LinkActions/redesignStyles.js +4 -4
  36. package/dist/cjs/components/LinkActions/styles.js +1 -1
  37. package/dist/cjs/components/MissingEntityCard/MissingEntityCard.js +11 -9
  38. package/dist/cjs/components/ResourceEntityErrorCard/ResourceEntityErrorCard.js +6 -4
  39. package/dist/cjs/components/ResourceEntityErrorCard/UnsupportedEntityCard.js +6 -4
  40. package/dist/cjs/components/ScheduledIconWithTooltip/ScheduleTooltip.js +10 -8
  41. package/dist/cjs/components/ScheduledIconWithTooltip/ScheduledIconWithTooltip.js +9 -4
  42. package/dist/cjs/components/ScheduledIconWithTooltip/formatDateAndTime.js +5 -4
  43. package/dist/cjs/components/SpaceName/SpaceName.js +9 -7
  44. package/dist/cjs/components/index.js +12 -12
  45. package/dist/cjs/entries/MultipleEntryReferenceEditor.js +9 -7
  46. package/dist/cjs/entries/SingleEntryReferenceEditor.js +7 -5
  47. package/dist/cjs/entries/WrappedEntryCard/FetchingWrappedEntryCard.js +20 -11
  48. package/dist/cjs/entries/WrappedEntryCard/WrappedEntryCard.js +23 -17
  49. package/dist/cjs/entries/index.js +3 -3
  50. package/dist/cjs/index.js +38 -34
  51. package/dist/cjs/resources/Cards/ContentfulEntryCard.js +13 -4
  52. package/dist/cjs/resources/Cards/ResourceCard.js +16 -12
  53. package/dist/cjs/resources/Cards/ResourceCard.spec.js +20 -17
  54. package/dist/cjs/resources/MultipleResourceReferenceEditor.js +20 -17
  55. package/dist/cjs/resources/MultipleResourceReferenceEditor.spec.js +34 -13
  56. package/dist/cjs/resources/SingleResourceReferenceEditor.js +11 -9
  57. package/dist/cjs/resources/SingleResourceReferenceEditor.spec.js +13 -6
  58. package/dist/cjs/resources/testHelpers/resourceEditorHelpers.js +12 -5
  59. package/dist/cjs/resources/useResourceLinkActions.js +11 -2
  60. package/dist/cjs/types.js +3 -3
  61. package/dist/cjs/utils/fromFieldValidations.js +2 -1
  62. package/dist/cjs/utils/useSortIDs.js +6 -4
  63. package/dist/esm/__fixtures__/FakeSdk.js +3 -3
  64. package/dist/esm/assets/MultipleMediaEditor.js +3 -3
  65. package/dist/esm/assets/SingleMediaEditor.js +2 -2
  66. package/dist/esm/assets/WrappedAssetCard/AssetCardActions.js +12 -12
  67. package/dist/esm/assets/WrappedAssetCard/FetchingWrappedAssetCard.js +14 -9
  68. package/dist/esm/assets/WrappedAssetCard/WrappedAssetCard.js +15 -7
  69. package/dist/esm/assets/WrappedAssetCard/WrappedAssetLink.js +7 -6
  70. package/dist/esm/common/EntityStore.js +40 -42
  71. package/dist/esm/common/MultipleReferenceEditor.js +16 -9
  72. package/dist/esm/common/ReferenceEditor.js +2 -2
  73. package/dist/esm/common/SingleReferenceEditor.js +7 -5
  74. package/dist/esm/common/SortableLinkList.js +12 -12
  75. package/dist/esm/common/queryClient.js +44 -0
  76. package/dist/esm/common/useContentTypePermissions.js +3 -1
  77. package/dist/esm/common/useEditorPermissions.js +15 -3
  78. package/dist/esm/common/useEditorPermissions.spec.js +13 -12
  79. package/dist/esm/components/AssetThumbnail/AssetThumbnail.js +1 -1
  80. package/dist/esm/components/CreateEntryLinkButton/CreateEntryLinkButton.js +7 -5
  81. package/dist/esm/components/CreateEntryLinkButton/CreateEntryLinkButton.spec.js +12 -12
  82. package/dist/esm/components/CreateEntryLinkButton/CreateEntryMenuTrigger.js +23 -15
  83. package/dist/esm/components/CreateEntryLinkButton/CreateEntryMenuTrigger.spec.js +9 -8
  84. package/dist/esm/components/LinkActions/CombinedLinkActions.js +30 -19
  85. package/dist/esm/components/LinkActions/LinkActions.js +9 -9
  86. package/dist/esm/components/LinkActions/LinkEntityActions.js +18 -11
  87. package/dist/esm/components/LinkActions/NoLinkPermissionsInfo.js +1 -1
  88. package/dist/esm/components/LinkActions/helpers.js +7 -2
  89. package/dist/esm/components/MissingEntityCard/MissingEntityCard.js +6 -6
  90. package/dist/esm/components/ResourceEntityErrorCard/ResourceEntityErrorCard.js +2 -2
  91. package/dist/esm/components/ResourceEntityErrorCard/UnsupportedEntityCard.js +2 -2
  92. package/dist/esm/components/ScheduledIconWithTooltip/ScheduleTooltip.js +3 -3
  93. package/dist/esm/components/ScheduledIconWithTooltip/ScheduledIconWithTooltip.js +5 -2
  94. package/dist/esm/components/ScheduledIconWithTooltip/formatDateAndTime.js +11 -2
  95. package/dist/esm/components/SpaceName/SpaceName.js +4 -4
  96. package/dist/esm/entries/MultipleEntryReferenceEditor.js +5 -5
  97. package/dist/esm/entries/SingleEntryReferenceEditor.js +3 -3
  98. package/dist/esm/entries/WrappedEntryCard/FetchingWrappedEntryCard.js +15 -8
  99. package/dist/esm/entries/WrappedEntryCard/WrappedEntryCard.js +18 -14
  100. package/dist/esm/index.js +1 -0
  101. package/dist/esm/resources/Cards/ContentfulEntryCard.js +9 -2
  102. package/dist/esm/resources/Cards/ResourceCard.js +12 -10
  103. package/dist/esm/resources/Cards/ResourceCard.spec.js +12 -11
  104. package/dist/esm/resources/MultipleResourceReferenceEditor.js +14 -13
  105. package/dist/esm/resources/MultipleResourceReferenceEditor.spec.js +30 -11
  106. package/dist/esm/resources/SingleResourceReferenceEditor.js +6 -6
  107. package/dist/esm/resources/SingleResourceReferenceEditor.spec.js +9 -4
  108. package/dist/esm/resources/testHelpers/resourceEditorHelpers.js +9 -2
  109. package/dist/esm/resources/useResourceLinkActions.js +11 -2
  110. package/dist/esm/utils/fromFieldValidations.js +1 -0
  111. package/dist/esm/utils/useSortIDs.js +2 -2
  112. package/dist/types/common/EntityStore.d.ts +1 -1
  113. package/dist/types/common/queryClient.d.ts +9 -0
  114. package/dist/types/index.d.ts +1 -0
  115. package/package.json +2 -2
@@ -19,15 +19,17 @@ const redesignStyles = {
19
19
  maxWidth: '300px'
20
20
  })
21
21
  };
22
- export const CreateEntryLinkButton = ({ contentTypes , onSelect , customDropdownItems , text , testId , hasPlusIcon =false , useExperimentalStyles , suggestedContentTypeId , dropdownSettings , disabled =false })=>{
22
+ export const CreateEntryLinkButton = ({ contentTypes, onSelect, customDropdownItems, text, testId, hasPlusIcon = false, useExperimentalStyles, suggestedContentTypeId, dropdownSettings, disabled = false })=>{
23
23
  contentTypes = contentTypes.sort((a, b)=>a.name.localeCompare(b.name));
24
24
  const suggestedContentType = contentTypes.find((ct)=>ct.sys.id === suggestedContentTypeId);
25
25
  const buttonText = text || `Add ${get(suggestedContentType || (contentTypes.length === 1 ? contentTypes[0] : {}), 'name', 'entry')}`;
26
26
  const hasDropdown = contentTypes.length > 1 || customDropdownItems;
27
- const plusIcon = hasPlusIcon ? React.createElement(PlusIcon, null) : undefined;
27
+ // TODO: Introduce `icon: string` and remove `hasPlusIcon` or remove "Plus" if we keep new layout.
28
+ const plusIcon = hasPlusIcon ? /*#__PURE__*/ React.createElement(PlusIcon, null) : undefined;
29
+ // TODO: Always use "New content" here if we fully switch to new layout.
28
30
  const contentTypesLabel = useExperimentalStyles ? 'New content' : undefined;
29
31
  const styles = useExperimentalStyles ? redesignStyles : standardStyles;
30
- return React.createElement(CreateEntryMenuTrigger, {
32
+ return /*#__PURE__*/ React.createElement(CreateEntryMenuTrigger, {
31
33
  contentTypes: contentTypes,
32
34
  suggestedContentTypeId: suggestedContentTypeId,
33
35
  contentTypesLabel: contentTypesLabel,
@@ -35,8 +37,8 @@ export const CreateEntryLinkButton = ({ contentTypes , onSelect , customDropdown
35
37
  testId: testId,
36
38
  dropdownSettings: dropdownSettings,
37
39
  customDropdownItems: customDropdownItems
38
- }, ({ isSelecting })=>React.createElement(Button, {
39
- endIcon: hasDropdown ? React.createElement(ChevronDownIcon, null) : undefined,
40
+ }, ({ isSelecting })=>/*#__PURE__*/ React.createElement(Button, {
41
+ endIcon: hasDropdown ? /*#__PURE__*/ React.createElement(ChevronDownIcon, null) : undefined,
40
42
  variant: "secondary",
41
43
  className: styles.action,
42
44
  isDisabled: disabled || isSelecting,
@@ -37,14 +37,14 @@ describe('CreateEntryLinkButton general', ()=>{
37
37
  }
38
38
  };
39
39
  it('renders with multiple content types as list', ()=>{
40
- const { getByTestId } = render(React.createElement(CreateEntryLinkButton, props));
40
+ const { getByTestId } = render(/*#__PURE__*/ React.createElement(CreateEntryLinkButton, props));
41
41
  expect(getByTestId('create-entry-button-menu-trigger')).toBeDefined();
42
42
  const link = findButton(getByTestId);
43
43
  expect(link).toBeDefined();
44
44
  expect(link.textContent).toBe('Add entry');
45
45
  });
46
46
  it('renders dropdown menu on click when with multiple content types', ()=>{
47
- const { getByTestId } = render(React.createElement(CreateEntryLinkButton, props));
47
+ const { getByTestId } = render(/*#__PURE__*/ React.createElement(CreateEntryLinkButton, props));
48
48
  fireEvent.click(findButton(getByTestId));
49
49
  const menu = getByTestId('add-entry-menu');
50
50
  expect(menu).toBeDefined();
@@ -54,7 +54,7 @@ describe('CreateEntryLinkButton general', ()=>{
54
54
  });
55
55
  it('renders suggestedContentType as text when given', ()=>{
56
56
  const suggestedContentTypeId = 'ID_2';
57
- const { getByTestId } = render(React.createElement(CreateEntryLinkButton, {
57
+ const { getByTestId } = render(/*#__PURE__*/ React.createElement(CreateEntryLinkButton, {
58
58
  ...props,
59
59
  suggestedContentTypeId: suggestedContentTypeId
60
60
  }));
@@ -64,7 +64,7 @@ describe('CreateEntryLinkButton general', ()=>{
64
64
  expect(button.textContent).toBe(`Add ${CONTENT_TYPE_2.name}`);
65
65
  });
66
66
  it('renders the name of the content type as part of the text if only 1 content type is given', ()=>{
67
- const { getByTestId } = render(React.createElement(CreateEntryLinkButton, {
67
+ const { getByTestId } = render(/*#__PURE__*/ React.createElement(CreateEntryLinkButton, {
68
68
  onSelect: props.onSelect,
69
69
  contentTypes: [
70
70
  CONTENT_TYPE_1
@@ -80,7 +80,7 @@ describe('CreateEntryLinkButton general', ()=>{
80
80
  text: 'CUSTOM_TEXT',
81
81
  hasPlusIcon: true
82
82
  };
83
- const { getByTestId } = render(React.createElement(CreateEntryLinkButton, {
83
+ const { getByTestId } = render(/*#__PURE__*/ React.createElement(CreateEntryLinkButton, {
84
84
  ...props,
85
85
  ...propsOverrides
86
86
  }));
@@ -101,13 +101,13 @@ describe('CreateEntryLinkButton with multiple entries', ()=>{
101
101
  }
102
102
  };
103
103
  it('should render dropdown items for each content type', ()=>{
104
- const { getByTestId , getAllByTestId } = render(React.createElement(CreateEntryLinkButton, props));
104
+ const { getByTestId, getAllByTestId } = render(/*#__PURE__*/ React.createElement(CreateEntryLinkButton, props));
105
105
  fireEvent.click(findButton(getByTestId));
106
106
  expect(getAllByTestId('contentType')).toHaveLength(props.contentTypes.length);
107
107
  });
108
108
  it('calls onSelect after click on menu item', ()=>{
109
109
  const selectSpy = jest.fn();
110
- const { getByTestId , getAllByTestId } = render(React.createElement(CreateEntryLinkButton, {
110
+ const { getByTestId, getAllByTestId } = render(/*#__PURE__*/ React.createElement(CreateEntryLinkButton, {
111
111
  ...props,
112
112
  onSelect: selectSpy
113
113
  }));
@@ -127,7 +127,7 @@ describe('CreateEntryLinkButton with a single entry', ()=>{
127
127
  };
128
128
  it('should fire the onSelect function when clicked', ()=>{
129
129
  const onSelectStub = jest.fn();
130
- const { getByTestId } = render(React.createElement(CreateEntryLinkButton, {
130
+ const { getByTestId } = render(/*#__PURE__*/ React.createElement(CreateEntryLinkButton, {
131
131
  ...props,
132
132
  onSelect: onSelectStub
133
133
  }));
@@ -139,7 +139,7 @@ describe('CreateEntryLinkButton with a single entry', ()=>{
139
139
  describe('CreateEntryLinkButton common', ()=>{
140
140
  it('should render a spinner if onSelect returns a promise', async ()=>{
141
141
  const onSelect = jest.fn(()=>new Promise((resolve)=>setTimeout(resolve, 1000)));
142
- const { getByTestId , container } = render(React.createElement(CreateEntryLinkButton, {
142
+ const { getByTestId, container } = render(/*#__PURE__*/ React.createElement(CreateEntryLinkButton, {
143
143
  contentTypes: [
144
144
  CONTENT_TYPE_1
145
145
  ],
@@ -155,7 +155,7 @@ describe('CreateEntryLinkButton common', ()=>{
155
155
  });
156
156
  it('should hide a spinner after the promise from onSelect resolves', async ()=>{
157
157
  const onSelect = jest.fn(()=>new Promise((resolve)=>setTimeout(resolve, 500)));
158
- const { getByTestId , container } = render(React.createElement(CreateEntryLinkButton, {
158
+ const { getByTestId, container } = render(/*#__PURE__*/ React.createElement(CreateEntryLinkButton, {
159
159
  contentTypes: [
160
160
  CONTENT_TYPE_1
161
161
  ],
@@ -172,7 +172,7 @@ describe('CreateEntryLinkButton common', ()=>{
172
172
  });
173
173
  it('does not emit onSelect on subsequent click before the promise from onSelect resolves', async ()=>{
174
174
  const onSelect = jest.fn(()=>new Promise((resolve)=>setTimeout(()=>resolve(undefined), 200)));
175
- const { getByTestId } = render(React.createElement(CreateEntryLinkButton, {
175
+ const { getByTestId } = render(/*#__PURE__*/ React.createElement(CreateEntryLinkButton, {
176
176
  contentTypes: [
177
177
  CONTENT_TYPE_1
178
178
  ],
@@ -188,7 +188,7 @@ describe('CreateEntryLinkButton common', ()=>{
188
188
  });
189
189
  it('emits onSelect on subsequent click after the promise from onSelect resolves', async ()=>{
190
190
  const onSelect = jest.fn(()=>Promise.resolve());
191
- const { getByTestId } = render(React.createElement(CreateEntryLinkButton, {
191
+ const { getByTestId } = render(/*#__PURE__*/ React.createElement(CreateEntryLinkButton, {
192
192
  contentTypes: [
193
193
  CONTENT_TYPE_1
194
194
  ],
@@ -1,4 +1,4 @@
1
- import React, { useState, useRef, useEffect } from 'react';
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */ import React, { useState, useRef, useEffect } from 'react';
2
2
  import { TextInput, Menu } from '@contentful/f36-components';
3
3
  import { SearchIcon } from '@contentful/f36-icons';
4
4
  import tokens from '@contentful/f36-tokens';
@@ -36,16 +36,23 @@ const styles = {
36
36
  borderColor: tokens.gray200
37
37
  })
38
38
  };
39
- export const CreateEntryMenuTrigger = ({ contentTypes , suggestedContentTypeId , contentTypesLabel , onSelect , testId , dropdownSettings ={
39
+ export const CreateEntryMenuTrigger = ({ contentTypes, suggestedContentTypeId, contentTypesLabel, onSelect, testId, dropdownSettings = {
40
40
  position: 'bottom-left'
41
- } , customDropdownItems , children , menuProps })=>{
41
+ }, customDropdownItems, children, menuProps })=>{
42
42
  const [isOpen, setOpen] = useState(false);
43
43
  const [isSelecting, setSelecting] = useState(false);
44
44
  const [searchInput, setSearchInput] = useState('');
45
45
  const wrapper = useRef(null);
46
46
  const textField = useRef(null);
47
47
  const menuListRef = useRef(null);
48
- const [dropdownWidth, setDropdownWidth] = useState();
48
+ /*
49
+ By default, dropdown wraps it's content, so it's width = the width of the widest item
50
+ During search, menu items change, and so the widest menu item can change
51
+ This leads to menu always changing it's width
52
+ To prevent this, we get the width of the menu item after the first mount of a dropdown (when all the content is displayed)
53
+ And hardcode it through the class name. This way we ensure that even during search the menu will keep that max width
54
+ That it had on initial mount and that fits any menu item in has
55
+ */ const [dropdownWidth, setDropdownWidth] = useState();
49
56
  const hasDropdown = contentTypes.length > 1 || !!customDropdownItems;
50
57
  const closeMenu = ()=>setOpen(false);
51
58
  useEffect(()=>{
@@ -70,6 +77,7 @@ export const CreateEntryMenuTrigger = ({ contentTypes , suggestedContentTypeId ,
70
77
  const handleSelect = (item)=>{
71
78
  closeMenu();
72
79
  const res = onSelect(item.sys.id);
80
+ // TODO: Convert to controllable component.
73
81
  if (res && typeof res.then === 'function') {
74
82
  setSelecting(true);
75
83
  res.then(()=>setSelecting(false), ()=>setSelecting(false));
@@ -89,28 +97,28 @@ export const CreateEntryMenuTrigger = ({ contentTypes , suggestedContentTypeId ,
89
97
  }, [
90
98
  isOpen
91
99
  ]);
92
- const renderSearchResultsCount = (resultsLength)=>resultsLength ? React.createElement(Menu.SectionTitle, {
100
+ const renderSearchResultsCount = (resultsLength)=>resultsLength ? /*#__PURE__*/ React.createElement(Menu.SectionTitle, {
93
101
  testId: "add-entru-menu-search-results"
94
102
  }, resultsLength, " result", resultsLength > 1 ? 's' : '') : null;
95
103
  const isSearchable = contentTypes.length > MAX_ITEMS_WITHOUT_SEARCH;
96
104
  const maxDropdownHeight = suggestedContentTypeId ? 300 : 250;
97
105
  const suggestedContentType = contentTypes.find((ct)=>ct.sys.id === suggestedContentTypeId);
98
106
  const filteredContentTypes = contentTypes.filter((ct)=>!searchInput || get(ct, 'name', 'Untitled').toLowerCase().includes(searchInput.toLowerCase()));
99
- return React.createElement("span", {
107
+ return /*#__PURE__*/ React.createElement("span", {
100
108
  className: styles.wrapper,
101
109
  ref: wrapper,
102
110
  "data-test-id": testId
103
- }, React.createElement(Menu, {
111
+ }, /*#__PURE__*/ React.createElement(Menu, {
104
112
  placement: menuPlacementMap[dropdownSettings.position],
105
113
  isAutoalignmentEnabled: dropdownSettings.isAutoalignmentEnabled,
106
114
  isOpen: isOpen,
107
115
  onClose: closeMenu,
108
116
  onOpen: handleMenuOpen,
109
117
  ...menuProps
110
- }, React.createElement(Menu.Trigger, null, children({
118
+ }, /*#__PURE__*/ React.createElement(Menu.Trigger, null, children({
111
119
  isOpen,
112
120
  isSelecting
113
- })), isOpen && React.createElement(Menu.List, {
121
+ })), isOpen && /*#__PURE__*/ React.createElement(Menu.List, {
114
122
  className: styles.dropdownList,
115
123
  style: {
116
124
  width: dropdownWidth != undefined ? `${dropdownWidth}px` : undefined,
@@ -118,25 +126,25 @@ export const CreateEntryMenuTrigger = ({ contentTypes , suggestedContentTypeId ,
118
126
  },
119
127
  ref: menuListRef,
120
128
  testId: "add-entry-menu"
121
- }, Boolean(customDropdownItems) && React.createElement(React.Fragment, null, customDropdownItems, React.createElement(Menu.Divider, null)), isSearchable && React.createElement(React.Fragment, null, React.createElement("div", {
129
+ }, Boolean(customDropdownItems) && /*#__PURE__*/ React.createElement(React.Fragment, null, customDropdownItems, /*#__PURE__*/ React.createElement(Menu.Divider, null)), isSearchable && /*#__PURE__*/ React.createElement(React.Fragment, null, /*#__PURE__*/ React.createElement("div", {
122
130
  ref: textField,
123
131
  className: styles.inputWrapper
124
- }, React.createElement(TextInput, {
132
+ }, /*#__PURE__*/ React.createElement(TextInput, {
125
133
  className: styles.searchInput,
126
134
  placeholder: "Search all content types",
127
135
  testId: "add-entry-menu-search",
128
136
  value: searchInput,
129
137
  onChange: (e)=>setSearchInput(e.target.value)
130
- }), React.createElement(SearchIcon, {
138
+ }), /*#__PURE__*/ React.createElement(SearchIcon, {
131
139
  className: styles.searchIcon
132
- })), React.createElement(Menu.Divider, null)), searchInput && renderSearchResultsCount(filteredContentTypes.length), suggestedContentType && !searchInput && React.createElement(React.Fragment, null, React.createElement(Menu.SectionTitle, null, "Suggested Content Type"), React.createElement(Menu.Item, {
140
+ })), /*#__PURE__*/ React.createElement(Menu.Divider, null)), searchInput && renderSearchResultsCount(filteredContentTypes.length), suggestedContentType && !searchInput && /*#__PURE__*/ React.createElement(React.Fragment, null, /*#__PURE__*/ React.createElement(Menu.SectionTitle, null, "Suggested Content Type"), /*#__PURE__*/ React.createElement(Menu.Item, {
133
141
  testId: "suggested",
134
142
  onClick: ()=>handleSelect(suggestedContentType)
135
- }, get(suggestedContentType, 'name')), React.createElement(Menu.Divider, null)), !searchInput && React.createElement(Menu.SectionTitle, null, contentTypesLabel), filteredContentTypes.length ? filteredContentTypes.map((contentType, i)=>React.createElement(Menu.Item, {
143
+ }, get(suggestedContentType, 'name')), /*#__PURE__*/ React.createElement(Menu.Divider, null)), !searchInput && /*#__PURE__*/ React.createElement(Menu.SectionTitle, null, contentTypesLabel), filteredContentTypes.length ? filteredContentTypes.map((contentType, i)=>/*#__PURE__*/ React.createElement(Menu.Item, {
136
144
  testId: "contentType",
137
145
  key: `${get(contentType, 'name')}-${i}`,
138
146
  onClick: ()=>handleSelect(contentType)
139
- }, get(contentType, 'name', 'Untitled'))) : React.createElement(Menu.Item, {
147
+ }, get(contentType, 'name', 'Untitled'))) : /*#__PURE__*/ React.createElement(Menu.Item, {
140
148
  testId: "add-entru-menu-search-results"
141
149
  }, "No results found"))));
142
150
  };
@@ -3,6 +3,7 @@ import { Button } from '@contentful/f36-components';
3
3
  import '@testing-library/jest-dom/extend-expect';
4
4
  import { act, configure, fireEvent, render } from '@testing-library/react';
5
5
  import noop from 'lodash/noop';
6
+ // eslint-disable-next-line -- TODO: describe this disable you-dont-need-lodash-underscore/fill
6
7
  import fill from 'lodash/fill';
7
8
  import { CreateEntryMenuTrigger } from './CreateEntryMenuTrigger';
8
9
  configure({
@@ -39,7 +40,7 @@ describe('CreateEntryMenuTrigger general', ()=>{
39
40
  };
40
41
  let stub = jest.fn();
41
42
  beforeEach(()=>{
42
- stub = jest.fn().mockImplementation(()=>React.createElement(Button, {
43
+ stub = jest.fn().mockImplementation(()=>/*#__PURE__*/ React.createElement(Button, {
43
44
  testId: "menu-trigger"
44
45
  }));
45
46
  });
@@ -47,13 +48,13 @@ describe('CreateEntryMenuTrigger general', ()=>{
47
48
  const stub = (api)=>{
48
49
  expect(api.isOpen).toBe(false);
49
50
  expect(api.isSelecting).toBe(false);
50
- return React.createElement("span", null);
51
+ return /*#__PURE__*/ React.createElement("span", null);
51
52
  };
52
- render(React.createElement(CreateEntryMenuTrigger, props, stub));
53
+ render(/*#__PURE__*/ React.createElement(CreateEntryMenuTrigger, props, stub));
53
54
  });
54
55
  it('should set isSelecting to true in case onSelect returns a promise', async ()=>{
55
56
  const selectStub = jest.fn(()=>new Promise((resolve)=>setTimeout(resolve, 1000)));
56
- const { getAllByTestId , getByTestId } = render(React.createElement(CreateEntryMenuTrigger, {
57
+ const { getAllByTestId, getByTestId } = render(/*#__PURE__*/ React.createElement(CreateEntryMenuTrigger, {
57
58
  ...props,
58
59
  onSelect: selectStub
59
60
  }, stub));
@@ -67,7 +68,7 @@ describe('CreateEntryMenuTrigger general', ()=>{
67
68
  });
68
69
  it('should not set isSelecting to true in case onSelect is sync', async ()=>{
69
70
  const selectStub = jest.fn();
70
- const { getAllByTestId , getByTestId } = render(React.createElement(CreateEntryMenuTrigger, {
71
+ const { getAllByTestId, getByTestId } = render(/*#__PURE__*/ React.createElement(CreateEntryMenuTrigger, {
71
72
  ...props,
72
73
  onSelect: selectStub
73
74
  }, stub));
@@ -84,7 +85,7 @@ describe('CreateEntryMenuTrigger general', ()=>{
84
85
  expect(selectStub).toHaveBeenCalled();
85
86
  });
86
87
  it('renders text input if contentTypes.length > 20', ()=>{
87
- const { getByTestId } = render(React.createElement(CreateEntryMenuTrigger, {
88
+ const { getByTestId } = render(/*#__PURE__*/ React.createElement(CreateEntryMenuTrigger, {
88
89
  ...props,
89
90
  contentTypes: fill(Array(21), CONTENT_TYPE_3)
90
91
  }, stub));
@@ -95,7 +96,7 @@ describe('CreateEntryMenuTrigger general', ()=>{
95
96
  });
96
97
  it('shows the search results if typed in input', ()=>{
97
98
  const contentTypes = fill(fill(fill(Array(21), CONTENT_TYPE_1, 0, 10), CONTENT_TYPE_2, 10, 20), CONTENT_TYPE_3, 20);
98
- const { getByTestId , getAllByTestId } = render(React.createElement(CreateEntryMenuTrigger, {
99
+ const { getByTestId, getAllByTestId } = render(/*#__PURE__*/ React.createElement(CreateEntryMenuTrigger, {
99
100
  ...props,
100
101
  contentTypes: contentTypes
101
102
  }, stub));
@@ -128,7 +129,7 @@ describe('CreateEntryMenuTrigger general', ()=>{
128
129
  expect(getByTestId('add-entru-menu-search-results').textContent).toBe('No results found');
129
130
  });
130
131
  it('shows suggestedContentType in the list', ()=>{
131
- const { getByTestId } = render(React.createElement(CreateEntryMenuTrigger, {
132
+ const { getByTestId } = render(/*#__PURE__*/ React.createElement(CreateEntryMenuTrigger, {
132
133
  ...props,
133
134
  suggestedContentTypeId: props.contentTypes[0].sys.id
134
135
  }, stub));
@@ -9,18 +9,27 @@ const testIds = {
9
9
  ...sharedTextIds,
10
10
  actionsWrapper: 'link-actions-menu-trigger'
11
11
  };
12
- export function CombinedLinkActions(props) {
12
+ /**
13
+ * Alternative, experimental alternative to <LinkActions /> that is planned to
14
+ * replace the current default LinkActions in reference and media editors.
15
+ *
16
+ * Places both actions to create and link new, as well as link existing, behind
17
+ * one action dropdown and introduces new copy for action labels.
18
+ */ export function CombinedLinkActions(props) {
13
19
  if (props.isFull) {
14
- return null;
20
+ return null; // Don't render link actions if we reached max allowed links.
15
21
  }
22
+ // We don't want to render a spacious container in case there are are already
23
+ // assets linked (in case of entries, always show it) as the border wouldn't be
24
+ // nicely aligned with asset cards.
16
25
  const hideEmptyCard = props.entityType === 'Asset' && !props.isEmpty;
17
- return React.createElement("div", {
26
+ return /*#__PURE__*/ React.createElement("div", {
18
27
  className: hideEmptyCard ? '' : styles.container
19
- }, !props.canCreateEntity && !props.canLinkEntity && React.createElement(NoLinkPermissionsInfo, null), props.entityType === 'Entry' && React.createElement(CombinedEntryLinkActions, props), props.entityType === 'Asset' && React.createElement(CombinedAssetLinkActions, props));
28
+ }, !props.canCreateEntity && !props.canLinkEntity && /*#__PURE__*/ React.createElement(NoLinkPermissionsInfo, null), props.entityType === 'Entry' && /*#__PURE__*/ React.createElement(CombinedEntryLinkActions, props), props.entityType === 'Asset' && /*#__PURE__*/ React.createElement(CombinedAssetLinkActions, props));
20
29
  }
21
30
  function CombinedEntryLinkActions(props) {
22
31
  if (props.canCreateEntity) {
23
- return React.createElement(CreateEntryLinkButton, {
32
+ return /*#__PURE__*/ React.createElement(CreateEntryLinkButton, {
24
33
  testId: testIds.actionsWrapper,
25
34
  disabled: props.isDisabled,
26
35
  text: props.combinedActionsLabel || 'Add content',
@@ -33,7 +42,7 @@ function CombinedEntryLinkActions(props) {
33
42
  onSelect: (contentTypeId)=>{
34
43
  return contentTypeId ? props.onCreate(contentTypeId) : Promise.resolve();
35
44
  },
36
- customDropdownItems: props.canLinkEntity ? React.createElement(Menu.Item, {
45
+ customDropdownItems: props.canLinkEntity ? /*#__PURE__*/ React.createElement(Menu.Item, {
37
46
  testId: testIds.linkExisting,
38
47
  onClick: ()=>{
39
48
  props.onLinkExisting();
@@ -41,7 +50,7 @@ function CombinedEntryLinkActions(props) {
41
50
  }, "Add existing content") : undefined
42
51
  });
43
52
  } else if (props.canLinkEntity) {
44
- return React.createElement(Button, {
53
+ return /*#__PURE__*/ React.createElement(Button, {
45
54
  isDisabled: props.isDisabled,
46
55
  testId: testIds.linkExisting,
47
56
  className: styles.action,
@@ -49,7 +58,7 @@ function CombinedEntryLinkActions(props) {
49
58
  props.onLinkExisting();
50
59
  },
51
60
  variant: "secondary",
52
- startIcon: React.createElement(LinkIcon, null),
61
+ startIcon: /*#__PURE__*/ React.createElement(LinkIcon, null),
53
62
  size: "small"
54
63
  }, "Add existing content");
55
64
  }
@@ -59,7 +68,7 @@ function CombinedAssetLinkActions(props) {
59
68
  const [isOpen, setOpen] = React.useState(false);
60
69
  if (!props.canLinkEntity || !props.canCreateEntity) {
61
70
  if (props.canLinkEntity) {
62
- return React.createElement(Button, {
71
+ return /*#__PURE__*/ React.createElement(Button, {
63
72
  isDisabled: props.isDisabled,
64
73
  testId: testIds.linkExisting,
65
74
  className: styles.action,
@@ -67,12 +76,12 @@ function CombinedAssetLinkActions(props) {
67
76
  props.onLinkExisting();
68
77
  },
69
78
  variant: "secondary",
70
- startIcon: React.createElement(PlusIcon, null),
79
+ startIcon: /*#__PURE__*/ React.createElement(PlusIcon, null),
71
80
  size: "small"
72
81
  }, "Add existing media");
73
82
  }
74
83
  if (props.canCreateEntity) {
75
- return React.createElement(Button, {
84
+ return /*#__PURE__*/ React.createElement(Button, {
76
85
  isDisabled: props.isDisabled,
77
86
  testId: testIds.createAndLink,
78
87
  className: styles.action,
@@ -80,13 +89,15 @@ function CombinedAssetLinkActions(props) {
80
89
  props.onCreate();
81
90
  },
82
91
  variant: "secondary",
83
- startIcon: React.createElement(PlusIcon, null),
92
+ startIcon: /*#__PURE__*/ React.createElement(PlusIcon, null),
84
93
  size: "small"
85
94
  }, "Add media");
86
95
  }
87
96
  return null;
88
97
  }
89
- return React.createElement(Menu, {
98
+ // TODO: If we fully switch to this new layout, make a more generic `CreateEntityLinkButton`
99
+ // that works without content types to cover asset use-case.
100
+ return /*#__PURE__*/ React.createElement(Menu, {
90
101
  isOpen: isOpen,
91
102
  onClose: ()=>{
92
103
  setOpen(false);
@@ -94,22 +105,22 @@ function CombinedAssetLinkActions(props) {
94
105
  onOpen: ()=>{
95
106
  setOpen(true);
96
107
  }
97
- }, React.createElement(Menu.Trigger, null, React.createElement(Button, {
98
- endIcon: React.createElement(ChevronDownIcon, null),
108
+ }, /*#__PURE__*/ React.createElement(Menu.Trigger, null, /*#__PURE__*/ React.createElement(Button, {
109
+ endIcon: /*#__PURE__*/ React.createElement(ChevronDownIcon, null),
99
110
  isDisabled: props.isDisabled,
100
111
  testId: testIds.actionsWrapper,
101
112
  className: styles.action,
102
113
  variant: "secondary",
103
- startIcon: React.createElement(PlusIcon, null),
114
+ startIcon: /*#__PURE__*/ React.createElement(PlusIcon, null),
104
115
  size: "small"
105
- }, "Add media")), isOpen && React.createElement(Menu.List, {
116
+ }, "Add media")), isOpen && /*#__PURE__*/ React.createElement(Menu.List, {
106
117
  testId: testIds.dropdown
107
- }, React.createElement(Menu.Item, {
118
+ }, /*#__PURE__*/ React.createElement(Menu.Item, {
108
119
  testId: testIds.linkExisting,
109
120
  onClick: ()=>{
110
121
  props.onLinkExisting();
111
122
  }
112
- }, "Add existing media"), React.createElement(Menu.Item, {
123
+ }, "Add existing media"), /*#__PURE__*/ React.createElement(Menu.Item, {
113
124
  testId: testIds.createAndLink,
114
125
  onClick: ()=>{
115
126
  props.onCreate();
@@ -20,16 +20,16 @@ export const testIds = {
20
20
  };
21
21
  export function LinkActions(props) {
22
22
  if (props.isFull) {
23
- return null;
23
+ return null; // Don't render link actions if we reached max allowed links.
24
24
  }
25
25
  const defaultLabels = props.entityType === 'Entry' ? defaultEntryLabels : defaultAssetLabels;
26
26
  const labels = {
27
27
  ...defaultLabels,
28
28
  ...props.actionLabels
29
29
  };
30
- return React.createElement("div", {
30
+ return /*#__PURE__*/ React.createElement("div", {
31
31
  className: styles.container
32
- }, props.canCreateEntity && React.createElement(React.Fragment, null, props.entityType === 'Entry' && React.createElement(CreateEntryLinkButton, {
32
+ }, props.canCreateEntity && /*#__PURE__*/ React.createElement(React.Fragment, null, props.entityType === 'Entry' && /*#__PURE__*/ React.createElement(CreateEntryLinkButton, {
33
33
  testId: testIds.createAndLink,
34
34
  disabled: props.isDisabled,
35
35
  text: labels.createNew({
@@ -40,27 +40,27 @@ export function LinkActions(props) {
40
40
  onSelect: (contentTypeId)=>{
41
41
  return contentTypeId ? props.onCreate(contentTypeId, props.itemsLength) : Promise.resolve();
42
42
  }
43
- }), props.entityType === 'Asset' && React.createElement(Button, {
43
+ }), props.entityType === 'Asset' && /*#__PURE__*/ React.createElement(Button, {
44
44
  isDisabled: props.isDisabled,
45
45
  testId: testIds.createAndLink,
46
46
  onClick: ()=>{
47
47
  props.onCreate(undefined, props.itemsLength);
48
48
  },
49
49
  variant: "secondary",
50
- startIcon: React.createElement(PlusIcon, null),
50
+ startIcon: /*#__PURE__*/ React.createElement(PlusIcon, null),
51
51
  size: "small"
52
- }, labels.createNew()), React.createElement("span", {
52
+ }, labels.createNew()), /*#__PURE__*/ React.createElement("span", {
53
53
  className: styles.separator
54
- })), props.canLinkEntity && React.createElement(Button, {
54
+ })), props.canLinkEntity && /*#__PURE__*/ React.createElement(Button, {
55
55
  isDisabled: props.isDisabled,
56
56
  testId: testIds.linkExisting,
57
57
  onClick: ()=>{
58
58
  props.onLinkExisting();
59
59
  },
60
60
  variant: "secondary",
61
- startIcon: React.createElement(LinkIcon, null),
61
+ startIcon: /*#__PURE__*/ React.createElement(LinkIcon, null),
62
62
  size: "small"
63
63
  }, labels.linkExisting({
64
64
  canLinkMultiple: props.canLinkMultiple
65
- })), !props.canCreateEntity && !props.canLinkEntity && React.createElement(NoLinkPermissionsInfo, null));
65
+ })), !props.canCreateEntity && !props.canLinkEntity && /*#__PURE__*/ React.createElement(NoLinkPermissionsInfo, null));
66
66
  }
@@ -4,7 +4,7 @@ import { CombinedLinkActions } from './CombinedLinkActions';
4
4
  import { createEntity, selectMultipleEntities, selectSingleEntity } from './helpers';
5
5
  import { LinkActions } from './LinkActions';
6
6
  export function useLinkActionsProps(props) {
7
- const { sdk , editorPermissions , entityType , canLinkMultiple , isDisabled , actionLabels , itemsLength } = props;
7
+ const { sdk, editorPermissions, entityType, canLinkMultiple, isDisabled, actionLabels, itemsLength } = props;
8
8
  const maxLinksCount = editorPermissions.validations.numberOfLinks?.max;
9
9
  const value = sdk.field.getValue();
10
10
  const linkCount = Array.isArray(value) ? value.length : value ? 1 : 0;
@@ -19,7 +19,8 @@ export function useLinkActionsProps(props) {
19
19
  slide,
20
20
  index
21
21
  });
22
- }, [
22
+ }, // eslint-disable-next-line react-hooks/exhaustive-deps -- TODO: Evaluate the dependencies
23
+ [
23
24
  entityType,
24
25
  props.onCreate,
25
26
  props.onAction
@@ -34,13 +35,14 @@ export function useLinkActionsProps(props) {
34
35
  index: index === undefined ? undefined : index + i
35
36
  });
36
37
  });
37
- }, [
38
+ }, // eslint-disable-next-line react-hooks/exhaustive-deps -- TODO: Evaluate the dependencies
39
+ [
38
40
  entityType,
39
41
  props.onLink,
40
42
  props.onAction
41
43
  ]);
42
44
  const onCreate = React.useCallback(async (contentTypeId, index)=>{
43
- const { entity , slide } = await createEntity({
45
+ const { entity, slide } = await createEntity({
44
46
  sdk,
45
47
  entityType,
46
48
  contentTypeId
@@ -66,7 +68,8 @@ export function useLinkActionsProps(props) {
66
68
  onLinkedExisting([
67
69
  entity
68
70
  ], index);
69
- }, [
71
+ }, // eslint-disable-next-line react-hooks/exhaustive-deps -- TODO: Evaluate the dependencies
72
+ [
70
73
  sdk,
71
74
  entityType,
72
75
  onLinkedExisting
@@ -81,11 +84,13 @@ export function useLinkActionsProps(props) {
81
84
  return;
82
85
  }
83
86
  onLinkedExisting(entities, index);
84
- }, [
87
+ }, // eslint-disable-next-line react-hooks/exhaustive-deps -- TODO: Evaluate the dependencies
88
+ [
85
89
  sdk,
86
90
  entityType,
87
91
  onLinkedExisting
88
92
  ]);
93
+ // FIXME: The memoization might rerun every time due to the always changing callback identities above
89
94
  return useMemo(()=>({
90
95
  entityType,
91
96
  canLinkMultiple,
@@ -101,7 +106,8 @@ export function useLinkActionsProps(props) {
101
106
  onCreated,
102
107
  onLinkedExisting,
103
108
  itemsLength
104
- }), [
109
+ }), // eslint-disable-next-line react-hooks/exhaustive-deps -- TODO: Evaluate the dependencies
110
+ [
105
111
  entityType,
106
112
  canLinkMultiple,
107
113
  isDisabled,
@@ -110,6 +116,7 @@ export function useLinkActionsProps(props) {
110
116
  editorPermissions.canCreateEntity,
111
117
  editorPermissions.canLinkEntity,
112
118
  actionLabels,
119
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- TODO: Evaluate the dependencies
113
120
  editorPermissions.creatableContentTypes.map((ct)=>ct.sys.id).join(':'),
114
121
  onCreate,
115
122
  onLinkExisting,
@@ -119,9 +126,9 @@ export function useLinkActionsProps(props) {
119
126
  itemsLength
120
127
  ]);
121
128
  }
122
- export function LinkEntityActions({ renderCustomActions , ...props }) {
123
- return renderCustomActions ? renderCustomActions(props) : React.createElement(LinkActions, props);
129
+ export function LinkEntityActions({ renderCustomActions, ...props }) {
130
+ return renderCustomActions ? renderCustomActions(props) : /*#__PURE__*/ React.createElement(LinkActions, props);
124
131
  }
125
- export function CombinedLinkEntityActions({ renderCustomActions , ...props }) {
126
- return renderCustomActions ? renderCustomActions(props) : React.createElement(CombinedLinkActions, props);
132
+ export function CombinedLinkEntityActions({ renderCustomActions, ...props }) {
133
+ return renderCustomActions ? renderCustomActions(props) : /*#__PURE__*/ React.createElement(CombinedLinkActions, props);
127
134
  }
@@ -1,5 +1,5 @@
1
1
  import * as React from 'react';
2
2
  import { Paragraph } from '@contentful/f36-components';
3
3
  export function NoLinkPermissionsInfo() {
4
- return React.createElement(Paragraph, null, "You don't have permission to view this content or this field is not correctly configured. Contact your administrator for help.");
4
+ return /*#__PURE__*/ React.createElement(Paragraph, null, "You don't have permission to view this content or this field is not correctly configured. Contact your administrator for help.");
5
5
  }
@@ -4,7 +4,7 @@ export async function createEntity(props) {
4
4
  if (!props.contentTypeId) {
5
5
  return {};
6
6
  }
7
- const { entity , slide } = await props.sdk.navigator.openNewEntry(props.contentTypeId, {
7
+ const { entity, slide } = await props.sdk.navigator.openNewEntry(props.contentTypeId, {
8
8
  slideIn: true
9
9
  });
10
10
  return {
@@ -12,7 +12,7 @@ export async function createEntity(props) {
12
12
  slide
13
13
  };
14
14
  } else {
15
- const { entity , slide } = await props.sdk.navigator.openNewAsset({
15
+ const { entity, slide } = await props.sdk.navigator.openNewAsset({
16
16
  slideIn: true
17
17
  });
18
18
  return {
@@ -37,7 +37,12 @@ export async function selectSingleEntity(props) {
37
37
  export async function selectMultipleEntities(props) {
38
38
  const value = props.sdk.field.getValue();
39
39
  const linkCount = Array.isArray(value) ? value.length : value ? 1 : 0;
40
+ // TODO: Why not always set `min: 1` by default? Does it make sense to enforce
41
+ // user to select as many entities as the field's "min" requires? What if e.g.
42
+ // "min" is 4 and the user wants to insert 2 entities first, then create 2 new ones?
40
43
  const min = Math.max((props.editorPermissions.validations.numberOfLinks?.min || 1) - linkCount, 1);
44
+ // TODO: Consider same for max. If e.g. "max" is 4, we disable the button if the
45
+ // user wants to select 5 but we show no information why the button is disabled.
41
46
  const max = (props.editorPermissions.validations.numberOfLinks?.max || +Infinity) - linkCount;
42
47
  if (props.entityType === 'Entry') {
43
48
  return await props.sdk.dialogs.selectMultipleEntries({