@atlaskit/editor-plugin-synced-block 5.3.1 → 5.3.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.
Files changed (41) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/afm-cc/tsconfig.json +4 -1
  3. package/dist/cjs/editor-commands/index.js +4 -0
  4. package/dist/cjs/pm-plugins/main.js +8 -1
  5. package/dist/cjs/pm-plugins/utils/handle-bodied-sync-block-removal.js +2 -2
  6. package/dist/cjs/ui/DeleteConfirmationModal.compiled.css +2 -0
  7. package/dist/cjs/ui/DeleteConfirmationModal.js +151 -13
  8. package/dist/cjs/ui/SyncBlockLabel.js +44 -94
  9. package/dist/cjs/ui/SyncBlockRendererWrapper.js +2 -1
  10. package/dist/cjs/ui/SyncedLocationDropdown.js +9 -3
  11. package/dist/cjs/ui/floating-toolbar.js +2 -2
  12. package/dist/cjs/ui/utils/time.js +63 -0
  13. package/dist/es2019/editor-commands/index.js +4 -0
  14. package/dist/es2019/pm-plugins/main.js +8 -1
  15. package/dist/es2019/pm-plugins/utils/handle-bodied-sync-block-removal.js +2 -2
  16. package/dist/es2019/ui/DeleteConfirmationModal.compiled.css +2 -0
  17. package/dist/es2019/ui/DeleteConfirmationModal.js +121 -12
  18. package/dist/es2019/ui/SyncBlockLabel.js +18 -72
  19. package/dist/es2019/ui/SyncBlockRendererWrapper.js +2 -1
  20. package/dist/es2019/ui/SyncedLocationDropdown.js +9 -3
  21. package/dist/es2019/ui/floating-toolbar.js +2 -2
  22. package/dist/es2019/ui/utils/time.js +56 -0
  23. package/dist/esm/editor-commands/index.js +4 -0
  24. package/dist/esm/pm-plugins/main.js +8 -1
  25. package/dist/esm/pm-plugins/utils/handle-bodied-sync-block-removal.js +2 -2
  26. package/dist/esm/ui/DeleteConfirmationModal.compiled.css +2 -0
  27. package/dist/esm/ui/DeleteConfirmationModal.js +152 -14
  28. package/dist/esm/ui/SyncBlockLabel.js +42 -92
  29. package/dist/esm/ui/SyncBlockRendererWrapper.js +2 -1
  30. package/dist/esm/ui/SyncedLocationDropdown.js +9 -3
  31. package/dist/esm/ui/floating-toolbar.js +2 -2
  32. package/dist/esm/ui/utils/time.js +56 -0
  33. package/dist/types/pm-plugins/utils/handle-bodied-sync-block-removal.d.ts +2 -2
  34. package/dist/types/ui/SyncBlockLabel.d.ts +2 -4
  35. package/dist/types/ui/SyncBlockRendererWrapper.d.ts +1 -1
  36. package/dist/types/ui/utils/time.d.ts +2 -0
  37. package/dist/types-ts4.5/pm-plugins/utils/handle-bodied-sync-block-removal.d.ts +2 -2
  38. package/dist/types-ts4.5/ui/SyncBlockLabel.d.ts +2 -4
  39. package/dist/types-ts4.5/ui/SyncBlockRendererWrapper.d.ts +1 -1
  40. package/dist/types-ts4.5/ui/utils/time.d.ts +2 -0
  41. package/package.json +3 -3
@@ -1,4 +1,9 @@
1
+ /* DeleteConfirmationModal.tsx generated by @compiled/babel-plugin v0.38.1 */
2
+ import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
1
3
  import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
4
+ import "./DeleteConfirmationModal.compiled.css";
5
+ import { ax, ix } from "@compiled/react/runtime";
6
+ import _regeneratorRuntime from "@babel/runtime/regenerator";
2
7
  import React, { useCallback, useEffect, useState } from 'react';
3
8
  import { useIntl } from 'react-intl-next';
4
9
  import Button from '@atlaskit/button/new';
@@ -7,20 +12,52 @@ import { syncBlockMessages as messages } from '@atlaskit/editor-common/messages'
7
12
  import { isOfflineMode } from '@atlaskit/editor-plugin-connectivity';
8
13
  import ModalDialog, { ModalBody, ModalFooter, ModalHeader, ModalTitle, ModalTransition } from '@atlaskit/modal-dialog';
9
14
  import { fg } from '@atlaskit/platform-feature-flags';
10
- import { Text } from '@atlaskit/primitives/compiled';
15
+ import { Text, Box } from '@atlaskit/primitives/compiled';
16
+ import Spinner from '@atlaskit/spinner';
11
17
  import { syncedBlockPluginKey } from '../pm-plugins/main';
18
+ var modalContentMap = {
19
+ 'source-block-deleted': {
20
+ titleMultiple: messages.deleteConfirmationModalTitleSingle,
21
+ titleSingle: messages.deleteConfirmationModalTitleSingle,
22
+ descriptionSingle: messages.deleteConfirmationModalDescriptionNoRef,
23
+ descriptionMultiple: messages.deleteConfirmationModalDescription,
24
+ confirmButtonLabel: messages.deleteConfirmationModalDeleteButton
25
+ },
26
+ 'source-block-unsynced': {
27
+ titleMultiple: messages.unsyncConfirmationModalTitle,
28
+ titleSingle: messages.unsyncConfirmationModalTitle,
29
+ descriptionSingle: messages.unsyncConfirmationModalDescriptionSingle,
30
+ descriptionMultiple: messages.unsyncConfirmationModalDescriptionMultiple,
31
+ confirmButtonLabel: messages.deleteConfirmationModalUnsyncButton
32
+ }
33
+ };
34
+ var styles = {
35
+ spinner: "_1mou1wug _195g1wug"
36
+ };
12
37
  export var DeleteConfirmationModal = function DeleteConfirmationModal(_ref) {
13
- var _api$core2, _api$core4, _api$core6;
38
+ var _api$core2, _api$core4, _api$core6, _syncBlockIds$length;
14
39
  var syncBlockStoreManager = _ref.syncBlockStoreManager,
15
40
  api = _ref.api;
16
41
  var _useState = useState(false),
17
42
  _useState2 = _slicedToArray(_useState, 2),
18
43
  isOpen = _useState2[0],
19
44
  setIsOpen = _useState2[1];
20
- var _useState3 = useState(1),
45
+ var _useState3 = useState(undefined),
21
46
  _useState4 = _slicedToArray(_useState3, 2),
22
- syncBlockCount = _useState4[0],
23
- setSyncBlockCount = _useState4[1];
47
+ syncBlockIds = _useState4[0],
48
+ setSyncBlockIds = _useState4[1];
49
+ var _useState5 = useState(undefined),
50
+ _useState6 = _slicedToArray(_useState5, 2),
51
+ referenceCount = _useState6[0],
52
+ setReferenceCount = _useState6[1];
53
+ var _useState7 = useState('source-block-deleted'),
54
+ _useState8 = _slicedToArray(_useState7, 2),
55
+ deleteReason = _useState8[0],
56
+ setDeleteReason = _useState8[1];
57
+ var _useState9 = useState('none'),
58
+ _useState0 = _slicedToArray(_useState9, 2),
59
+ fetchStatus = _useState0[0],
60
+ setFetchStatus = _useState0[1];
24
61
  var _useSharedPluginState = useSharedPluginStateWithSelector(api, ['connectivity', 'syncedBlock'], function (states) {
25
62
  var _states$connectivityS, _states$syncedBlockSt, _states$syncedBlockSt2;
26
63
  return {
@@ -44,6 +81,8 @@ export var DeleteConfirmationModal = function DeleteConfirmationModal(_ref) {
44
81
  }
45
82
  if (!confirm) {
46
83
  setIsOpen(false);
84
+ setFetchStatus('none');
85
+ setReferenceCount(undefined);
47
86
  }
48
87
  api === null || api === void 0 || (_api$core = api.core) === null || _api$core === void 0 || _api$core.actions.execute(function (_ref2) {
49
88
  var tr = _ref2.tr;
@@ -54,9 +93,12 @@ export var DeleteConfirmationModal = function DeleteConfirmationModal(_ref) {
54
93
  });
55
94
  };
56
95
  }, [api === null || api === void 0 || (_api$core2 = api.core) === null || _api$core2 === void 0 ? void 0 : _api$core2.actions]);
57
- var confirmationCallback = useCallback(function (syncBlockCount) {
96
+ var confirmationCallback = useCallback(function (syncBlockIds, deleteReason) {
58
97
  setIsOpen(true);
59
- setSyncBlockCount(syncBlockCount);
98
+ setSyncBlockIds(syncBlockIds);
99
+ if (deleteReason) {
100
+ setDeleteReason(deleteReason);
101
+ }
60
102
  var confirmedPromise = new Promise(function (resolve) {
61
103
  resolverRef.current = resolve;
62
104
  });
@@ -83,6 +125,7 @@ export var DeleteConfirmationModal = function DeleteConfirmationModal(_ref) {
83
125
  var _api$core5;
84
126
  // auto close modal once deletion is successful
85
127
  setIsOpen(false);
128
+ setFetchStatus('none');
86
129
  api === null || api === void 0 || (_api$core5 = api.core) === null || _api$core5 === void 0 || _api$core5.actions.execute(function (_ref4) {
87
130
  var tr = _ref4.tr;
88
131
  return tr.setMeta(syncedBlockPluginKey, {
@@ -92,15 +135,76 @@ export var DeleteConfirmationModal = function DeleteConfirmationModal(_ref) {
92
135
  });
93
136
  }
94
137
  }, [api === null || api === void 0 || (_api$core6 = api.core) === null || _api$core6 === void 0 ? void 0 : _api$core6.actions, bodiedSyncBlockDeletionStatus, isOpen]);
138
+ useEffect(function () {
139
+ if (isOpen && syncBlockIds !== undefined && fg('platform_synced_block_dogfooding')) {
140
+ var _referenceCount = 0;
141
+ setFetchStatus('loading');
142
+ var fetchFailed = false;
143
+ syncBlockIds.forEach( /*#__PURE__*/function () {
144
+ var _ref5 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(syncBlockId) {
145
+ var references, _references$reference, _references$reference2;
146
+ return _regeneratorRuntime.wrap(function _callee$(_context) {
147
+ while (1) switch (_context.prev = _context.next) {
148
+ case 0:
149
+ if (!fetchFailed) {
150
+ _context.next = 2;
151
+ break;
152
+ }
153
+ return _context.abrupt("return");
154
+ case 2:
155
+ _context.next = 4;
156
+ return syncBlockStoreManager.sourceManager.fetchReferences(syncBlockId.resourceId);
157
+ case 4:
158
+ references = _context.sent;
159
+ if (!references.error) {
160
+ _context.next = 11;
161
+ break;
162
+ }
163
+ // Consider fetch fails as soon as one of the fetches fails
164
+ setFetchStatus('error');
165
+ fetchFailed = true;
166
+ return _context.abrupt("return");
167
+ case 11:
168
+ _referenceCount += (_references$reference = (_references$reference2 = references.references) === null || _references$reference2 === void 0 ? void 0 : _references$reference2.length) !== null && _references$reference !== void 0 ? _references$reference : 0;
169
+ case 12:
170
+ case "end":
171
+ return _context.stop();
172
+ }
173
+ }, _callee);
174
+ }));
175
+ return function (_x) {
176
+ return _ref5.apply(this, arguments);
177
+ };
178
+ }());
179
+ if (!fetchFailed) {
180
+ setReferenceCount(_referenceCount);
181
+ setFetchStatus('success');
182
+ }
183
+ }
184
+ }, [isOpen, syncBlockIds, syncBlockStoreManager.sourceManager]);
95
185
  return /*#__PURE__*/React.createElement(ModalTransition, null, isOpen && /*#__PURE__*/React.createElement(ModalDialog, {
96
186
  onClose: handleClick(false),
97
- testId: "sync-block-delete-confirmation"
98
- }, /*#__PURE__*/React.createElement(ModalHeader, {
187
+ testId: "sync-block-delete-confirmation",
188
+ height: 184
189
+ }, fg('platform_synced_block_dogfooding') ? /*#__PURE__*/React.createElement(React.Fragment, null, referenceCount === undefined ? /*#__PURE__*/React.createElement(Box, {
190
+ xcss: styles.spinner
191
+ }, /*#__PURE__*/React.createElement(Spinner, {
192
+ size: "large"
193
+ })) : /*#__PURE__*/React.createElement(ModalContent, {
194
+ content: modalContentMap[deleteReason],
195
+ referenceCount: referenceCount,
196
+ handleClick: handleClick,
197
+ formatMessage: formatMessage,
198
+ isDeleting: bodiedSyncBlockDeletionStatus === 'processing',
199
+ isDisabled: isOfflineMode(mode),
200
+ deleteReason: deleteReason,
201
+ failToFetch: fetchStatus === 'error'
202
+ })) : /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(ModalHeader, {
99
203
  hasCloseButton: true
100
204
  }, /*#__PURE__*/React.createElement(ModalTitle, {
101
205
  appearance: "warning"
102
- }, formatMessage(messages.deleteConfirmationModalTitle))), /*#__PURE__*/React.createElement(ModalBody, null, /*#__PURE__*/React.createElement(Text, null, formatMessage(messages.deleteConfirmationModalDescription, {
103
- syncBlockCount: syncBlockCount
206
+ }, formatMessage(messages.deleteConfirmationModalTitleSingle))), /*#__PURE__*/React.createElement(ModalBody, null, /*#__PURE__*/React.createElement(Text, null, formatMessage(messages.deleteConfirmationModalDescription, {
207
+ syncBlockCount: (_syncBlockIds$length = syncBlockIds === null || syncBlockIds === void 0 ? void 0 : syncBlockIds.length) !== null && _syncBlockIds$length !== void 0 ? _syncBlockIds$length : 1
104
208
  }))), /*#__PURE__*/React.createElement(ModalFooter, null, /*#__PURE__*/React.createElement(Button, {
105
209
  appearance: "subtle",
106
210
  onClick: handleClick(false)
@@ -109,7 +213,41 @@ export var DeleteConfirmationModal = function DeleteConfirmationModal(_ref) {
109
213
  onClick: handleClick(true),
110
214
  autoFocus: true,
111
215
  isDisabled: isOfflineMode(mode),
112
- isLoading: bodiedSyncBlockDeletionStatus === 'processing',
113
- testId: fg('platform_synced_block_dogfooding') ? 'synced-block-delete-confirmation-modal-delete-button' : undefined
114
- }, formatMessage(messages.deleteConfirmationModalDeleteButton)))));
216
+ isLoading: bodiedSyncBlockDeletionStatus === 'processing'
217
+ }, formatMessage(messages.deleteConfirmationModalDeleteButton))))));
218
+ };
219
+ var ModalContent = function ModalContent(_ref6) {
220
+ var content = _ref6.content,
221
+ referenceCount = _ref6.referenceCount,
222
+ handleClick = _ref6.handleClick,
223
+ formatMessage = _ref6.formatMessage,
224
+ isDeleting = _ref6.isDeleting,
225
+ isDisabled = _ref6.isDisabled,
226
+ deleteReason = _ref6.deleteReason,
227
+ failToFetch = _ref6.failToFetch;
228
+ var titleMultiple = content.titleMultiple,
229
+ titleSingle = content.titleSingle,
230
+ descriptionSingle = content.descriptionSingle,
231
+ descriptionMultiple = content.descriptionMultiple,
232
+ confirmButtonLabel = content.confirmButtonLabel;
233
+ var hasNoReferenceOrFailToFetch = referenceCount === 0 || failToFetch;
234
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(ModalHeader, {
235
+ hasCloseButton: true
236
+ }, /*#__PURE__*/React.createElement(ModalTitle, {
237
+ appearance: "warning"
238
+ }, hasNoReferenceOrFailToFetch ? formatMessage(titleSingle) : formatMessage(titleMultiple, {
239
+ count: referenceCount
240
+ }))), /*#__PURE__*/React.createElement(ModalBody, null, /*#__PURE__*/React.createElement(Text, null, hasNoReferenceOrFailToFetch ? formatMessage(descriptionSingle) : formatMessage(descriptionMultiple, {
241
+ syncBlockCount: referenceCount
242
+ }))), /*#__PURE__*/React.createElement(ModalFooter, null, /*#__PURE__*/React.createElement(Button, {
243
+ appearance: "subtle",
244
+ onClick: handleClick(false)
245
+ }, formatMessage(messages.deleteConfirmationModalCancelButton)), /*#__PURE__*/React.createElement(Button, {
246
+ appearance: "warning",
247
+ onClick: handleClick(true),
248
+ autoFocus: true,
249
+ isDisabled: isDisabled,
250
+ isLoading: isDeleting,
251
+ testId: "synced-block-delete-confirmation-modal-".concat(deleteReason, "-button")
252
+ }, formatMessage(confirmButtonLabel))));
115
253
  };
@@ -1,6 +1,5 @@
1
1
  import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
2
2
  import React, { useCallback, useState } from 'react';
3
- import isYesterday from 'date-fns/isYesterday';
4
3
  import { useIntl } from 'react-intl-next';
5
4
  import { syncBlockMessages as messages } from '@atlaskit/editor-common/messages';
6
5
  import { SyncBlockLabelSharedCssClassName } from '@atlaskit/editor-common/sync-block';
@@ -9,76 +8,21 @@ import { fg } from '@atlaskit/platform-feature-flags';
9
8
  import { Text } from '@atlaskit/primitives/compiled';
10
9
  import Tooltip from '@atlaskit/tooltip';
11
10
  import VisuallyHidden from '@atlaskit/visually-hidden';
11
+ import { formatElapsedTime } from './utils/time';
12
12
  var SyncBlockLabelDataId = 'sync-block-label';
13
- var SECONDS_IN_MINUTE = 60;
14
- var SECONDS_IN_HOUR = SECONDS_IN_MINUTE * 60;
15
- var SECONDS_IN_DAY = SECONDS_IN_HOUR * 24;
16
- var SECONDS_IN_WEEK = SECONDS_IN_DAY * 7;
17
- var SECONDS_IN_MONTH = SECONDS_IN_DAY * 30;
18
- var SECONDS_IN_YEAR = SECONDS_IN_DAY * 365;
19
- export var formatElapsedTime = function formatElapsedTime(isoDate, intl) {
20
- var now = Date.now();
21
- var date = new Date(isoDate).getTime();
22
- var diffInSeconds = Math.floor((now - date) / 1000);
23
- var dateObj = new Date(isoDate);
24
-
25
- // Show "yesterday" when timestamp is from the previous calendar day
26
- if (isYesterday(dateObj) && diffInSeconds >= SECONDS_IN_DAY) {
27
- return intl.formatRelativeTime(-1, 'day', {
28
- numeric: 'auto',
29
- style: 'long'
30
- });
31
- }
32
- if (diffInSeconds < SECONDS_IN_MINUTE) {
33
- return intl.formatRelativeTime(-Math.max(diffInSeconds, 1), 'second', {
34
- style: 'long'
35
- });
36
- } else if (diffInSeconds < SECONDS_IN_HOUR) {
37
- var minutes = Math.floor(diffInSeconds / SECONDS_IN_MINUTE);
38
- return intl.formatRelativeTime(-minutes, 'minute', {
39
- style: 'long'
40
- });
41
- } else if (diffInSeconds < SECONDS_IN_DAY) {
42
- var hours = Math.floor(diffInSeconds / SECONDS_IN_HOUR);
43
- return intl.formatRelativeTime(-hours, 'hour', {
44
- style: 'long'
45
- });
46
- } else if (diffInSeconds < SECONDS_IN_WEEK) {
47
- var days = Math.floor(diffInSeconds / SECONDS_IN_DAY);
48
- return intl.formatRelativeTime(-days, 'day', {
49
- style: 'long'
50
- });
51
- } else if (diffInSeconds < SECONDS_IN_MONTH) {
52
- var weeks = Math.floor(diffInSeconds / SECONDS_IN_WEEK);
53
- return intl.formatRelativeTime(-weeks, 'week', {
54
- style: 'long'
55
- });
56
- } else if (diffInSeconds < SECONDS_IN_YEAR) {
57
- var months = Math.floor(diffInSeconds / SECONDS_IN_MONTH);
58
- return intl.formatRelativeTime(-months, 'month', {
59
- style: 'long'
60
- });
61
- } else {
62
- var years = Math.floor(diffInSeconds / SECONDS_IN_YEAR);
63
- return intl.formatRelativeTime(-years, 'year', {
64
- style: 'long'
65
- });
66
- }
67
- };
68
13
  var SyncBlockLabelComponent = function SyncBlockLabelComponent(_ref) {
69
- var isSource = _ref.isSource,
70
- useFetchSyncBlockTitle = _ref.useFetchSyncBlockTitle,
14
+ var contentUpdatedAt = _ref.contentUpdatedAt,
15
+ isSource = _ref.isSource,
71
16
  localId = _ref.localId,
72
- contentUpdatedAt = _ref.contentUpdatedAt;
17
+ title = _ref.title;
73
18
  var intl = useIntl();
74
19
  var formatMessage = intl.formatMessage;
75
- var title = useFetchSyncBlockTitle === null || useFetchSyncBlockTitle === void 0 ? void 0 : useFetchSyncBlockTitle();
76
20
  var _useState = useState(formatMessage(messages.defaultSyncBlockTooltip)),
77
21
  _useState2 = _slicedToArray(_useState, 2),
78
22
  tooltipContent = _useState2[0],
79
23
  setTooltipContent = _useState2[1];
80
24
  var tooltipMessage = formatMessage(messages.defaultSyncBlockTooltip);
81
- if (isSource) {
25
+ if (isSource && !fg('platform_synced_block_dogfooding')) {
82
26
  tooltipMessage = formatMessage(messages.sourceSyncBlockTooltip);
83
27
  } else if (title) {
84
28
  tooltipMessage = formatMessage(messages.referenceSyncBlockTooltip, {
@@ -107,36 +51,42 @@ var SyncBlockLabelComponent = function SyncBlockLabelComponent(_ref) {
107
51
  setTooltipContent(tooltipContent);
108
52
  }, [contentUpdatedAt, formatMessage, intl, tooltipMessage]);
109
53
  var ariaDescribedById = "sync-block-label-description-".concat(localId);
110
- return /*#__PURE__*/React.createElement(Tooltip, {
111
- position: "top",
112
- content: fg('platform_synced_block_dogfooding') ? tooltipContent : tooltipMessage
113
- // workaround because tooltip adds aria-describedby with a new id every time the tooltip is opened
114
- // this causes an infinite rerender loop because of the forwardRef from the node view we are inside in bodiedSyncBlock
115
- // tooltip content is available for screen readers in visually hidden content after the label
116
- ,
117
- isScreenReaderAnnouncementDisabled: true
118
- // using this to ensure that the 'last edited' time is updated when the tooltip is opened
119
- ,
120
- onShow: updateTooltipContent
121
- }, /*#__PURE__*/React.createElement("div", {
122
- "data-testid": SyncBlockLabelDataId
123
- // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop
124
- ,
125
- className: SyncBlockLabelSharedCssClassName.labelClassName,
126
- "aria-describedby": ariaDescribedById
127
- }, /*#__PURE__*/React.createElement(BlockSyncedIcon, {
128
- color: "var(--ds-icon-subtle, #505258)",
129
- size: "small",
130
- label: ""
131
- }), isSource || !title ? /*#__PURE__*/React.createElement(Text, {
132
- size: "small",
133
- color: "color.text.subtle"
134
- }, formatMessage(messages.syncedBlockLabel)) : /*#__PURE__*/React.createElement(Text, {
135
- maxLines: 1,
136
- size: "small",
137
- color: "color.text.subtle"
138
- }, title)), /*#__PURE__*/React.createElement(VisuallyHidden, {
139
- id: ariaDescribedById
140
- }, tooltipContent));
54
+ var LabelComponent = function LabelComponent() {
55
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
56
+ "data-testid": SyncBlockLabelDataId
57
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop
58
+ ,
59
+ className: SyncBlockLabelSharedCssClassName.labelClassName,
60
+ "aria-describedby": ariaDescribedById
61
+ }, /*#__PURE__*/React.createElement(BlockSyncedIcon, {
62
+ color: "var(--ds-icon-subtle, #505258)",
63
+ size: "small",
64
+ label: ""
65
+ }), isSource || !title ? /*#__PURE__*/React.createElement(Text, {
66
+ size: "small",
67
+ color: "color.text.subtle"
68
+ }, formatMessage(messages.syncedBlockLabel)) : /*#__PURE__*/React.createElement(Text, {
69
+ maxLines: 1,
70
+ size: "small",
71
+ color: "color.text.subtle"
72
+ }, title)), /*#__PURE__*/React.createElement(VisuallyHidden, {
73
+ id: ariaDescribedById
74
+ }, tooltipContent));
75
+ };
76
+ var LabelWithTooltip = function LabelWithTooltip() {
77
+ return /*#__PURE__*/React.createElement(Tooltip, {
78
+ position: "top",
79
+ content: fg('platform_synced_block_dogfooding') ? tooltipContent : tooltipMessage
80
+ // workaround because tooltip adds aria-describedby with a new id every time the tooltip is opened
81
+ // this causes an infinite rerender loop because of the forwardRef from the node view we are inside in bodiedSyncBlock
82
+ // tooltip content is available for screen readers in visually hidden content after the label
83
+ ,
84
+ isScreenReaderAnnouncementDisabled: true
85
+ // using this to ensure that the 'last edited' time is updated when the tooltip is opened
86
+ ,
87
+ onShow: updateTooltipContent
88
+ }, /*#__PURE__*/React.createElement(LabelComponent, null));
89
+ };
90
+ return fg('platform_synced_block_dogfooding') ? isSource ? /*#__PURE__*/React.createElement(LabelComponent, null) : /*#__PURE__*/React.createElement(LabelWithTooltip, null) : /*#__PURE__*/React.createElement(LabelWithTooltip, null);
141
91
  };
142
92
  export var SyncBlockLabel = /*#__PURE__*/React.memo(SyncBlockLabelComponent);
@@ -10,6 +10,7 @@ var SyncBlockRendererWrapperComponent = function SyncBlockRendererWrapperCompone
10
10
  localId = _ref.localId,
11
11
  api = _ref.api;
12
12
  var syncBlockFetchResult = useFetchSyncBlockData();
13
+ var title = useFetchSyncBlockTitle === null || useFetchSyncBlockTitle === void 0 ? void 0 : useFetchSyncBlockTitle();
13
14
  var contentUpdatedAt = syncBlockFetchResult === null || syncBlockFetchResult === void 0 || (_syncBlockFetchResult = syncBlockFetchResult.syncBlockInstance) === null || _syncBlockFetchResult === void 0 || (_syncBlockFetchResult = _syncBlockFetchResult.data) === null || _syncBlockFetchResult === void 0 ? void 0 : _syncBlockFetchResult.contentUpdatedAt;
14
15
  return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
15
16
  "data-testid": SyncBlockRendererWrapperDataId
@@ -21,7 +22,7 @@ var SyncBlockRendererWrapperComponent = function SyncBlockRendererWrapperCompone
21
22
  api: api
22
23
  })), /*#__PURE__*/React.createElement(SyncBlockLabel, {
23
24
  isSource: false,
24
- useFetchSyncBlockTitle: useFetchSyncBlockTitle,
25
+ title: title,
25
26
  contentUpdatedAt: contentUpdatedAt,
26
27
  localId: localId
27
28
  }));
@@ -12,6 +12,7 @@ function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol
12
12
  function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
13
13
  function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
14
14
  import { useState, useEffect } from 'react';
15
+ import { cx } from '@compiled/react';
15
16
  import DropdownMenu, { DropdownItem, DropdownItemGroup } from '@atlaskit/dropdown-menu';
16
17
  import { syncBlockMessages as messages } from '@atlaskit/editor-common/messages';
17
18
  import { FloatingToolbarButton as Button } from '@atlaskit/editor-common/ui';
@@ -37,13 +38,18 @@ var styles = {
37
38
  note: "_syaz1rpy _o5721q9c",
38
39
  lozenge: "_ahbq12x7 _1ul91wqb",
39
40
  noResultsContainer: "_1bsbo8uj _y3gn1h6o",
40
- dropdownContent: "_1rjcv77o _1bsbsmdz _1tkeqkoa _c71lko4j _1e0c1txw _1bah1h6o _4cvr1h6o",
41
+ dropdownContent: "_1rjcv77o _1bsbsmdz _c71lko4j _1e0c1txw _1bah1h6o _4cvr1h6o",
42
+ containerWithMinHeight: "_1tkeqkoa",
41
43
  contentContainer: "_y44vfmxe _1bsb1osq _1wpz1fhb _18m91wug",
42
44
  errorContainer: "_1bsbo8uj _1e0c1txw",
43
45
  errorIcon: "_1mour5cr",
44
46
  learnMoreLink: "_4bfu1r31 _1hmsglyw _ajmmnqa1",
45
47
  requestAccess: "_1bsb19n7 _o5721q9c _ahbq12x7 _syaz1rpy"
46
48
  };
49
+ var shouldApplyMinHeight = function shouldApplyMinHeight(fetchStatus, itemCount) {
50
+ // When there are 1/2 items, dropdown height is less than minHeight 144px
51
+ return !(fetchStatus === 'success' && itemCount > 0);
52
+ };
47
53
  var ItemTitle = function ItemTitle(_ref) {
48
54
  var title = _ref.title,
49
55
  formatMessage = _ref.formatMessage,
@@ -57,7 +63,7 @@ var ItemTitle = function ItemTitle(_ref) {
57
63
  }, title), onSameDocument && /*#__PURE__*/React.createElement(Box, {
58
64
  as: "span",
59
65
  xcss: styles.note
60
- }, "\xA0- ", formatMessage(productType === 'confluence-page' ? messages.syncedLocationDropdownTitleNoteForConfluencePage : messages.syncedLocationDropdownTitleNoteForJiraWorkItem)), isSource && /*#__PURE__*/React.createElement(Box, {
66
+ }, "\xA0-", ' ', formatMessage(productType === 'confluence-page' ? messages.syncedLocationDropdownTitleNoteForConfluencePage : messages.syncedLocationDropdownTitleNoteForJiraWorkItem)), isSource && /*#__PURE__*/React.createElement(Box, {
61
67
  as: "span",
62
68
  xcss: styles.lozenge
63
69
  }, /*#__PURE__*/React.createElement(Lozenge, null, formatMessage(messages.syncedLocationDropdownSourceLozenge))), !hasAccess && /*#__PURE__*/React.createElement(Box, {
@@ -284,7 +290,7 @@ var DropdownContent = function DropdownContent(_ref7) {
284
290
  }
285
291
  };
286
292
  return /*#__PURE__*/React.createElement(Box, {
287
- xcss: styles.dropdownContent
293
+ xcss: cx(styles.dropdownContent, shouldApplyMinHeight(fetchStatus, referenceData.length) && styles.containerWithMinHeight)
288
294
  }, content());
289
295
  };
290
296
  var LoadingScreen = function LoadingScreen() {
@@ -17,13 +17,13 @@ import { findSyncBlockOrBodiedSyncBlock, isBodiedSyncBlockNode } from '../pm-plu
17
17
  import { SYNCED_BLOCK_BUTTON_TEST_ID } from '../types';
18
18
  import { SyncedLocationDropdown } from './SyncedLocationDropdown';
19
19
  export var getToolbarConfig = function getToolbarConfig(state, intl, api, syncBlockStore) {
20
- var _api$decorations, _api$connectivity;
20
+ var _syncBlockInstance$er, _api$decorations, _api$connectivity;
21
21
  var syncBlockObject = findSyncBlockOrBodiedSyncBlock(state.schema, state.selection);
22
22
  if (!syncBlockObject) {
23
23
  return;
24
24
  }
25
25
  var syncBlockInstance = syncBlockStore.referenceManager.getFromCache(syncBlockObject.node.attrs.resourceId);
26
- var isUnsyncedBlock = (syncBlockInstance === null || syncBlockInstance === void 0 ? void 0 : syncBlockInstance.error) === SyncBlockError.NotFound;
26
+ var isUnsyncedBlock = (syncBlockInstance === null || syncBlockInstance === void 0 || (_syncBlockInstance$er = syncBlockInstance.error) === null || _syncBlockInstance$er === void 0 ? void 0 : _syncBlockInstance$er.type) === SyncBlockError.NotFound;
27
27
  var isErroredBlock = syncBlockInstance === null || syncBlockInstance === void 0 ? void 0 : syncBlockInstance.error;
28
28
  var bodiedSyncBlock = state.schema.nodes.bodiedSyncBlock;
29
29
  var isBodiedSyncBlock = isBodiedSyncBlockNode(syncBlockObject.node, bodiedSyncBlock);
@@ -0,0 +1,56 @@
1
+ import isYesterday from 'date-fns/isYesterday';
2
+ var SECONDS_IN_MINUTE = 60;
3
+ var SECONDS_IN_HOUR = SECONDS_IN_MINUTE * 60;
4
+ var SECONDS_IN_DAY = SECONDS_IN_HOUR * 24;
5
+ var SECONDS_IN_WEEK = SECONDS_IN_DAY * 7;
6
+ var SECONDS_IN_MONTH = SECONDS_IN_DAY * 30;
7
+ var SECONDS_IN_YEAR = SECONDS_IN_DAY * 365;
8
+ export var formatElapsedTime = function formatElapsedTime(isoDate, intl) {
9
+ var now = Date.now();
10
+ var date = new Date(isoDate).getTime();
11
+ var diffInSeconds = Math.floor((now - date) / 1000);
12
+ var dateObj = new Date(isoDate);
13
+
14
+ // Show "yesterday" when timestamp is from the previous calendar day
15
+ if (isYesterday(dateObj) && diffInSeconds >= SECONDS_IN_DAY) {
16
+ return intl.formatRelativeTime(-1, 'day', {
17
+ numeric: 'auto',
18
+ style: 'long'
19
+ });
20
+ }
21
+ if (diffInSeconds < SECONDS_IN_MINUTE) {
22
+ return intl.formatRelativeTime(-Math.max(diffInSeconds, 1), 'second', {
23
+ style: 'long'
24
+ });
25
+ } else if (diffInSeconds < SECONDS_IN_HOUR) {
26
+ var minutes = Math.floor(diffInSeconds / SECONDS_IN_MINUTE);
27
+ return intl.formatRelativeTime(-minutes, 'minute', {
28
+ style: 'long'
29
+ });
30
+ } else if (diffInSeconds < SECONDS_IN_DAY) {
31
+ var hours = Math.floor(diffInSeconds / SECONDS_IN_HOUR);
32
+ return intl.formatRelativeTime(-hours, 'hour', {
33
+ style: 'long'
34
+ });
35
+ } else if (diffInSeconds < SECONDS_IN_WEEK) {
36
+ var days = Math.floor(diffInSeconds / SECONDS_IN_DAY);
37
+ return intl.formatRelativeTime(-days, 'day', {
38
+ style: 'long'
39
+ });
40
+ } else if (diffInSeconds < SECONDS_IN_MONTH) {
41
+ var weeks = Math.floor(diffInSeconds / SECONDS_IN_WEEK);
42
+ return intl.formatRelativeTime(-weeks, 'week', {
43
+ style: 'long'
44
+ });
45
+ } else if (diffInSeconds < SECONDS_IN_YEAR) {
46
+ var months = Math.floor(diffInSeconds / SECONDS_IN_MONTH);
47
+ return intl.formatRelativeTime(-months, 'month', {
48
+ style: 'long'
49
+ });
50
+ } else {
51
+ var years = Math.floor(diffInSeconds / SECONDS_IN_YEAR);
52
+ return intl.formatRelativeTime(-years, 'year', {
53
+ style: 'long'
54
+ });
55
+ }
56
+ };
@@ -1,9 +1,9 @@
1
1
  import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
2
2
  import type { Transaction } from '@atlaskit/editor-prosemirror/state';
3
- import type { SyncBlockStoreManager } from '@atlaskit/editor-synced-block-provider';
3
+ import type { DeletionReason, SyncBlockStoreManager } from '@atlaskit/editor-synced-block-provider';
4
4
  import type { SyncedBlockPlugin } from '../../syncedBlockPluginType';
5
5
  import { type SyncBlockInfo } from '../../types';
6
6
  export type ConfirmationTransactionRef = {
7
7
  current: Transaction | undefined;
8
8
  };
9
- export declare const handleBodiedSyncBlockRemoval: (tr: Transaction, bodiedSyncBlockRemoved: SyncBlockInfo[], syncBlockStore: SyncBlockStoreManager, api: ExtractInjectionAPI<SyncedBlockPlugin> | undefined, confirmationTransactionRef: ConfirmationTransactionRef) => boolean;
9
+ export declare const handleBodiedSyncBlockRemoval: (bodiedSyncBlockRemoved: SyncBlockInfo[], syncBlockStore: SyncBlockStoreManager, api: ExtractInjectionAPI<SyncedBlockPlugin> | undefined, confirmationTransactionRef: ConfirmationTransactionRef, deletionReason: DeletionReason | undefined) => boolean;
@@ -1,11 +1,9 @@
1
1
  import React from 'react';
2
- import { type IntlShape } from 'react-intl-next';
3
- export declare const formatElapsedTime: (isoDate: string, intl: IntlShape) => string;
4
2
  type SyncBlockLabelProps = {
5
3
  contentUpdatedAt?: string;
6
4
  isSource: boolean;
7
5
  localId: string;
8
- useFetchSyncBlockTitle?: () => string | undefined;
6
+ title?: string;
9
7
  };
10
- export declare const SyncBlockLabel: React.MemoExoticComponent<({ isSource, useFetchSyncBlockTitle, localId, contentUpdatedAt, }: SyncBlockLabelProps) => React.JSX.Element>;
8
+ export declare const SyncBlockLabel: React.MemoExoticComponent<({ contentUpdatedAt, isSource, localId, title, }: SyncBlockLabelProps) => React.JSX.Element>;
11
9
  export {};
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
3
- import type { UseFetchSyncBlockDataResult } from '@atlaskit/editor-synced-block-provider';
3
+ import { type UseFetchSyncBlockDataResult } from '@atlaskit/editor-synced-block-provider';
4
4
  import type { SyncedBlockPlugin, SyncedBlockRendererProps } from '../syncedBlockPluginType';
5
5
  type Props = {
6
6
  api?: ExtractInjectionAPI<SyncedBlockPlugin>;
@@ -0,0 +1,2 @@
1
+ import { type IntlShape } from 'react-intl-next';
2
+ export declare const formatElapsedTime: (isoDate: string, intl: IntlShape) => string;
@@ -1,9 +1,9 @@
1
1
  import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
2
2
  import type { Transaction } from '@atlaskit/editor-prosemirror/state';
3
- import type { SyncBlockStoreManager } from '@atlaskit/editor-synced-block-provider';
3
+ import type { DeletionReason, SyncBlockStoreManager } from '@atlaskit/editor-synced-block-provider';
4
4
  import type { SyncedBlockPlugin } from '../../syncedBlockPluginType';
5
5
  import { type SyncBlockInfo } from '../../types';
6
6
  export type ConfirmationTransactionRef = {
7
7
  current: Transaction | undefined;
8
8
  };
9
- export declare const handleBodiedSyncBlockRemoval: (tr: Transaction, bodiedSyncBlockRemoved: SyncBlockInfo[], syncBlockStore: SyncBlockStoreManager, api: ExtractInjectionAPI<SyncedBlockPlugin> | undefined, confirmationTransactionRef: ConfirmationTransactionRef) => boolean;
9
+ export declare const handleBodiedSyncBlockRemoval: (bodiedSyncBlockRemoved: SyncBlockInfo[], syncBlockStore: SyncBlockStoreManager, api: ExtractInjectionAPI<SyncedBlockPlugin> | undefined, confirmationTransactionRef: ConfirmationTransactionRef, deletionReason: DeletionReason | undefined) => boolean;
@@ -1,11 +1,9 @@
1
1
  import React from 'react';
2
- import { type IntlShape } from 'react-intl-next';
3
- export declare const formatElapsedTime: (isoDate: string, intl: IntlShape) => string;
4
2
  type SyncBlockLabelProps = {
5
3
  contentUpdatedAt?: string;
6
4
  isSource: boolean;
7
5
  localId: string;
8
- useFetchSyncBlockTitle?: () => string | undefined;
6
+ title?: string;
9
7
  };
10
- export declare const SyncBlockLabel: React.MemoExoticComponent<({ isSource, useFetchSyncBlockTitle, localId, contentUpdatedAt, }: SyncBlockLabelProps) => React.JSX.Element>;
8
+ export declare const SyncBlockLabel: React.MemoExoticComponent<({ contentUpdatedAt, isSource, localId, title, }: SyncBlockLabelProps) => React.JSX.Element>;
11
9
  export {};
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
3
- import type { UseFetchSyncBlockDataResult } from '@atlaskit/editor-synced-block-provider';
3
+ import { type UseFetchSyncBlockDataResult } from '@atlaskit/editor-synced-block-provider';
4
4
  import type { SyncedBlockPlugin, SyncedBlockRendererProps } from '../syncedBlockPluginType';
5
5
  type Props = {
6
6
  api?: ExtractInjectionAPI<SyncedBlockPlugin>;
@@ -0,0 +1,2 @@
1
+ import { type IntlShape } from 'react-intl-next';
2
+ export declare const formatElapsedTime: (isoDate: string, intl: IntlShape) => string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-synced-block",
3
- "version": "5.3.1",
3
+ "version": "5.3.2",
4
4
  "description": "SyncedBlock plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -40,7 +40,7 @@
40
40
  "@atlaskit/editor-plugin-selection": "^7.0.0",
41
41
  "@atlaskit/editor-prosemirror": "^7.2.0",
42
42
  "@atlaskit/editor-shared-styles": "^3.10.0",
43
- "@atlaskit/editor-synced-block-provider": "^3.13.0",
43
+ "@atlaskit/editor-synced-block-provider": "^3.14.0",
44
44
  "@atlaskit/editor-tables": "^2.9.0",
45
45
  "@atlaskit/editor-toolbar": "^0.19.0",
46
46
  "@atlaskit/flag": "^17.8.0",
@@ -52,7 +52,7 @@
52
52
  "@atlaskit/platform-feature-flags": "^1.1.0",
53
53
  "@atlaskit/primitives": "^17.1.0",
54
54
  "@atlaskit/spinner": "19.0.9",
55
- "@atlaskit/tmp-editor-statsig": "^16.30.0",
55
+ "@atlaskit/tmp-editor-statsig": "^16.31.0",
56
56
  "@atlaskit/tokens": "10.1.0",
57
57
  "@atlaskit/tooltip": "^20.14.0",
58
58
  "@atlaskit/visually-hidden": "^3.0.0",