@atlaskit/editor-plugin-synced-block 5.3.0 → 5.3.1
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.
- package/CHANGELOG.md +8 -0
- package/dist/cjs/ui/SyncBlockLabel.js +103 -9
- package/dist/cjs/ui/SyncBlockRendererWrapper.js +6 -2
- package/dist/es2019/ui/SyncBlockLabel.js +96 -7
- package/dist/es2019/ui/SyncBlockRendererWrapper.js +6 -2
- package/dist/esm/ui/SyncBlockLabel.js +100 -8
- package/dist/esm/ui/SyncBlockRendererWrapper.js +6 -2
- package/dist/types/syncedBlockPluginType.d.ts +1 -1
- package/dist/types/ui/SyncBlockLabel.d.ts +4 -1
- package/dist/types/ui/SyncBlockRendererWrapper.d.ts +1 -1
- package/dist/types-ts4.5/syncedBlockPluginType.d.ts +1 -1
- package/dist/types-ts4.5/ui/SyncBlockLabel.d.ts +4 -1
- package/dist/types-ts4.5/ui/SyncBlockRendererWrapper.d.ts +1 -1
- package/package.json +5 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# @atlaskit/editor-plugin-synced-block
|
|
2
2
|
|
|
3
|
+
## 5.3.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`87abc5dda86fe`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/87abc5dda86fe) -
|
|
8
|
+
[ux] Show last edited time in sync block tooltip
|
|
9
|
+
- Updated dependencies
|
|
10
|
+
|
|
3
11
|
## 5.3.0
|
|
4
12
|
|
|
5
13
|
### Minor Changes
|
|
@@ -1,38 +1,132 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
var _typeof = require("@babel/runtime/helpers/typeof");
|
|
4
5
|
Object.defineProperty(exports, "__esModule", {
|
|
5
6
|
value: true
|
|
6
7
|
});
|
|
7
|
-
exports.SyncBlockLabel = void 0;
|
|
8
|
-
var
|
|
8
|
+
exports.formatElapsedTime = exports.SyncBlockLabel = void 0;
|
|
9
|
+
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
|
|
10
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
11
|
+
var _isYesterday = _interopRequireDefault(require("date-fns/isYesterday"));
|
|
9
12
|
var _reactIntlNext = require("react-intl-next");
|
|
10
13
|
var _messages = require("@atlaskit/editor-common/messages");
|
|
11
14
|
var _syncBlock = require("@atlaskit/editor-common/sync-block");
|
|
12
15
|
var _blockSynced = _interopRequireDefault(require("@atlaskit/icon-lab/core/block-synced"));
|
|
16
|
+
var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
|
|
13
17
|
var _compiled = require("@atlaskit/primitives/compiled");
|
|
14
18
|
var _tooltip = _interopRequireDefault(require("@atlaskit/tooltip"));
|
|
15
19
|
var _visuallyHidden = _interopRequireDefault(require("@atlaskit/visually-hidden"));
|
|
20
|
+
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
|
|
16
21
|
var SyncBlockLabelDataId = 'sync-block-label';
|
|
22
|
+
var SECONDS_IN_MINUTE = 60;
|
|
23
|
+
var SECONDS_IN_HOUR = SECONDS_IN_MINUTE * 60;
|
|
24
|
+
var SECONDS_IN_DAY = SECONDS_IN_HOUR * 24;
|
|
25
|
+
var SECONDS_IN_WEEK = SECONDS_IN_DAY * 7;
|
|
26
|
+
var SECONDS_IN_MONTH = SECONDS_IN_DAY * 30;
|
|
27
|
+
var SECONDS_IN_YEAR = SECONDS_IN_DAY * 365;
|
|
28
|
+
var formatElapsedTime = exports.formatElapsedTime = function formatElapsedTime(isoDate, intl) {
|
|
29
|
+
var now = Date.now();
|
|
30
|
+
var date = new Date(isoDate).getTime();
|
|
31
|
+
var diffInSeconds = Math.floor((now - date) / 1000);
|
|
32
|
+
var dateObj = new Date(isoDate);
|
|
33
|
+
|
|
34
|
+
// Show "yesterday" when timestamp is from the previous calendar day
|
|
35
|
+
if ((0, _isYesterday.default)(dateObj) && diffInSeconds >= SECONDS_IN_DAY) {
|
|
36
|
+
return intl.formatRelativeTime(-1, 'day', {
|
|
37
|
+
numeric: 'auto',
|
|
38
|
+
style: 'long'
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
if (diffInSeconds < SECONDS_IN_MINUTE) {
|
|
42
|
+
return intl.formatRelativeTime(-Math.max(diffInSeconds, 1), 'second', {
|
|
43
|
+
style: 'long'
|
|
44
|
+
});
|
|
45
|
+
} else if (diffInSeconds < SECONDS_IN_HOUR) {
|
|
46
|
+
var minutes = Math.floor(diffInSeconds / SECONDS_IN_MINUTE);
|
|
47
|
+
return intl.formatRelativeTime(-minutes, 'minute', {
|
|
48
|
+
style: 'long'
|
|
49
|
+
});
|
|
50
|
+
} else if (diffInSeconds < SECONDS_IN_DAY) {
|
|
51
|
+
var hours = Math.floor(diffInSeconds / SECONDS_IN_HOUR);
|
|
52
|
+
return intl.formatRelativeTime(-hours, 'hour', {
|
|
53
|
+
style: 'long'
|
|
54
|
+
});
|
|
55
|
+
} else if (diffInSeconds < SECONDS_IN_WEEK) {
|
|
56
|
+
var days = Math.floor(diffInSeconds / SECONDS_IN_DAY);
|
|
57
|
+
return intl.formatRelativeTime(-days, 'day', {
|
|
58
|
+
style: 'long'
|
|
59
|
+
});
|
|
60
|
+
} else if (diffInSeconds < SECONDS_IN_MONTH) {
|
|
61
|
+
var weeks = Math.floor(diffInSeconds / SECONDS_IN_WEEK);
|
|
62
|
+
return intl.formatRelativeTime(-weeks, 'week', {
|
|
63
|
+
style: 'long'
|
|
64
|
+
});
|
|
65
|
+
} else if (diffInSeconds < SECONDS_IN_YEAR) {
|
|
66
|
+
var months = Math.floor(diffInSeconds / SECONDS_IN_MONTH);
|
|
67
|
+
return intl.formatRelativeTime(-months, 'month', {
|
|
68
|
+
style: 'long'
|
|
69
|
+
});
|
|
70
|
+
} else {
|
|
71
|
+
var years = Math.floor(diffInSeconds / SECONDS_IN_YEAR);
|
|
72
|
+
return intl.formatRelativeTime(-years, 'year', {
|
|
73
|
+
style: 'long'
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
};
|
|
17
77
|
var SyncBlockLabelComponent = function SyncBlockLabelComponent(_ref) {
|
|
18
78
|
var isSource = _ref.isSource,
|
|
19
79
|
useFetchSyncBlockTitle = _ref.useFetchSyncBlockTitle,
|
|
20
|
-
localId = _ref.localId
|
|
21
|
-
|
|
22
|
-
|
|
80
|
+
localId = _ref.localId,
|
|
81
|
+
contentUpdatedAt = _ref.contentUpdatedAt;
|
|
82
|
+
var intl = (0, _reactIntlNext.useIntl)();
|
|
83
|
+
var formatMessage = intl.formatMessage;
|
|
23
84
|
var title = useFetchSyncBlockTitle === null || useFetchSyncBlockTitle === void 0 ? void 0 : useFetchSyncBlockTitle();
|
|
24
|
-
var
|
|
25
|
-
|
|
26
|
-
|
|
85
|
+
var _useState = (0, _react.useState)(formatMessage(_messages.syncBlockMessages.defaultSyncBlockTooltip)),
|
|
86
|
+
_useState2 = (0, _slicedToArray2.default)(_useState, 2),
|
|
87
|
+
tooltipContent = _useState2[0],
|
|
88
|
+
setTooltipContent = _useState2[1];
|
|
89
|
+
var tooltipMessage = formatMessage(_messages.syncBlockMessages.defaultSyncBlockTooltip);
|
|
90
|
+
if (isSource) {
|
|
91
|
+
tooltipMessage = formatMessage(_messages.syncBlockMessages.sourceSyncBlockTooltip);
|
|
92
|
+
} else if (title) {
|
|
93
|
+
tooltipMessage = formatMessage(_messages.syncBlockMessages.referenceSyncBlockTooltip, {
|
|
94
|
+
title: title
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
var updateTooltipContent = (0, _react.useCallback)(function () {
|
|
98
|
+
if (!(0, _platformFeatureFlags.fg)('platform_synced_block_dogfooding')) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
var tooltipContent = tooltipMessage;
|
|
102
|
+
if (contentUpdatedAt) {
|
|
103
|
+
var elapsedTime = formatElapsedTime(contentUpdatedAt, intl);
|
|
104
|
+
tooltipContent = /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement(_compiled.Text, {
|
|
105
|
+
size: "small",
|
|
106
|
+
color: "color.text.inverse"
|
|
107
|
+
}, tooltipMessage), /*#__PURE__*/_react.default.createElement("br", null), /*#__PURE__*/_react.default.createElement("br", null), /*#__PURE__*/_react.default.createElement(_compiled.Text, {
|
|
108
|
+
size: "small",
|
|
109
|
+
color: "color.text.inverse",
|
|
110
|
+
weight: "bold"
|
|
111
|
+
}, formatMessage(_messages.syncBlockMessages.referenceSyncBlockLastEdited)), /*#__PURE__*/_react.default.createElement(_compiled.Text, {
|
|
112
|
+
size: "small",
|
|
113
|
+
color: "color.text.inverse"
|
|
114
|
+
}, elapsedTime));
|
|
115
|
+
}
|
|
116
|
+
setTooltipContent(tooltipContent);
|
|
117
|
+
}, [contentUpdatedAt, formatMessage, intl, tooltipMessage]);
|
|
27
118
|
var ariaDescribedById = "sync-block-label-description-".concat(localId);
|
|
28
119
|
return /*#__PURE__*/_react.default.createElement(_tooltip.default, {
|
|
29
120
|
position: "top",
|
|
30
|
-
content: tooltipContent
|
|
121
|
+
content: (0, _platformFeatureFlags.fg)('platform_synced_block_dogfooding') ? tooltipContent : tooltipMessage
|
|
31
122
|
// workaround because tooltip adds aria-describedby with a new id every time the tooltip is opened
|
|
32
123
|
// this causes an infinite rerender loop because of the forwardRef from the node view we are inside in bodiedSyncBlock
|
|
33
124
|
// tooltip content is available for screen readers in visually hidden content after the label
|
|
34
125
|
,
|
|
35
126
|
isScreenReaderAnnouncementDisabled: true
|
|
127
|
+
// using this to ensure that the 'last edited' time is updated when the tooltip is opened
|
|
128
|
+
,
|
|
129
|
+
onShow: updateTooltipContent
|
|
36
130
|
}, /*#__PURE__*/_react.default.createElement("div", {
|
|
37
131
|
"data-testid": SyncBlockLabelDataId
|
|
38
132
|
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop
|
|
@@ -10,22 +10,26 @@ var _syncBlock = require("@atlaskit/editor-common/sync-block");
|
|
|
10
10
|
var _SyncBlockLabel = require("./SyncBlockLabel");
|
|
11
11
|
var SyncBlockRendererWrapperDataId = 'sync-block-plugin-renderer-wrapper';
|
|
12
12
|
var SyncBlockRendererWrapperComponent = function SyncBlockRendererWrapperComponent(_ref) {
|
|
13
|
+
var _syncBlockFetchResult;
|
|
13
14
|
var syncedBlockRenderer = _ref.syncedBlockRenderer,
|
|
14
15
|
useFetchSyncBlockData = _ref.useFetchSyncBlockData,
|
|
15
|
-
localId = _ref.localId,
|
|
16
16
|
useFetchSyncBlockTitle = _ref.useFetchSyncBlockTitle,
|
|
17
|
+
localId = _ref.localId,
|
|
17
18
|
api = _ref.api;
|
|
19
|
+
var syncBlockFetchResult = useFetchSyncBlockData();
|
|
20
|
+
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;
|
|
18
21
|
return /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement("div", {
|
|
19
22
|
"data-testid": SyncBlockRendererWrapperDataId
|
|
20
23
|
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop
|
|
21
24
|
,
|
|
22
25
|
className: _syncBlock.SyncBlockSharedCssClassName.renderer
|
|
23
26
|
}, syncedBlockRenderer({
|
|
24
|
-
|
|
27
|
+
syncBlockFetchResult: syncBlockFetchResult,
|
|
25
28
|
api: api
|
|
26
29
|
})), /*#__PURE__*/_react.default.createElement(_SyncBlockLabel.SyncBlockLabel, {
|
|
27
30
|
isSource: false,
|
|
28
31
|
useFetchSyncBlockTitle: useFetchSyncBlockTitle,
|
|
32
|
+
contentUpdatedAt: contentUpdatedAt,
|
|
29
33
|
localId: localId
|
|
30
34
|
}));
|
|
31
35
|
};
|
|
@@ -1,33 +1,122 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { useCallback, useState } from 'react';
|
|
2
|
+
import isYesterday from 'date-fns/isYesterday';
|
|
2
3
|
import { useIntl } from 'react-intl-next';
|
|
3
4
|
import { syncBlockMessages as messages } from '@atlaskit/editor-common/messages';
|
|
4
5
|
import { SyncBlockLabelSharedCssClassName } from '@atlaskit/editor-common/sync-block';
|
|
5
6
|
import BlockSyncedIcon from '@atlaskit/icon-lab/core/block-synced';
|
|
7
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
6
8
|
import { Text } from '@atlaskit/primitives/compiled';
|
|
7
9
|
import Tooltip from '@atlaskit/tooltip';
|
|
8
10
|
import VisuallyHidden from '@atlaskit/visually-hidden';
|
|
9
11
|
const SyncBlockLabelDataId = 'sync-block-label';
|
|
12
|
+
const SECONDS_IN_MINUTE = 60;
|
|
13
|
+
const SECONDS_IN_HOUR = SECONDS_IN_MINUTE * 60;
|
|
14
|
+
const SECONDS_IN_DAY = SECONDS_IN_HOUR * 24;
|
|
15
|
+
const SECONDS_IN_WEEK = SECONDS_IN_DAY * 7;
|
|
16
|
+
const SECONDS_IN_MONTH = SECONDS_IN_DAY * 30;
|
|
17
|
+
const SECONDS_IN_YEAR = SECONDS_IN_DAY * 365;
|
|
18
|
+
export const formatElapsedTime = (isoDate, intl) => {
|
|
19
|
+
const now = Date.now();
|
|
20
|
+
const date = new Date(isoDate).getTime();
|
|
21
|
+
const diffInSeconds = Math.floor((now - date) / 1000);
|
|
22
|
+
const dateObj = new Date(isoDate);
|
|
23
|
+
|
|
24
|
+
// Show "yesterday" when timestamp is from the previous calendar day
|
|
25
|
+
if (isYesterday(dateObj) && diffInSeconds >= SECONDS_IN_DAY) {
|
|
26
|
+
return intl.formatRelativeTime(-1, 'day', {
|
|
27
|
+
numeric: 'auto',
|
|
28
|
+
style: 'long'
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
if (diffInSeconds < SECONDS_IN_MINUTE) {
|
|
32
|
+
return intl.formatRelativeTime(-Math.max(diffInSeconds, 1), 'second', {
|
|
33
|
+
style: 'long'
|
|
34
|
+
});
|
|
35
|
+
} else if (diffInSeconds < SECONDS_IN_HOUR) {
|
|
36
|
+
const minutes = Math.floor(diffInSeconds / SECONDS_IN_MINUTE);
|
|
37
|
+
return intl.formatRelativeTime(-minutes, 'minute', {
|
|
38
|
+
style: 'long'
|
|
39
|
+
});
|
|
40
|
+
} else if (diffInSeconds < SECONDS_IN_DAY) {
|
|
41
|
+
const hours = Math.floor(diffInSeconds / SECONDS_IN_HOUR);
|
|
42
|
+
return intl.formatRelativeTime(-hours, 'hour', {
|
|
43
|
+
style: 'long'
|
|
44
|
+
});
|
|
45
|
+
} else if (diffInSeconds < SECONDS_IN_WEEK) {
|
|
46
|
+
const days = Math.floor(diffInSeconds / SECONDS_IN_DAY);
|
|
47
|
+
return intl.formatRelativeTime(-days, 'day', {
|
|
48
|
+
style: 'long'
|
|
49
|
+
});
|
|
50
|
+
} else if (diffInSeconds < SECONDS_IN_MONTH) {
|
|
51
|
+
const weeks = Math.floor(diffInSeconds / SECONDS_IN_WEEK);
|
|
52
|
+
return intl.formatRelativeTime(-weeks, 'week', {
|
|
53
|
+
style: 'long'
|
|
54
|
+
});
|
|
55
|
+
} else if (diffInSeconds < SECONDS_IN_YEAR) {
|
|
56
|
+
const months = Math.floor(diffInSeconds / SECONDS_IN_MONTH);
|
|
57
|
+
return intl.formatRelativeTime(-months, 'month', {
|
|
58
|
+
style: 'long'
|
|
59
|
+
});
|
|
60
|
+
} else {
|
|
61
|
+
const years = Math.floor(diffInSeconds / SECONDS_IN_YEAR);
|
|
62
|
+
return intl.formatRelativeTime(-years, 'year', {
|
|
63
|
+
style: 'long'
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
};
|
|
10
67
|
const SyncBlockLabelComponent = ({
|
|
11
68
|
isSource,
|
|
12
69
|
useFetchSyncBlockTitle,
|
|
13
|
-
localId
|
|
70
|
+
localId,
|
|
71
|
+
contentUpdatedAt
|
|
14
72
|
}) => {
|
|
73
|
+
const intl = useIntl();
|
|
15
74
|
const {
|
|
16
75
|
formatMessage
|
|
17
|
-
} =
|
|
76
|
+
} = intl;
|
|
18
77
|
const title = useFetchSyncBlockTitle === null || useFetchSyncBlockTitle === void 0 ? void 0 : useFetchSyncBlockTitle();
|
|
19
|
-
const tooltipContent =
|
|
20
|
-
|
|
21
|
-
|
|
78
|
+
const [tooltipContent, setTooltipContent] = useState(formatMessage(messages.defaultSyncBlockTooltip));
|
|
79
|
+
let tooltipMessage = formatMessage(messages.defaultSyncBlockTooltip);
|
|
80
|
+
if (isSource) {
|
|
81
|
+
tooltipMessage = formatMessage(messages.sourceSyncBlockTooltip);
|
|
82
|
+
} else if (title) {
|
|
83
|
+
tooltipMessage = formatMessage(messages.referenceSyncBlockTooltip, {
|
|
84
|
+
title
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
const updateTooltipContent = useCallback(() => {
|
|
88
|
+
if (!fg('platform_synced_block_dogfooding')) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
let tooltipContent = tooltipMessage;
|
|
92
|
+
if (contentUpdatedAt) {
|
|
93
|
+
const elapsedTime = formatElapsedTime(contentUpdatedAt, intl);
|
|
94
|
+
tooltipContent = /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Text, {
|
|
95
|
+
size: "small",
|
|
96
|
+
color: "color.text.inverse"
|
|
97
|
+
}, tooltipMessage), /*#__PURE__*/React.createElement("br", null), /*#__PURE__*/React.createElement("br", null), /*#__PURE__*/React.createElement(Text, {
|
|
98
|
+
size: "small",
|
|
99
|
+
color: "color.text.inverse",
|
|
100
|
+
weight: "bold"
|
|
101
|
+
}, formatMessage(messages.referenceSyncBlockLastEdited)), /*#__PURE__*/React.createElement(Text, {
|
|
102
|
+
size: "small",
|
|
103
|
+
color: "color.text.inverse"
|
|
104
|
+
}, elapsedTime));
|
|
105
|
+
}
|
|
106
|
+
setTooltipContent(tooltipContent);
|
|
107
|
+
}, [contentUpdatedAt, formatMessage, intl, tooltipMessage]);
|
|
22
108
|
const ariaDescribedById = `sync-block-label-description-${localId}`;
|
|
23
109
|
return /*#__PURE__*/React.createElement(Tooltip, {
|
|
24
110
|
position: "top",
|
|
25
|
-
content: tooltipContent
|
|
111
|
+
content: fg('platform_synced_block_dogfooding') ? tooltipContent : tooltipMessage
|
|
26
112
|
// workaround because tooltip adds aria-describedby with a new id every time the tooltip is opened
|
|
27
113
|
// this causes an infinite rerender loop because of the forwardRef from the node view we are inside in bodiedSyncBlock
|
|
28
114
|
// tooltip content is available for screen readers in visually hidden content after the label
|
|
29
115
|
,
|
|
30
116
|
isScreenReaderAnnouncementDisabled: true
|
|
117
|
+
// using this to ensure that the 'last edited' time is updated when the tooltip is opened
|
|
118
|
+
,
|
|
119
|
+
onShow: updateTooltipContent
|
|
31
120
|
}, /*#__PURE__*/React.createElement("div", {
|
|
32
121
|
"data-testid": SyncBlockLabelDataId
|
|
33
122
|
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop
|
|
@@ -5,21 +5,25 @@ const SyncBlockRendererWrapperDataId = 'sync-block-plugin-renderer-wrapper';
|
|
|
5
5
|
const SyncBlockRendererWrapperComponent = ({
|
|
6
6
|
syncedBlockRenderer,
|
|
7
7
|
useFetchSyncBlockData,
|
|
8
|
-
localId,
|
|
9
8
|
useFetchSyncBlockTitle,
|
|
9
|
+
localId,
|
|
10
10
|
api
|
|
11
11
|
}) => {
|
|
12
|
+
var _syncBlockFetchResult, _syncBlockFetchResult2;
|
|
13
|
+
const syncBlockFetchResult = useFetchSyncBlockData();
|
|
14
|
+
const contentUpdatedAt = syncBlockFetchResult === null || syncBlockFetchResult === void 0 ? void 0 : (_syncBlockFetchResult = syncBlockFetchResult.syncBlockInstance) === null || _syncBlockFetchResult === void 0 ? void 0 : (_syncBlockFetchResult2 = _syncBlockFetchResult.data) === null || _syncBlockFetchResult2 === void 0 ? void 0 : _syncBlockFetchResult2.contentUpdatedAt;
|
|
12
15
|
return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
|
|
13
16
|
"data-testid": SyncBlockRendererWrapperDataId
|
|
14
17
|
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop
|
|
15
18
|
,
|
|
16
19
|
className: SyncBlockSharedCssClassName.renderer
|
|
17
20
|
}, syncedBlockRenderer({
|
|
18
|
-
|
|
21
|
+
syncBlockFetchResult,
|
|
19
22
|
api
|
|
20
23
|
})), /*#__PURE__*/React.createElement(SyncBlockLabel, {
|
|
21
24
|
isSource: false,
|
|
22
25
|
useFetchSyncBlockTitle: useFetchSyncBlockTitle,
|
|
26
|
+
contentUpdatedAt: contentUpdatedAt,
|
|
23
27
|
localId: localId
|
|
24
28
|
}));
|
|
25
29
|
};
|
|
@@ -1,31 +1,123 @@
|
|
|
1
|
-
import
|
|
1
|
+
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
2
|
+
import React, { useCallback, useState } from 'react';
|
|
3
|
+
import isYesterday from 'date-fns/isYesterday';
|
|
2
4
|
import { useIntl } from 'react-intl-next';
|
|
3
5
|
import { syncBlockMessages as messages } from '@atlaskit/editor-common/messages';
|
|
4
6
|
import { SyncBlockLabelSharedCssClassName } from '@atlaskit/editor-common/sync-block';
|
|
5
7
|
import BlockSyncedIcon from '@atlaskit/icon-lab/core/block-synced';
|
|
8
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
6
9
|
import { Text } from '@atlaskit/primitives/compiled';
|
|
7
10
|
import Tooltip from '@atlaskit/tooltip';
|
|
8
11
|
import VisuallyHidden from '@atlaskit/visually-hidden';
|
|
9
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
|
+
};
|
|
10
68
|
var SyncBlockLabelComponent = function SyncBlockLabelComponent(_ref) {
|
|
11
69
|
var isSource = _ref.isSource,
|
|
12
70
|
useFetchSyncBlockTitle = _ref.useFetchSyncBlockTitle,
|
|
13
|
-
localId = _ref.localId
|
|
14
|
-
|
|
15
|
-
|
|
71
|
+
localId = _ref.localId,
|
|
72
|
+
contentUpdatedAt = _ref.contentUpdatedAt;
|
|
73
|
+
var intl = useIntl();
|
|
74
|
+
var formatMessage = intl.formatMessage;
|
|
16
75
|
var title = useFetchSyncBlockTitle === null || useFetchSyncBlockTitle === void 0 ? void 0 : useFetchSyncBlockTitle();
|
|
17
|
-
var
|
|
18
|
-
|
|
19
|
-
|
|
76
|
+
var _useState = useState(formatMessage(messages.defaultSyncBlockTooltip)),
|
|
77
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
78
|
+
tooltipContent = _useState2[0],
|
|
79
|
+
setTooltipContent = _useState2[1];
|
|
80
|
+
var tooltipMessage = formatMessage(messages.defaultSyncBlockTooltip);
|
|
81
|
+
if (isSource) {
|
|
82
|
+
tooltipMessage = formatMessage(messages.sourceSyncBlockTooltip);
|
|
83
|
+
} else if (title) {
|
|
84
|
+
tooltipMessage = formatMessage(messages.referenceSyncBlockTooltip, {
|
|
85
|
+
title: title
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
var updateTooltipContent = useCallback(function () {
|
|
89
|
+
if (!fg('platform_synced_block_dogfooding')) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
var tooltipContent = tooltipMessage;
|
|
93
|
+
if (contentUpdatedAt) {
|
|
94
|
+
var elapsedTime = formatElapsedTime(contentUpdatedAt, intl);
|
|
95
|
+
tooltipContent = /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Text, {
|
|
96
|
+
size: "small",
|
|
97
|
+
color: "color.text.inverse"
|
|
98
|
+
}, tooltipMessage), /*#__PURE__*/React.createElement("br", null), /*#__PURE__*/React.createElement("br", null), /*#__PURE__*/React.createElement(Text, {
|
|
99
|
+
size: "small",
|
|
100
|
+
color: "color.text.inverse",
|
|
101
|
+
weight: "bold"
|
|
102
|
+
}, formatMessage(messages.referenceSyncBlockLastEdited)), /*#__PURE__*/React.createElement(Text, {
|
|
103
|
+
size: "small",
|
|
104
|
+
color: "color.text.inverse"
|
|
105
|
+
}, elapsedTime));
|
|
106
|
+
}
|
|
107
|
+
setTooltipContent(tooltipContent);
|
|
108
|
+
}, [contentUpdatedAt, formatMessage, intl, tooltipMessage]);
|
|
20
109
|
var ariaDescribedById = "sync-block-label-description-".concat(localId);
|
|
21
110
|
return /*#__PURE__*/React.createElement(Tooltip, {
|
|
22
111
|
position: "top",
|
|
23
|
-
content: tooltipContent
|
|
112
|
+
content: fg('platform_synced_block_dogfooding') ? tooltipContent : tooltipMessage
|
|
24
113
|
// workaround because tooltip adds aria-describedby with a new id every time the tooltip is opened
|
|
25
114
|
// this causes an infinite rerender loop because of the forwardRef from the node view we are inside in bodiedSyncBlock
|
|
26
115
|
// tooltip content is available for screen readers in visually hidden content after the label
|
|
27
116
|
,
|
|
28
117
|
isScreenReaderAnnouncementDisabled: true
|
|
118
|
+
// using this to ensure that the 'last edited' time is updated when the tooltip is opened
|
|
119
|
+
,
|
|
120
|
+
onShow: updateTooltipContent
|
|
29
121
|
}, /*#__PURE__*/React.createElement("div", {
|
|
30
122
|
"data-testid": SyncBlockLabelDataId
|
|
31
123
|
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop
|
|
@@ -3,22 +3,26 @@ import { SyncBlockSharedCssClassName } from '@atlaskit/editor-common/sync-block'
|
|
|
3
3
|
import { SyncBlockLabel } from './SyncBlockLabel';
|
|
4
4
|
var SyncBlockRendererWrapperDataId = 'sync-block-plugin-renderer-wrapper';
|
|
5
5
|
var SyncBlockRendererWrapperComponent = function SyncBlockRendererWrapperComponent(_ref) {
|
|
6
|
+
var _syncBlockFetchResult;
|
|
6
7
|
var syncedBlockRenderer = _ref.syncedBlockRenderer,
|
|
7
8
|
useFetchSyncBlockData = _ref.useFetchSyncBlockData,
|
|
8
|
-
localId = _ref.localId,
|
|
9
9
|
useFetchSyncBlockTitle = _ref.useFetchSyncBlockTitle,
|
|
10
|
+
localId = _ref.localId,
|
|
10
11
|
api = _ref.api;
|
|
12
|
+
var syncBlockFetchResult = useFetchSyncBlockData();
|
|
13
|
+
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;
|
|
11
14
|
return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
|
|
12
15
|
"data-testid": SyncBlockRendererWrapperDataId
|
|
13
16
|
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop
|
|
14
17
|
,
|
|
15
18
|
className: SyncBlockSharedCssClassName.renderer
|
|
16
19
|
}, syncedBlockRenderer({
|
|
17
|
-
|
|
20
|
+
syncBlockFetchResult: syncBlockFetchResult,
|
|
18
21
|
api: api
|
|
19
22
|
})), /*#__PURE__*/React.createElement(SyncBlockLabel, {
|
|
20
23
|
isSource: false,
|
|
21
24
|
useFetchSyncBlockTitle: useFetchSyncBlockTitle,
|
|
25
|
+
contentUpdatedAt: contentUpdatedAt,
|
|
22
26
|
localId: localId
|
|
23
27
|
}));
|
|
24
28
|
};
|
|
@@ -37,7 +37,7 @@ export type SyncedBlockEditorProps = {
|
|
|
37
37
|
};
|
|
38
38
|
export type SyncedBlockRendererProps = {
|
|
39
39
|
api?: ExtractInjectionAPI<SyncedBlockPlugin>;
|
|
40
|
-
|
|
40
|
+
syncBlockFetchResult: UseFetchSyncBlockDataResult;
|
|
41
41
|
};
|
|
42
42
|
export interface SyncedBlockPluginOptions extends LongPressSelectionPluginOptions {
|
|
43
43
|
enableSourceCreation?: boolean;
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { type IntlShape } from 'react-intl-next';
|
|
3
|
+
export declare const formatElapsedTime: (isoDate: string, intl: IntlShape) => string;
|
|
2
4
|
type SyncBlockLabelProps = {
|
|
5
|
+
contentUpdatedAt?: string;
|
|
3
6
|
isSource: boolean;
|
|
4
7
|
localId: string;
|
|
5
8
|
useFetchSyncBlockTitle?: () => string | undefined;
|
|
6
9
|
};
|
|
7
|
-
export declare const SyncBlockLabel: React.MemoExoticComponent<({ isSource, useFetchSyncBlockTitle, localId, }: SyncBlockLabelProps) => React.JSX.Element>;
|
|
10
|
+
export declare const SyncBlockLabel: React.MemoExoticComponent<({ isSource, useFetchSyncBlockTitle, localId, contentUpdatedAt, }: SyncBlockLabelProps) => React.JSX.Element>;
|
|
8
11
|
export {};
|
|
@@ -9,5 +9,5 @@ type Props = {
|
|
|
9
9
|
useFetchSyncBlockData: () => UseFetchSyncBlockDataResult;
|
|
10
10
|
useFetchSyncBlockTitle: () => string | undefined;
|
|
11
11
|
};
|
|
12
|
-
export declare const SyncBlockRendererWrapper: React.MemoExoticComponent<({ syncedBlockRenderer, useFetchSyncBlockData,
|
|
12
|
+
export declare const SyncBlockRendererWrapper: React.MemoExoticComponent<({ syncedBlockRenderer, useFetchSyncBlockData, useFetchSyncBlockTitle, localId, api, }: Props) => React.JSX.Element>;
|
|
13
13
|
export {};
|
|
@@ -37,7 +37,7 @@ export type SyncedBlockEditorProps = {
|
|
|
37
37
|
};
|
|
38
38
|
export type SyncedBlockRendererProps = {
|
|
39
39
|
api?: ExtractInjectionAPI<SyncedBlockPlugin>;
|
|
40
|
-
|
|
40
|
+
syncBlockFetchResult: UseFetchSyncBlockDataResult;
|
|
41
41
|
};
|
|
42
42
|
export interface SyncedBlockPluginOptions extends LongPressSelectionPluginOptions {
|
|
43
43
|
enableSourceCreation?: boolean;
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { type IntlShape } from 'react-intl-next';
|
|
3
|
+
export declare const formatElapsedTime: (isoDate: string, intl: IntlShape) => string;
|
|
2
4
|
type SyncBlockLabelProps = {
|
|
5
|
+
contentUpdatedAt?: string;
|
|
3
6
|
isSource: boolean;
|
|
4
7
|
localId: string;
|
|
5
8
|
useFetchSyncBlockTitle?: () => string | undefined;
|
|
6
9
|
};
|
|
7
|
-
export declare const SyncBlockLabel: React.MemoExoticComponent<({ isSource, useFetchSyncBlockTitle, localId, }: SyncBlockLabelProps) => React.JSX.Element>;
|
|
10
|
+
export declare const SyncBlockLabel: React.MemoExoticComponent<({ isSource, useFetchSyncBlockTitle, localId, contentUpdatedAt, }: SyncBlockLabelProps) => React.JSX.Element>;
|
|
8
11
|
export {};
|
|
@@ -9,5 +9,5 @@ type Props = {
|
|
|
9
9
|
useFetchSyncBlockData: () => UseFetchSyncBlockDataResult;
|
|
10
10
|
useFetchSyncBlockTitle: () => string | undefined;
|
|
11
11
|
};
|
|
12
|
-
export declare const SyncBlockRendererWrapper: React.MemoExoticComponent<({ syncedBlockRenderer, useFetchSyncBlockData,
|
|
12
|
+
export declare const SyncBlockRendererWrapper: React.MemoExoticComponent<({ syncedBlockRenderer, useFetchSyncBlockData, useFetchSyncBlockTitle, localId, api, }: Props) => React.JSX.Element>;
|
|
13
13
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/editor-plugin-synced-block",
|
|
3
|
-
"version": "5.3.
|
|
3
|
+
"version": "5.3.1",
|
|
4
4
|
"description": "SyncedBlock plugin for @atlaskit/editor-core",
|
|
5
5
|
"author": "Atlassian Pty Ltd",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"atlaskit:src": "src/index.ts",
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@atlaskit/adf-schema": "^51.5.0",
|
|
32
|
-
"@atlaskit/button": "23.9.
|
|
33
|
-
"@atlaskit/dropdown-menu": "16.4.
|
|
32
|
+
"@atlaskit/button": "23.9.5",
|
|
33
|
+
"@atlaskit/dropdown-menu": "16.4.3",
|
|
34
34
|
"@atlaskit/editor-json-transformer": "^8.31.0",
|
|
35
35
|
"@atlaskit/editor-plugin-analytics": "^7.0.0",
|
|
36
36
|
"@atlaskit/editor-plugin-block-menu": "^6.0.0",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"@atlaskit/editor-tables": "^2.9.0",
|
|
45
45
|
"@atlaskit/editor-toolbar": "^0.19.0",
|
|
46
46
|
"@atlaskit/flag": "^17.8.0",
|
|
47
|
-
"@atlaskit/icon": "
|
|
47
|
+
"@atlaskit/icon": "30.0.0",
|
|
48
48
|
"@atlaskit/icon-lab": "^5.14.0",
|
|
49
49
|
"@atlaskit/logo": "^19.10.0",
|
|
50
50
|
"@atlaskit/lozenge": "^13.3.0",
|
|
@@ -59,6 +59,7 @@
|
|
|
59
59
|
"@babel/runtime": "^7.0.0",
|
|
60
60
|
"@compiled/react": "^0.18.6",
|
|
61
61
|
"bind-event-listener": "^3.0.0",
|
|
62
|
+
"date-fns": "^2.17.0",
|
|
62
63
|
"react-intl-next": "npm:react-intl@^5.18.1"
|
|
63
64
|
},
|
|
64
65
|
"peerDependencies": {
|