@atlaskit/editor-plugin-synced-block 10.2.9 → 10.2.11

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 CHANGED
@@ -1,5 +1,28 @@
1
1
  # @atlaskit/editor-plugin-synced-block
2
2
 
3
+ ## 10.2.11
4
+
5
+ ### Patch Changes
6
+
7
+ - [`a3bbfab896310`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/a3bbfab896310) -
8
+ Replace feature gate `confluence_frontend_native_tabs_extension` with experiment
9
+ `confluence_native_tabs_experiment` using `expValEquals` from
10
+ `@atlaskit/tmp-editor-statsig/exp-val-equals`. Usage:
11
+ `expValEquals('confluence_native_tabs_experiment', 'isEnabled', true)`.
12
+ - Updated dependencies
13
+
14
+ ## 10.2.10
15
+
16
+ ### Patch Changes
17
+
18
+ - [`abfc496602dcb`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/abfc496602dcb) -
19
+ [ux] Fix the "when the page is published" link in the unpublished synced block reference error
20
+ card. Links rendered inside the reference sync block's contentEditable island did not navigate on
21
+ click (the browser placed the caret instead); anchor navigation is now re-triggered on click, and
22
+ interactive elements show the pointer cursor rather than the text cursor. Both behaviours are
23
+ gated behind the `platform_editor_sync_block_activation` experiment.
24
+ - Updated dependencies
25
+
3
26
  ## 10.2.9
4
27
 
5
28
  ### Patch Changes
@@ -11,7 +11,7 @@ var _selection = require("@atlaskit/editor-common/selection");
11
11
  var _model = require("@atlaskit/editor-prosemirror/model");
12
12
  var _transform = require("@atlaskit/editor-prosemirror/transform");
13
13
  var _utils = require("@atlaskit/editor-prosemirror/utils");
14
- var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
14
+ var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
15
15
  /**
16
16
  * Defers a callback to the next microtask (when gated) or next macrotask via setTimeout(0).
17
17
  * Used to avoid re-entrant ProseMirror dispatch cycles.
@@ -33,7 +33,7 @@ var isBodiedSyncBlockNode = exports.isBodiedSyncBlockNode = function isBodiedSyn
33
33
  return node.type === bodiedSyncBlock;
34
34
  };
35
35
  var getUnsupportedNodeTypes = exports.getUnsupportedNodeTypes = (0, _memoizeOne.default)(function () {
36
- return new Set(['inlineExtension', 'extension', 'bodiedExtension', 'syncBlock', 'bodiedSyncBlock'].concat((0, _toConsumableArray2.default)((0, _platformFeatureFlags.fg)('confluence_frontend_native_tabs_extension') ? ['multiBodiedExtension'] : [])));
36
+ return new Set(['inlineExtension', 'extension', 'bodiedExtension', 'syncBlock', 'bodiedSyncBlock'].concat((0, _toConsumableArray2.default)((0, _expValEquals.expValEquals)('confluence_native_tabs_experiment', 'isEnabled', true) ? ['multiBodiedExtension'] : [])));
37
37
  });
38
38
 
39
39
  /**
@@ -6,9 +6,11 @@ Object.defineProperty(exports, "__esModule", {
6
6
  });
7
7
  exports.SyncBlockRendererWrapper = void 0;
8
8
  var _react = _interopRequireWildcard(require("react"));
9
+ var _bindEventListener = require("bind-event-listener");
9
10
  var _syncBlock = require("@atlaskit/editor-common/sync-block");
10
11
  var _editorSyncedBlockProvider = require("@atlaskit/editor-synced-block-provider");
11
12
  var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
13
+ var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
12
14
  var _SyncBlockLabel = require("./SyncBlockLabel");
13
15
  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); }
14
16
  var SyncBlockRendererWrapperDataId = 'sync-block-plugin-renderer-wrapper';
@@ -27,6 +29,10 @@ var SyncBlockRendererWrapperComponent = function SyncBlockRendererWrapperCompone
27
29
  var isUnsyncedBlock = isUnpublishedBlock || (syncBlockFetchResult === null || syncBlockFetchResult === void 0 || (_syncBlockFetchResult3 = syncBlockFetchResult.syncBlockInstance) === null || _syncBlockFetchResult3 === void 0 || (_syncBlockFetchResult3 = _syncBlockFetchResult3.error) === null || _syncBlockFetchResult3 === void 0 ? void 0 : _syncBlockFetchResult3.type) === _editorSyncedBlockProvider.SyncBlockError.NotFound;
28
30
  var isTextSelectionEnabled = (0, _platformFeatureFlags.fg)('platform_synced_block_patch_14');
29
31
 
32
+ // Evaluated unconditionally so the experiment exposure is tracked correctly
33
+ // (recorded on every render, not lazily on first click).
34
+ var isSyncBlockActivationEnabled = (0, _expValEquals.expValEquals)('platform_editor_sync_block_activation', 'isEnabled', true);
35
+
30
36
  // Prevent editing in the contentEditable renderer wrapper. We set
31
37
  // contentEditable="true" to enable text selection (creating an editable
32
38
  // island inside ProseMirror's contentEditable="false" nodeview wrapper),
@@ -34,7 +40,39 @@ var SyncBlockRendererWrapperComponent = function SyncBlockRendererWrapperCompone
34
40
  var preventInput = (0, _react.useCallback)(function (e) {
35
41
  e.preventDefault();
36
42
  }, []);
43
+
44
+ // Browsers suppress link navigation on a plain click inside a
45
+ // contentEditable region (they place the caret instead), which breaks links
46
+ // rendered in the content — e.g. the "when the page is published" link in
47
+ // the unpublished error card. Re-trigger navigation for _blank anchors
48
+ // ourselves. A native listener (rather than an onClick on the div) is used
49
+ // so we delegate link clicks without making the container itself interactive.
50
+ var rendererRef = (0, _react.useRef)(null);
51
+ (0, _react.useEffect)(function () {
52
+ var containerEl = rendererRef.current;
53
+ if (!containerEl || !isTextSelectionEnabled || !isSyncBlockActivationEnabled) {
54
+ return;
55
+ }
56
+ var unbind = (0, _bindEventListener.bind)(containerEl, {
57
+ type: 'click',
58
+ listener: function listener(e) {
59
+ // Let the browser handle modified/non-primary clicks (open-in-new-tab,
60
+ // etc.) natively so we don't open a second tab on top of it.
61
+ if (e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) {
62
+ return;
63
+ }
64
+ var target = e.target instanceof Element ? e.target : null;
65
+ var anchor = target === null || target === void 0 ? void 0 : target.closest('a[href]');
66
+ if (!(anchor instanceof HTMLAnchorElement) || e.defaultPrevented || anchor.target !== '_blank') {
67
+ return;
68
+ }
69
+ window.open(anchor.href, '_blank', 'noopener,noreferrer');
70
+ }
71
+ });
72
+ return unbind;
73
+ }, [isTextSelectionEnabled, isSyncBlockActivationEnabled]);
37
74
  return /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement("div", {
75
+ ref: rendererRef,
38
76
  "data-testid": SyncBlockRendererWrapperDataId
39
77
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop
40
78
  ,
@@ -3,7 +3,7 @@ import { expandSelectionToBlockRange } from '@atlaskit/editor-common/selection';
3
3
  import { Fragment } from '@atlaskit/editor-prosemirror/model';
4
4
  import { ReplaceAroundStep, ReplaceStep } from '@atlaskit/editor-prosemirror/transform';
5
5
  import { findParentNodeOfType, findParentNodeOfTypeClosestToPos, findSelectedNodeOfType } from '@atlaskit/editor-prosemirror/utils';
6
- import { fg } from '@atlaskit/platform-feature-flags';
6
+ import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
7
7
 
8
8
  /**
9
9
  * Defers a callback to the next microtask (when gated) or next macrotask via setTimeout(0).
@@ -25,7 +25,7 @@ export const findSyncBlockOrBodiedSyncBlock = (schema, selection) => {
25
25
  return findSyncBlock(schema, selection) || findBodiedSyncBlock(schema, selection);
26
26
  };
27
27
  export const isBodiedSyncBlockNode = (node, bodiedSyncBlock) => node.type === bodiedSyncBlock;
28
- export const getUnsupportedNodeTypes = memoizeOne(() => new Set(['inlineExtension', 'extension', 'bodiedExtension', 'syncBlock', 'bodiedSyncBlock', ...(fg('confluence_frontend_native_tabs_extension') ? ['multiBodiedExtension'] : [])]));
28
+ export const getUnsupportedNodeTypes = memoizeOne(() => new Set(['inlineExtension', 'extension', 'bodiedExtension', 'syncBlock', 'bodiedSyncBlock', ...(expValEquals('confluence_native_tabs_experiment', 'isEnabled', true) ? ['multiBodiedExtension'] : [])]));
29
29
 
30
30
  /**
31
31
  * Checks whether the selection can be converted to sync block
@@ -1,7 +1,9 @@
1
- import React, { useCallback } from 'react';
1
+ import React, { useCallback, useEffect, useRef } from 'react';
2
+ import { bind } from 'bind-event-listener';
2
3
  import { SyncBlockSharedCssClassName } from '@atlaskit/editor-common/sync-block';
3
4
  import { SyncBlockError, useFetchSyncBlockData, useFetchSyncBlockTitle } from '@atlaskit/editor-synced-block-provider';
4
5
  import { fg } from '@atlaskit/platform-feature-flags';
6
+ import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
5
7
  import { SyncBlockLabel } from './SyncBlockLabel';
6
8
  const SyncBlockRendererWrapperDataId = 'sync-block-plugin-renderer-wrapper';
7
9
  const SyncBlockRendererWrapperComponent = ({
@@ -20,6 +22,10 @@ const SyncBlockRendererWrapperComponent = ({
20
22
  const isUnsyncedBlock = isUnpublishedBlock || (syncBlockFetchResult === null || syncBlockFetchResult === void 0 ? void 0 : (_syncBlockFetchResult5 = syncBlockFetchResult.syncBlockInstance) === null || _syncBlockFetchResult5 === void 0 ? void 0 : (_syncBlockFetchResult6 = _syncBlockFetchResult5.error) === null || _syncBlockFetchResult6 === void 0 ? void 0 : _syncBlockFetchResult6.type) === SyncBlockError.NotFound;
21
23
  const isTextSelectionEnabled = fg('platform_synced_block_patch_14');
22
24
 
25
+ // Evaluated unconditionally so the experiment exposure is tracked correctly
26
+ // (recorded on every render, not lazily on first click).
27
+ const isSyncBlockActivationEnabled = expValEquals('platform_editor_sync_block_activation', 'isEnabled', true);
28
+
23
29
  // Prevent editing in the contentEditable renderer wrapper. We set
24
30
  // contentEditable="true" to enable text selection (creating an editable
25
31
  // island inside ProseMirror's contentEditable="false" nodeview wrapper),
@@ -27,7 +33,39 @@ const SyncBlockRendererWrapperComponent = ({
27
33
  const preventInput = useCallback(e => {
28
34
  e.preventDefault();
29
35
  }, []);
36
+
37
+ // Browsers suppress link navigation on a plain click inside a
38
+ // contentEditable region (they place the caret instead), which breaks links
39
+ // rendered in the content — e.g. the "when the page is published" link in
40
+ // the unpublished error card. Re-trigger navigation for _blank anchors
41
+ // ourselves. A native listener (rather than an onClick on the div) is used
42
+ // so we delegate link clicks without making the container itself interactive.
43
+ const rendererRef = useRef(null);
44
+ useEffect(() => {
45
+ const containerEl = rendererRef.current;
46
+ if (!containerEl || !isTextSelectionEnabled || !isSyncBlockActivationEnabled) {
47
+ return;
48
+ }
49
+ const unbind = bind(containerEl, {
50
+ type: 'click',
51
+ listener: e => {
52
+ // Let the browser handle modified/non-primary clicks (open-in-new-tab,
53
+ // etc.) natively so we don't open a second tab on top of it.
54
+ if (e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) {
55
+ return;
56
+ }
57
+ const target = e.target instanceof Element ? e.target : null;
58
+ const anchor = target === null || target === void 0 ? void 0 : target.closest('a[href]');
59
+ if (!(anchor instanceof HTMLAnchorElement) || e.defaultPrevented || anchor.target !== '_blank') {
60
+ return;
61
+ }
62
+ window.open(anchor.href, '_blank', 'noopener,noreferrer');
63
+ }
64
+ });
65
+ return unbind;
66
+ }, [isTextSelectionEnabled, isSyncBlockActivationEnabled]);
30
67
  return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
68
+ ref: rendererRef,
31
69
  "data-testid": SyncBlockRendererWrapperDataId
32
70
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop
33
71
  ,
@@ -4,7 +4,7 @@ import { expandSelectionToBlockRange } from '@atlaskit/editor-common/selection';
4
4
  import { Fragment } from '@atlaskit/editor-prosemirror/model';
5
5
  import { ReplaceAroundStep, ReplaceStep } from '@atlaskit/editor-prosemirror/transform';
6
6
  import { findParentNodeOfType, findParentNodeOfTypeClosestToPos, findSelectedNodeOfType } from '@atlaskit/editor-prosemirror/utils';
7
- import { fg } from '@atlaskit/platform-feature-flags';
7
+ import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
8
8
 
9
9
  /**
10
10
  * Defers a callback to the next microtask (when gated) or next macrotask via setTimeout(0).
@@ -27,7 +27,7 @@ export var isBodiedSyncBlockNode = function isBodiedSyncBlockNode(node, bodiedSy
27
27
  return node.type === bodiedSyncBlock;
28
28
  };
29
29
  export var getUnsupportedNodeTypes = memoizeOne(function () {
30
- return new Set(['inlineExtension', 'extension', 'bodiedExtension', 'syncBlock', 'bodiedSyncBlock'].concat(_toConsumableArray(fg('confluence_frontend_native_tabs_extension') ? ['multiBodiedExtension'] : [])));
30
+ return new Set(['inlineExtension', 'extension', 'bodiedExtension', 'syncBlock', 'bodiedSyncBlock'].concat(_toConsumableArray(expValEquals('confluence_native_tabs_experiment', 'isEnabled', true) ? ['multiBodiedExtension'] : [])));
31
31
  });
32
32
 
33
33
  /**
@@ -1,7 +1,9 @@
1
- import React, { useCallback } from 'react';
1
+ import React, { useCallback, useEffect, useRef } from 'react';
2
+ import { bind } from 'bind-event-listener';
2
3
  import { SyncBlockSharedCssClassName } from '@atlaskit/editor-common/sync-block';
3
4
  import { SyncBlockError, useFetchSyncBlockData, useFetchSyncBlockTitle } from '@atlaskit/editor-synced-block-provider';
4
5
  import { fg } from '@atlaskit/platform-feature-flags';
6
+ import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
5
7
  import { SyncBlockLabel } from './SyncBlockLabel';
6
8
  var SyncBlockRendererWrapperDataId = 'sync-block-plugin-renderer-wrapper';
7
9
  var SyncBlockRendererWrapperComponent = function SyncBlockRendererWrapperComponent(_ref) {
@@ -19,6 +21,10 @@ var SyncBlockRendererWrapperComponent = function SyncBlockRendererWrapperCompone
19
21
  var isUnsyncedBlock = isUnpublishedBlock || (syncBlockFetchResult === null || syncBlockFetchResult === void 0 || (_syncBlockFetchResult3 = syncBlockFetchResult.syncBlockInstance) === null || _syncBlockFetchResult3 === void 0 || (_syncBlockFetchResult3 = _syncBlockFetchResult3.error) === null || _syncBlockFetchResult3 === void 0 ? void 0 : _syncBlockFetchResult3.type) === SyncBlockError.NotFound;
20
22
  var isTextSelectionEnabled = fg('platform_synced_block_patch_14');
21
23
 
24
+ // Evaluated unconditionally so the experiment exposure is tracked correctly
25
+ // (recorded on every render, not lazily on first click).
26
+ var isSyncBlockActivationEnabled = expValEquals('platform_editor_sync_block_activation', 'isEnabled', true);
27
+
22
28
  // Prevent editing in the contentEditable renderer wrapper. We set
23
29
  // contentEditable="true" to enable text selection (creating an editable
24
30
  // island inside ProseMirror's contentEditable="false" nodeview wrapper),
@@ -26,7 +32,39 @@ var SyncBlockRendererWrapperComponent = function SyncBlockRendererWrapperCompone
26
32
  var preventInput = useCallback(function (e) {
27
33
  e.preventDefault();
28
34
  }, []);
35
+
36
+ // Browsers suppress link navigation on a plain click inside a
37
+ // contentEditable region (they place the caret instead), which breaks links
38
+ // rendered in the content — e.g. the "when the page is published" link in
39
+ // the unpublished error card. Re-trigger navigation for _blank anchors
40
+ // ourselves. A native listener (rather than an onClick on the div) is used
41
+ // so we delegate link clicks without making the container itself interactive.
42
+ var rendererRef = useRef(null);
43
+ useEffect(function () {
44
+ var containerEl = rendererRef.current;
45
+ if (!containerEl || !isTextSelectionEnabled || !isSyncBlockActivationEnabled) {
46
+ return;
47
+ }
48
+ var unbind = bind(containerEl, {
49
+ type: 'click',
50
+ listener: function listener(e) {
51
+ // Let the browser handle modified/non-primary clicks (open-in-new-tab,
52
+ // etc.) natively so we don't open a second tab on top of it.
53
+ if (e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) {
54
+ return;
55
+ }
56
+ var target = e.target instanceof Element ? e.target : null;
57
+ var anchor = target === null || target === void 0 ? void 0 : target.closest('a[href]');
58
+ if (!(anchor instanceof HTMLAnchorElement) || e.defaultPrevented || anchor.target !== '_blank') {
59
+ return;
60
+ }
61
+ window.open(anchor.href, '_blank', 'noopener,noreferrer');
62
+ }
63
+ });
64
+ return unbind;
65
+ }, [isTextSelectionEnabled, isSyncBlockActivationEnabled]);
29
66
  return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
67
+ ref: rendererRef,
30
68
  "data-testid": SyncBlockRendererWrapperDataId
31
69
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop
32
70
  ,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-synced-block",
3
- "version": "10.2.9",
3
+ "version": "10.2.11",
4
4
  "description": "SyncedBlock plugin for @atlaskit/editor-core",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -21,8 +21,8 @@
21
21
  "atlaskit:src": "src/index.ts",
22
22
  "dependencies": {
23
23
  "@atlaskit/adf-schema": "^56.1.0",
24
- "@atlaskit/button": "24.3.2",
25
- "@atlaskit/dropdown-menu": "17.1.3",
24
+ "@atlaskit/button": "24.3.3",
25
+ "@atlaskit/dropdown-menu": "17.1.4",
26
26
  "@atlaskit/editor-json-transformer": "^9.0.0",
27
27
  "@atlaskit/editor-plugin-analytics": "^12.0.0",
28
28
  "@atlaskit/editor-plugin-block-menu": "^11.1.0",
@@ -37,16 +37,16 @@
37
37
  "@atlaskit/editor-shared-styles": "^4.0.0",
38
38
  "@atlaskit/editor-synced-block-provider": "^8.6.0",
39
39
  "@atlaskit/editor-toolbar": "^2.2.0",
40
- "@atlaskit/flag": "^18.1.0",
40
+ "@atlaskit/flag": "^18.2.0",
41
41
  "@atlaskit/icon": "37.0.0",
42
42
  "@atlaskit/icon-lab": "^7.3.0",
43
43
  "@atlaskit/logo": "^21.4.0",
44
44
  "@atlaskit/lozenge": "^14.1.0",
45
45
  "@atlaskit/modal-dialog": "^16.1.0",
46
46
  "@atlaskit/platform-feature-flags": "^2.0.0",
47
- "@atlaskit/primitives": "^20.6.0",
47
+ "@atlaskit/primitives": "^21.0.0",
48
48
  "@atlaskit/spinner": "20.1.0",
49
- "@atlaskit/tmp-editor-statsig": "^125.0.0",
49
+ "@atlaskit/tmp-editor-statsig": "^125.2.0",
50
50
  "@atlaskit/tokens": "15.8.0",
51
51
  "@atlaskit/tooltip": "^23.1.0",
52
52
  "@atlaskit/visually-hidden": "^4.1.0",
@@ -103,9 +103,6 @@
103
103
  }
104
104
  },
105
105
  "platform-feature-flags": {
106
- "confluence_frontend_native_tabs_extension": {
107
- "type": "boolean"
108
- },
109
106
  "confluence_fronend_labels_categorization_migration": {
110
107
  "type": "boolean"
111
108
  },