@contentful/field-editor-rich-text 3.12.7 → 3.14.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 (70) hide show
  1. package/dist/cjs/Toolbar/components/EmbedEntityWidget.js +6 -0
  2. package/dist/cjs/Toolbar/index.js +2 -1
  3. package/dist/cjs/constants/Schema.js +14 -0
  4. package/dist/cjs/helpers/{newEntitySelectorConfigFromRichTextField.js → config.js} +19 -5
  5. package/dist/cjs/helpers/editor.js +1 -0
  6. package/dist/cjs/plugins/DragAndDrop/index.js +4 -2
  7. package/dist/cjs/plugins/EmbeddedEntityInline/index.js +21 -4
  8. package/dist/cjs/plugins/EmbeddedResourceInline/FetchingWrappedResourceInlineCard.js +102 -0
  9. package/dist/cjs/plugins/EmbeddedResourceInline/LinkedResourceInline.js +51 -0
  10. package/dist/cjs/plugins/EmbeddedResourceInline/index.js +56 -0
  11. package/dist/cjs/plugins/Heading/__tests__/createHeadingPlugin.test.js +2 -0
  12. package/dist/cjs/plugins/Hyperlink/HyperlinkModal.js +63 -8
  13. package/dist/cjs/plugins/Hyperlink/__tests__/createHyperlinkPlugin.test.js +3 -1
  14. package/dist/cjs/plugins/Hyperlink/components/ResourceHyperlink.js +93 -0
  15. package/dist/cjs/plugins/Hyperlink/createHyperlinkPlugin.js +29 -1
  16. package/dist/cjs/plugins/Hyperlink/useResourceEntityInfo.js +71 -0
  17. package/dist/cjs/plugins/Hyperlink/utils.js +5 -2
  18. package/dist/cjs/plugins/Paragraph/__tests__/createParagraphPlugin.test.js +2 -0
  19. package/dist/cjs/plugins/Quote/__test__/createQuotePlugin.test.js +2 -0
  20. package/dist/cjs/plugins/index.js +2 -0
  21. package/dist/cjs/plugins/shared/EmbeddedBlockToolbarIcon.js +2 -4
  22. package/dist/cjs/plugins/shared/EmbeddedBlockUtil.js +3 -4
  23. package/dist/cjs/plugins/shared/EmbeddedInlineToolbarIcon.js +11 -6
  24. package/dist/cjs/plugins/shared/EmbeddedInlineUtil.js +66 -27
  25. package/dist/cjs/plugins/shared/ResourceNewBadge.js +57 -0
  26. package/dist/cjs/test-utils/jsx.js +11 -0
  27. package/dist/esm/Toolbar/components/EmbedEntityWidget.js +6 -0
  28. package/dist/esm/Toolbar/index.js +2 -1
  29. package/dist/esm/constants/Schema.js +14 -0
  30. package/dist/esm/helpers/{newEntitySelectorConfigFromRichTextField.js → config.js} +8 -2
  31. package/dist/esm/helpers/editor.js +1 -0
  32. package/dist/esm/plugins/DragAndDrop/index.js +4 -2
  33. package/dist/esm/plugins/EmbeddedEntityInline/index.js +22 -5
  34. package/dist/esm/plugins/EmbeddedResourceInline/FetchingWrappedResourceInlineCard.js +53 -0
  35. package/dist/esm/plugins/EmbeddedResourceInline/LinkedResourceInline.js +36 -0
  36. package/dist/esm/plugins/EmbeddedResourceInline/index.js +46 -0
  37. package/dist/esm/plugins/Heading/__tests__/createHeadingPlugin.test.js +2 -0
  38. package/dist/esm/plugins/Hyperlink/HyperlinkModal.js +63 -8
  39. package/dist/esm/plugins/Hyperlink/__tests__/createHyperlinkPlugin.test.js +3 -1
  40. package/dist/esm/plugins/Hyperlink/components/ResourceHyperlink.js +44 -0
  41. package/dist/esm/plugins/Hyperlink/createHyperlinkPlugin.js +29 -1
  42. package/dist/esm/plugins/Hyperlink/useResourceEntityInfo.js +22 -0
  43. package/dist/esm/plugins/Hyperlink/utils.js +2 -2
  44. package/dist/esm/plugins/Paragraph/__tests__/createParagraphPlugin.test.js +2 -0
  45. package/dist/esm/plugins/Quote/__test__/createQuotePlugin.test.js +2 -0
  46. package/dist/esm/plugins/index.js +2 -0
  47. package/dist/esm/plugins/shared/EmbeddedBlockToolbarIcon.js +3 -5
  48. package/dist/esm/plugins/shared/EmbeddedBlockUtil.js +1 -2
  49. package/dist/esm/plugins/shared/EmbeddedInlineToolbarIcon.js +12 -7
  50. package/dist/esm/plugins/shared/EmbeddedInlineUtil.js +64 -25
  51. package/dist/esm/plugins/shared/ResourceNewBadge.js +8 -0
  52. package/dist/esm/test-utils/jsx.js +11 -0
  53. package/dist/types/constants/Schema.d.ts +10 -0
  54. package/dist/types/helpers/config.d.ts +33 -0
  55. package/dist/types/helpers/editor.d.ts +1 -1
  56. package/dist/types/plugins/EmbeddedResourceInline/FetchingWrappedResourceInlineCard.d.ts +13 -0
  57. package/dist/types/plugins/EmbeddedResourceInline/LinkedResourceInline.d.ts +13 -0
  58. package/dist/types/plugins/EmbeddedResourceInline/index.d.ts +3 -0
  59. package/dist/types/plugins/Hyperlink/HyperlinkModal.d.ts +2 -1
  60. package/dist/types/plugins/Hyperlink/components/ResourceHyperlink.d.ts +20 -0
  61. package/dist/types/plugins/Hyperlink/useResourceEntityInfo.d.ts +7 -0
  62. package/dist/types/plugins/Hyperlink/utils.d.ts +1 -0
  63. package/dist/types/plugins/shared/EmbeddedInlineToolbarIcon.d.ts +2 -1
  64. package/dist/types/plugins/shared/EmbeddedInlineUtil.d.ts +3 -17
  65. package/dist/types/plugins/shared/ResourceNewBadge.d.ts +2 -0
  66. package/package.json +2 -2
  67. package/dist/cjs/helpers/newResourceEntitySelectorConfigFromRichTextField.js +0 -21
  68. package/dist/esm/helpers/newResourceEntitySelectorConfigFromRichTextField.js +0 -6
  69. package/dist/types/helpers/newEntitySelectorConfigFromRichTextField.d.ts +0 -14
  70. package/dist/types/helpers/newResourceEntitySelectorConfigFromRichTextField.d.ts +0 -16
@@ -63,6 +63,7 @@ const EmbedEntityWidget = ({ isDisabled , canInsertBlocks })=>{
63
63
  const onCloseEntityDropdown = ()=>setEmbedDropdownOpen(false);
64
64
  const onToggleEntityDropdown = ()=>setEmbedDropdownOpen(!isEmbedDropdownOpen);
65
65
  const inlineEntryEmbedEnabled = (0, _validations.isNodeTypeEnabled)(sdk.field, _richtexttypes.INLINES.EMBEDDED_ENTRY);
66
+ const inlineResourceEmbedEnabled = (0, _validations.isNodeTypeEnabled)(sdk.field, _richtexttypes.INLINES.EMBEDDED_RESOURCE);
66
67
  const blockEntryEmbedEnabled = (0, _validations.isNodeTypeEnabled)(sdk.field, _richtexttypes.BLOCKS.EMBEDDED_ENTRY) && canInsertBlocks;
67
68
  const blockResourceEmbedEnabled = (0, _validations.isNodeTypeEnabled)(sdk.field, _richtexttypes.BLOCKS.EMBEDDED_RESOURCE) && canInsertBlocks;
68
69
  const blockAssetEmbedEnabled = (0, _validations.isNodeTypeEnabled)(sdk.field, _richtexttypes.BLOCKS.EMBEDDED_ASSET) && canInsertBlocks;
@@ -75,6 +76,11 @@ const EmbedEntityWidget = ({ isDisabled , canInsertBlocks })=>{
75
76
  nodeType: _richtexttypes.BLOCKS.EMBEDDED_RESOURCE,
76
77
  onClose: onCloseEntityDropdown
77
78
  }), inlineEntryEmbedEnabled && _react.default.createElement(_EmbeddedInlineToolbarIcon.EmbeddedInlineToolbarIcon, {
79
+ nodeType: _richtexttypes.INLINES.EMBEDDED_ENTRY,
80
+ isDisabled: !!isDisabled || (0, _editor.isLinkActive)(editor),
81
+ onClose: onCloseEntityDropdown
82
+ }), inlineResourceEmbedEnabled && _react.default.createElement(_EmbeddedInlineToolbarIcon.EmbeddedInlineToolbarIcon, {
83
+ nodeType: _richtexttypes.INLINES.EMBEDDED_RESOURCE,
78
84
  isDisabled: !!isDisabled || (0, _editor.isLinkActive)(editor),
79
85
  onClose: onCloseEntityDropdown
80
86
  }), blockAssetEmbedEnabled && _react.default.createElement(_EmbeddedBlockToolbarIcon.EmbeddedBlockToolbarIcon, {
@@ -205,7 +205,8 @@ function getValidationInfo(field) {
205
205
  const isAnyHyperlinkEnabled = someWithValidation([
206
206
  _richtexttypes.INLINES.HYPERLINK,
207
207
  _richtexttypes.INLINES.ASSET_HYPERLINK,
208
- _richtexttypes.INLINES.ENTRY_HYPERLINK
208
+ _richtexttypes.INLINES.ENTRY_HYPERLINK,
209
+ _richtexttypes.INLINES.RESOURCE_HYPERLINK
209
210
  ], _validations.isNodeTypeEnabled);
210
211
  const isAnyBlockFormattingEnabled = someWithValidation([
211
212
  _richtexttypes.BLOCKS.UL_LIST,
@@ -154,6 +154,17 @@ const _default = {
154
154
  }
155
155
  ]
156
156
  },
157
+ [_richtexttypes.INLINES.RESOURCE_HYPERLINK]: {
158
+ nodes: [
159
+ {
160
+ match: [
161
+ {
162
+ object: 'text'
163
+ }
164
+ ]
165
+ }
166
+ ]
167
+ },
157
168
  [_richtexttypes.INLINES.ASSET_HYPERLINK]: {
158
169
  nodes: [
159
170
  {
@@ -167,6 +178,9 @@ const _default = {
167
178
  },
168
179
  [_richtexttypes.INLINES.EMBEDDED_ENTRY]: {
169
180
  isVoid: true
181
+ },
182
+ [_richtexttypes.INLINES.EMBEDDED_RESOURCE]: {
183
+ isVoid: true
170
184
  }
171
185
  }
172
186
  };
@@ -2,25 +2,34 @@
2
2
  Object.defineProperty(exports, "__esModule", {
3
3
  value: true
4
4
  });
5
- Object.defineProperty(exports, "default", {
6
- enumerable: true,
7
- get: function() {
5
+ function _export(target, all) {
6
+ for(var name in all)Object.defineProperty(target, name, {
7
+ enumerable: true,
8
+ get: all[name]
9
+ });
10
+ }
11
+ _export(exports, {
12
+ newEntitySelectorConfigFromRichTextField: function() {
8
13
  return newEntitySelectorConfigFromRichTextField;
14
+ },
15
+ newResourceEntitySelectorConfigFromRichTextField: function() {
16
+ return newResourceEntitySelectorConfigFromRichTextField;
9
17
  }
10
18
  });
19
+ const _getAllowedResourcesForNodeType = _interop_require_default(require("./getAllowedResourcesForNodeType"));
11
20
  const _getLinkedContentTypeIdsForNodeType = _interop_require_default(require("./getLinkedContentTypeIdsForNodeType"));
12
21
  function _interop_require_default(obj) {
13
22
  return obj && obj.__esModule ? obj : {
14
23
  default: obj
15
24
  };
16
25
  }
17
- function newEntitySelectorConfigFromRichTextField(field, nodeType) {
26
+ const newEntitySelectorConfigFromRichTextField = (field, nodeType)=>{
18
27
  return {
19
28
  entityType: getEntityTypeFromRichTextNode(nodeType),
20
29
  locale: field.locale || null,
21
30
  contentTypes: (0, _getLinkedContentTypeIdsForNodeType.default)(field, nodeType)
22
31
  };
23
- }
32
+ };
24
33
  function getEntityTypeFromRichTextNode(nodeType) {
25
34
  const words = nodeType.split('-');
26
35
  if (words.indexOf('entry') !== -1) {
@@ -31,3 +40,8 @@ function getEntityTypeFromRichTextNode(nodeType) {
31
40
  }
32
41
  throw new Error(`RichText node type \`${nodeType}\` has no associated \`entityType\``);
33
42
  }
43
+ const newResourceEntitySelectorConfigFromRichTextField = (field, nodeType)=>{
44
+ return {
45
+ allowedResources: (0, _getAllowedResourcesForNodeType.default)(field, nodeType)
46
+ };
47
+ };
@@ -84,6 +84,7 @@ const _environment = require("./environment");
84
84
  const LINK_TYPES = [
85
85
  _richtexttypes.INLINES.HYPERLINK,
86
86
  _richtexttypes.INLINES.ENTRY_HYPERLINK,
87
+ _richtexttypes.INLINES.RESOURCE_HYPERLINK,
87
88
  _richtexttypes.INLINES.ASSET_HYPERLINK
88
89
  ];
89
90
  const LIST_TYPES = [
@@ -16,11 +16,13 @@ function createDragAndDropPlugin() {
16
16
  _richtexttypes.BLOCKS.EMBEDDED_ASSET,
17
17
  _richtexttypes.BLOCKS.EMBEDDED_RESOURCE,
18
18
  _richtexttypes.BLOCKS.HR,
19
- _richtexttypes.INLINES.EMBEDDED_ENTRY
19
+ _richtexttypes.INLINES.EMBEDDED_ENTRY,
20
+ _richtexttypes.INLINES.EMBEDDED_RESOURCE
20
21
  ];
21
22
  const ON_DROP_ALLOWED_TYPES = {
22
23
  TABLE: [
23
- _richtexttypes.INLINES.EMBEDDED_ENTRY
24
+ _richtexttypes.INLINES.EMBEDDED_ENTRY,
25
+ _richtexttypes.INLINES.EMBEDDED_RESOURCE
24
26
  ]
25
27
  };
26
28
  return {
@@ -13,9 +13,10 @@ const _EmbeddedInlineUtil = require("../shared/EmbeddedInlineUtil");
13
13
  const _LinkedEntityInline = require("./LinkedEntityInline");
14
14
  function createEmbeddedEntityInlinePlugin(sdk) {
15
15
  const htmlAttributeName = 'data-embedded-entity-inline-id';
16
+ const nodeType = _richtexttypes.INLINES.EMBEDDED_ENTRY;
16
17
  return {
17
- key: _richtexttypes.INLINES.EMBEDDED_ENTRY,
18
- type: _richtexttypes.INLINES.EMBEDDED_ENTRY,
18
+ key: nodeType,
19
+ type: nodeType,
19
20
  isElement: true,
20
21
  isInline: true,
21
22
  isVoid: true,
@@ -24,7 +25,7 @@ function createEmbeddedEntityInlinePlugin(sdk) {
24
25
  hotkey: 'mod+shift+2'
25
26
  },
26
27
  handlers: {
27
- onKeyDown: (0, _EmbeddedInlineUtil.getWithEmbeddedEntryInlineEvents)(sdk)
28
+ onKeyDown: (0, _EmbeddedInlineUtil.getWithEmbeddedEntryInlineEvents)(nodeType, sdk)
28
29
  },
29
30
  deserializeHtml: {
30
31
  rules: [
@@ -33,7 +34,23 @@ function createEmbeddedEntityInlinePlugin(sdk) {
33
34
  }
34
35
  ],
35
36
  withoutChildren: true,
36
- getNode: (el)=>(0, _EmbeddedInlineUtil.createInlineEntryNode)(el.getAttribute(htmlAttributeName))
37
+ getNode: (el)=>({
38
+ type: nodeType,
39
+ children: [
40
+ {
41
+ text: ''
42
+ }
43
+ ],
44
+ data: {
45
+ target: {
46
+ sys: {
47
+ id: el.getAttribute('data-entity-id'),
48
+ type: 'Link',
49
+ linkType: el.getAttribute('data-entity-type')
50
+ }
51
+ }
52
+ }
53
+ })
37
54
  }
38
55
  };
39
56
  }
@@ -0,0 +1,102 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "FetchingWrappedResourceInlineCard", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return FetchingWrappedResourceInlineCard;
9
+ }
10
+ });
11
+ const _react = _interop_require_wildcard(require("react"));
12
+ const _f36components = require("@contentful/f36-components");
13
+ const _fieldeditorreference = require("@contentful/field-editor-reference");
14
+ const _fieldeditorshared = require("@contentful/field-editor-shared");
15
+ const _richtexttypes = require("@contentful/rich-text-types");
16
+ function _getRequireWildcardCache(nodeInterop) {
17
+ if (typeof WeakMap !== "function") return null;
18
+ var cacheBabelInterop = new WeakMap();
19
+ var cacheNodeInterop = new WeakMap();
20
+ return (_getRequireWildcardCache = function(nodeInterop) {
21
+ return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
22
+ })(nodeInterop);
23
+ }
24
+ function _interop_require_wildcard(obj, nodeInterop) {
25
+ if (!nodeInterop && obj && obj.__esModule) {
26
+ return obj;
27
+ }
28
+ if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
29
+ return {
30
+ default: obj
31
+ };
32
+ }
33
+ var cache = _getRequireWildcardCache(nodeInterop);
34
+ if (cache && cache.has(obj)) {
35
+ return cache.get(obj);
36
+ }
37
+ var newObj = {};
38
+ var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
39
+ for(var key in obj){
40
+ if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
41
+ var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
42
+ if (desc && (desc.get || desc.set)) {
43
+ Object.defineProperty(newObj, key, desc);
44
+ } else {
45
+ newObj[key] = obj[key];
46
+ }
47
+ }
48
+ }
49
+ newObj.default = obj;
50
+ if (cache) {
51
+ cache.set(obj, newObj);
52
+ }
53
+ return newObj;
54
+ }
55
+ const { getEntryTitle , getEntryStatus } = _fieldeditorshared.entityHelpers;
56
+ function FetchingWrappedResourceInlineCard(props) {
57
+ const { link , onEntityFetchComplete } = props;
58
+ const { data , status: requestStatus } = (0, _fieldeditorreference.useResource)(link.linkType, link.urn);
59
+ _react.useEffect(()=>{
60
+ if (requestStatus === 'success') {
61
+ onEntityFetchComplete?.();
62
+ }
63
+ }, [
64
+ onEntityFetchComplete,
65
+ requestStatus
66
+ ]);
67
+ if (requestStatus === 'error') {
68
+ return _react.createElement(_f36components.InlineEntryCard, {
69
+ title: "Entry missing or inaccessible",
70
+ testId: _richtexttypes.INLINES.EMBEDDED_RESOURCE,
71
+ isSelected: props.isSelected
72
+ });
73
+ }
74
+ if (requestStatus === 'loading' || data === undefined) {
75
+ return _react.createElement(_f36components.InlineEntryCard, {
76
+ isLoading: true
77
+ });
78
+ }
79
+ const { resource: entry , contentType , defaultLocaleCode , space } = data;
80
+ const title = getEntryTitle({
81
+ entry,
82
+ contentType,
83
+ defaultLocaleCode,
84
+ localeCode: defaultLocaleCode,
85
+ defaultTitle: 'Untitled'
86
+ });
87
+ const status = getEntryStatus(entry?.sys);
88
+ return _react.createElement(_f36components.InlineEntryCard, {
89
+ testId: _richtexttypes.INLINES.EMBEDDED_RESOURCE,
90
+ isSelected: props.isSelected,
91
+ title: `${data.contentType.name}: ${title} (Space: ${space.name})`,
92
+ status: status,
93
+ actions: [
94
+ _react.createElement(_f36components.MenuItem, {
95
+ key: "remove",
96
+ onClick: props.onRemove,
97
+ disabled: props.isDisabled,
98
+ testId: "delete"
99
+ }, "Remove")
100
+ ]
101
+ }, _react.createElement(_f36components.Text, null, title));
102
+ }
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "LinkedResourceInline", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return LinkedResourceInline;
9
+ }
10
+ });
11
+ const _react = _interop_require_default(require("react"));
12
+ const _slatereact = require("slate-react");
13
+ const _ContentfulEditorProvider = require("../../ContentfulEditorProvider");
14
+ const _internal = require("../../internal");
15
+ const _SdkProvider = require("../../SdkProvider");
16
+ const _linkstracking = require("../links-tracking");
17
+ const _LinkedInlineWrapper = require("../shared/LinkedInlineWrapper");
18
+ const _FetchingWrappedResourceInlineCard = require("./FetchingWrappedResourceInlineCard");
19
+ function _interop_require_default(obj) {
20
+ return obj && obj.__esModule ? obj : {
21
+ default: obj
22
+ };
23
+ }
24
+ function LinkedResourceInline(props) {
25
+ const { attributes , children , element } = props;
26
+ const { onEntityFetchComplete } = (0, _linkstracking.useLinkTracking)();
27
+ const isSelected = (0, _slatereact.useSelected)();
28
+ const editor = (0, _ContentfulEditorProvider.useContentfulEditor)();
29
+ const sdk = (0, _SdkProvider.useSdkContext)();
30
+ const isDisabled = (0, _slatereact.useReadOnly)();
31
+ const link = element.data.target.sys;
32
+ function handleRemoveClick() {
33
+ if (!editor) return;
34
+ const pathToElement = (0, _internal.findNodePath)(editor, element);
35
+ (0, _internal.removeNodes)(editor, {
36
+ at: pathToElement
37
+ });
38
+ }
39
+ return _react.default.createElement(_LinkedInlineWrapper.LinkedInlineWrapper, {
40
+ attributes: attributes,
41
+ link: element.data.target,
42
+ card: _react.default.createElement(_FetchingWrappedResourceInlineCard.FetchingWrappedResourceInlineCard, {
43
+ sdk: sdk,
44
+ link: link,
45
+ isDisabled: isDisabled,
46
+ isSelected: isSelected,
47
+ onRemove: handleRemoveClick,
48
+ onEntityFetchComplete: onEntityFetchComplete
49
+ })
50
+ }, children);
51
+ }
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "createEmbeddedResourceInlinePlugin", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return createEmbeddedResourceInlinePlugin;
9
+ }
10
+ });
11
+ const _richtexttypes = require("@contentful/rich-text-types");
12
+ const _EmbeddedInlineUtil = require("../shared/EmbeddedInlineUtil");
13
+ const _LinkedResourceInline = require("./LinkedResourceInline");
14
+ function createEmbeddedResourceInlinePlugin(sdk) {
15
+ const htmlAttributeName = 'data-embedded-resource-inline-id';
16
+ const nodeType = _richtexttypes.INLINES.EMBEDDED_RESOURCE;
17
+ return {
18
+ key: nodeType,
19
+ type: nodeType,
20
+ isElement: true,
21
+ isInline: true,
22
+ isVoid: true,
23
+ component: _LinkedResourceInline.LinkedResourceInline,
24
+ options: {
25
+ hotkey: 'mod+shift+p'
26
+ },
27
+ handlers: {
28
+ onKeyDown: (0, _EmbeddedInlineUtil.getWithEmbeddedEntryInlineEvents)(nodeType, sdk)
29
+ },
30
+ deserializeHtml: {
31
+ rules: [
32
+ {
33
+ validAttribute: htmlAttributeName
34
+ }
35
+ ],
36
+ withoutChildren: true,
37
+ getNode: (el)=>({
38
+ type: nodeType,
39
+ children: [
40
+ {
41
+ text: ''
42
+ }
43
+ ],
44
+ data: {
45
+ target: {
46
+ sys: {
47
+ urn: el.getAttribute('data-entity-id'),
48
+ linkType: el.getAttribute('data-entity-type'),
49
+ type: 'ResourceLink'
50
+ }
51
+ }
52
+ }
53
+ })
54
+ }
55
+ };
56
+ }
@@ -12,6 +12,8 @@ describe('normalization', ()=>{
12
12
  uri: "https://contentful.com"
13
13
  }), (0, _testutils.jsx)("hlink", {
14
14
  entry: "entry-id"
15
+ }), (0, _testutils.jsx)("hlink", {
16
+ resource: "resource-urn"
15
17
  }), (0, _testutils.jsx)("hlink", {
16
18
  asset: "asset-id"
17
19
  }), "some text after"), (0, _testutils.jsx)("hp", null, (0, _testutils.jsx)("htext", null)));
@@ -24,6 +24,7 @@ const _fieldeditorshared = require("@contentful/field-editor-shared");
24
24
  const _richtexttypes = require("@contentful/rich-text-types");
25
25
  const _emotion = require("emotion");
26
26
  const _editor = require("../../helpers/editor");
27
+ const _getAllowedResourcesForNodeType = _interop_require_default(require("../../helpers/getAllowedResourcesForNodeType"));
27
28
  const _getLinkedContentTypeIdsForNodeType = _interop_require_default(require("../../helpers/getLinkedContentTypeIdsForNodeType"));
28
29
  const _validations = require("../../helpers/validations");
29
30
  const _internal = require("../../internal");
@@ -31,6 +32,7 @@ const _queries = require("../../internal/queries");
31
32
  const _transforms = require("../../internal/transforms");
32
33
  const _FetchingWrappedAssetCard = require("../shared/FetchingWrappedAssetCard");
33
34
  const _FetchingWrappedEntryCard = require("../shared/FetchingWrappedEntryCard");
35
+ const _FetchingWrappedResourceCard = require("../shared/FetchingWrappedResourceCard");
34
36
  function _interop_require_default(obj) {
35
37
  return obj && obj.__esModule ? obj : {
36
38
  default: obj
@@ -78,15 +80,18 @@ function _interop_require_wildcard(obj, nodeInterop) {
78
80
  const styles = {
79
81
  removeSelectionLabel: (0, _emotion.css)`
80
82
  margin-left: ${_f36tokens.default.spacingS};
83
+ margin-bottom: ${_f36tokens.default.spacingXs}; // to match FormLabel margin
81
84
  `
82
85
  };
83
86
  const SYS_LINK_TYPES = {
84
87
  [_richtexttypes.INLINES.ENTRY_HYPERLINK]: 'Entry',
85
- [_richtexttypes.INLINES.ASSET_HYPERLINK]: 'Asset'
88
+ [_richtexttypes.INLINES.ASSET_HYPERLINK]: 'Asset',
89
+ [_richtexttypes.INLINES.RESOURCE_HYPERLINK]: 'Contentful:Entry'
86
90
  };
87
91
  const LINK_TYPE_SELECTION_VALUES = {
88
92
  [_richtexttypes.INLINES.HYPERLINK]: 'URL',
89
93
  [_richtexttypes.INLINES.ENTRY_HYPERLINK]: 'Entry',
94
+ [_richtexttypes.INLINES.RESOURCE_HYPERLINK]: 'Entry (different space)',
90
95
  [_richtexttypes.INLINES.ASSET_HYPERLINK]: 'Asset'
91
96
  };
92
97
  function HyperlinkModal(props) {
@@ -112,7 +117,16 @@ function HyperlinkModal(props) {
112
117
  const entityLinks = Object.keys(SYS_LINK_TYPES);
113
118
  const isEntityLink = entityLinks.includes(linkType);
114
119
  if (isEntityLink) {
115
- return !!(linkText && linkEntity);
120
+ if (linkType === _richtexttypes.INLINES.ENTRY_HYPERLINK) {
121
+ return !!(linkText && isEntryLink(linkEntity));
122
+ }
123
+ if (linkType === _richtexttypes.INLINES.ASSET_HYPERLINK) {
124
+ return !!(linkText && isAssetLink(linkEntity));
125
+ }
126
+ if (linkType === _richtexttypes.INLINES.RESOURCE_HYPERLINK) {
127
+ return !!(linkText && isResourceLink(linkEntity));
128
+ }
129
+ return false;
116
130
  }
117
131
  return false;
118
132
  }
@@ -135,22 +149,55 @@ function HyperlinkModal(props) {
135
149
  }
136
150
  };
137
151
  }
152
+ function entityToResourceLink(entity) {
153
+ const { urn } = entity.sys;
154
+ return {
155
+ sys: {
156
+ urn,
157
+ type: 'ResourceLink',
158
+ linkType: 'Contentful:Entry'
159
+ }
160
+ };
161
+ }
162
+ function isResourceLink(link) {
163
+ return !!link && !!link.sys.urn;
164
+ }
165
+ function isEntryLink(link) {
166
+ return !!link && link.sys.type === 'Link' && link.sys.linkType === 'Entry';
167
+ }
168
+ function isAssetLink(link) {
169
+ return !!link && link.sys.type === 'Link' && link.sys.linkType === 'Asset';
170
+ }
138
171
  async function selectEntry() {
139
172
  const options = {
140
173
  locale: props.sdk.field.locale,
141
174
  contentTypes: (0, _getLinkedContentTypeIdsForNodeType.default)(props.sdk.field, _richtexttypes.INLINES.ENTRY_HYPERLINK)
142
175
  };
143
176
  const entry = await props.sdk.dialogs.selectSingleEntry(options);
144
- setLinkTarget('');
145
- setLinkEntity(entityToLink(entry));
177
+ if (entry) {
178
+ setLinkTarget('');
179
+ setLinkEntity(entityToLink(entry));
180
+ }
181
+ }
182
+ async function selectResourceEntry() {
183
+ const options = {
184
+ allowedResources: (0, _getAllowedResourcesForNodeType.default)(props.sdk.field, _richtexttypes.INLINES.RESOURCE_HYPERLINK)
185
+ };
186
+ const entry = await props.sdk.dialogs.selectSingleResourceEntry(options);
187
+ if (entry) {
188
+ setLinkTarget('');
189
+ setLinkEntity(entityToResourceLink(entry));
190
+ }
146
191
  }
147
192
  async function selectAsset() {
148
193
  const options = {
149
194
  locale: props.sdk.field.locale
150
195
  };
151
196
  const asset = await props.sdk.dialogs.selectSingleAsset(options);
152
- setLinkTarget('');
153
- setLinkEntity(entityToLink(asset));
197
+ if (asset) {
198
+ setLinkTarget('');
199
+ setLinkEntity(entityToLink(asset));
200
+ }
154
201
  }
155
202
  function resetLinkEntity(event) {
156
203
  event.preventDefault();
@@ -196,13 +243,18 @@ function HyperlinkModal(props) {
196
243
  testId: "entity-selection-link",
197
244
  onClick: resetLinkEntity,
198
245
  className: styles.removeSelectionLabel
199
- }, "Remove selection"), _react.createElement("div", null, linkType === _richtexttypes.INLINES.ENTRY_HYPERLINK && _react.createElement(_FetchingWrappedEntryCard.FetchingWrappedEntryCard, {
246
+ }, "Remove selection"), _react.createElement("div", null, linkType === _richtexttypes.INLINES.ENTRY_HYPERLINK && isEntryLink(linkEntity) && _react.createElement(_FetchingWrappedEntryCard.FetchingWrappedEntryCard, {
200
247
  sdk: props.sdk,
201
248
  locale: props.sdk.field.locale,
202
249
  entryId: linkEntity.sys.id,
203
250
  isDisabled: true,
204
251
  isSelected: false
205
- }), linkType === _richtexttypes.INLINES.ASSET_HYPERLINK && _react.createElement(_FetchingWrappedAssetCard.FetchingWrappedAssetCard, {
252
+ }), linkType === _richtexttypes.INLINES.RESOURCE_HYPERLINK && isResourceLink(linkEntity) && _react.createElement(_FetchingWrappedResourceCard.FetchingWrappedResourceCard, {
253
+ sdk: props.sdk,
254
+ link: linkEntity.sys,
255
+ isDisabled: true,
256
+ isSelected: false
257
+ }), linkType === _richtexttypes.INLINES.ASSET_HYPERLINK && isAssetLink(linkEntity) && _react.createElement(_FetchingWrappedAssetCard.FetchingWrappedAssetCard, {
206
258
  sdk: props.sdk,
207
259
  locale: props.sdk.field.locale,
208
260
  assetId: linkEntity.sys.id,
@@ -211,6 +263,9 @@ function HyperlinkModal(props) {
211
263
  }))) : _react.createElement("div", null, linkType === _richtexttypes.INLINES.ENTRY_HYPERLINK && _react.createElement(_f36components.TextLink, {
212
264
  testId: "entity-selection-link",
213
265
  onClick: selectEntry
266
+ }, "Select entry"), linkType === _richtexttypes.INLINES.RESOURCE_HYPERLINK && _react.createElement(_f36components.TextLink, {
267
+ testId: "entity-selection-link",
268
+ onClick: selectResourceEntry
214
269
  }, "Select entry"), linkType === _richtexttypes.INLINES.ASSET_HYPERLINK && _react.createElement(_f36components.TextLink, {
215
270
  testId: "entity-selection-link",
216
271
  onClick: selectAsset
@@ -11,12 +11,14 @@ describe('normalization', ()=>{
11
11
  asset: "asset-id"
12
12
  })), (0, _testutils.jsx)("hp", null, (0, _testutils.jsx)("htext", null, "entry"), (0, _testutils.jsx)("hlink", {
13
13
  entry: "entry-id"
14
+ })), (0, _testutils.jsx)("hp", null, (0, _testutils.jsx)("htext", null, "resource"), (0, _testutils.jsx)("hlink", {
15
+ resource: "resource-urn"
14
16
  })), (0, _testutils.jsx)("hp", null, (0, _testutils.jsx)("htext", null, "explicit empty link"), (0, _testutils.jsx)("hlink", {
15
17
  uri: "https://link.com"
16
18
  }, '')), (0, _testutils.jsx)("hp", null, (0, _testutils.jsx)("htext", null, "link with empty space"), (0, _testutils.jsx)("hlink", {
17
19
  uri: "https://link.com"
18
20
  }, " ")));
19
- const expected = (0, _testutils.jsx)("editor", null, (0, _testutils.jsx)("hp", null, (0, _testutils.jsx)("htext", null, "link")), (0, _testutils.jsx)("hp", null, (0, _testutils.jsx)("htext", null, "asset")), (0, _testutils.jsx)("hp", null, (0, _testutils.jsx)("htext", null, "entry")), (0, _testutils.jsx)("hp", null, (0, _testutils.jsx)("htext", null, "explicit empty link")), (0, _testutils.jsx)("hp", null, (0, _testutils.jsx)("htext", null, "link with empty space")));
21
+ const expected = (0, _testutils.jsx)("editor", null, (0, _testutils.jsx)("hp", null, (0, _testutils.jsx)("htext", null, "link")), (0, _testutils.jsx)("hp", null, (0, _testutils.jsx)("htext", null, "asset")), (0, _testutils.jsx)("hp", null, (0, _testutils.jsx)("htext", null, "entry")), (0, _testutils.jsx)("hp", null, (0, _testutils.jsx)("htext", null, "resource")), (0, _testutils.jsx)("hp", null, (0, _testutils.jsx)("htext", null, "explicit empty link")), (0, _testutils.jsx)("hp", null, (0, _testutils.jsx)("htext", null, "link with empty space")));
20
22
  (0, _testutils.assertOutput)({
21
23
  input,
22
24
  expected
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "ResourceHyperlink", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return ResourceHyperlink;
9
+ }
10
+ });
11
+ const _react = _interop_require_wildcard(require("react"));
12
+ const _f36components = require("@contentful/f36-components");
13
+ const _ContentfulEditorProvider = require("../../../ContentfulEditorProvider");
14
+ const _internal = require("../../../internal");
15
+ const _linkstracking = require("../../../plugins/links-tracking");
16
+ const _SdkProvider = require("../../../SdkProvider");
17
+ const _HyperlinkModal = require("../HyperlinkModal");
18
+ const _useResourceEntityInfo = require("../useResourceEntityInfo");
19
+ const _styles = require("./styles");
20
+ function _getRequireWildcardCache(nodeInterop) {
21
+ if (typeof WeakMap !== "function") return null;
22
+ var cacheBabelInterop = new WeakMap();
23
+ var cacheNodeInterop = new WeakMap();
24
+ return (_getRequireWildcardCache = function(nodeInterop) {
25
+ return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
26
+ })(nodeInterop);
27
+ }
28
+ function _interop_require_wildcard(obj, nodeInterop) {
29
+ if (!nodeInterop && obj && obj.__esModule) {
30
+ return obj;
31
+ }
32
+ if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
33
+ return {
34
+ default: obj
35
+ };
36
+ }
37
+ var cache = _getRequireWildcardCache(nodeInterop);
38
+ if (cache && cache.has(obj)) {
39
+ return cache.get(obj);
40
+ }
41
+ var newObj = {};
42
+ var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
43
+ for(var key in obj){
44
+ if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
45
+ var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
46
+ if (desc && (desc.get || desc.set)) {
47
+ Object.defineProperty(newObj, key, desc);
48
+ } else {
49
+ newObj[key] = obj[key];
50
+ }
51
+ }
52
+ }
53
+ newObj.default = obj;
54
+ if (cache) {
55
+ cache.set(obj, newObj);
56
+ }
57
+ return newObj;
58
+ }
59
+ function ResourceHyperlink(props) {
60
+ const editor = (0, _ContentfulEditorProvider.useContentfulEditor)();
61
+ const sdk = (0, _SdkProvider.useSdkContext)();
62
+ const { target } = props.element.data;
63
+ const { onEntityFetchComplete } = (0, _linkstracking.useLinkTracking)();
64
+ const tooltipContent = (0, _useResourceEntityInfo.useResourceEntityInfo)({
65
+ target,
66
+ onEntityFetchComplete
67
+ });
68
+ if (!target) return null;
69
+ function handleClick(event) {
70
+ event.preventDefault();
71
+ event.stopPropagation();
72
+ if (!editor) return;
73
+ const p = (0, _internal.fromDOMPoint)(editor, [
74
+ event.target,
75
+ 0
76
+ ]);
77
+ if (p) {
78
+ (0, _HyperlinkModal.addOrEditLink)(editor, sdk, editor.tracking.onViewportAction, p.path);
79
+ }
80
+ }
81
+ return _react.createElement(_f36components.Tooltip, {
82
+ content: tooltipContent,
83
+ targetWrapperClassName: _styles.styles.hyperlinkWrapper,
84
+ placement: "bottom",
85
+ maxWidth: "auto"
86
+ }, _react.createElement(_f36components.TextLink, {
87
+ as: "a",
88
+ onClick: handleClick,
89
+ className: _styles.styles.hyperlink,
90
+ "data-resource-link-type": target.sys.linkType,
91
+ "data-resource-link-urn": target.sys.urn
92
+ }, props.children));
93
+ }