@atlaskit/editor-plugin-insert-block 8.7.2 → 8.7.3
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 +6 -0
- package/dist/cjs/pm-plugins/experiences/toolbar-action-experiences.js +24 -16
- package/dist/cjs/pm-plugins/experiences/toolbar-experience-utils.js +133 -187
- package/dist/es2019/pm-plugins/experiences/toolbar-action-experiences.js +25 -18
- package/dist/es2019/pm-plugins/experiences/toolbar-experience-utils.js +75 -91
- package/dist/esm/pm-plugins/experiences/toolbar-action-experiences.js +25 -17
- package/dist/esm/pm-plugins/experiences/toolbar-experience-utils.js +133 -186
- package/dist/types/pm-plugins/experiences/toolbar-experience-utils.d.ts +26 -13
- package/dist/types-ts4.5/pm-plugins/experiences/toolbar-experience-utils.d.ts +26 -13
- package/package.json +5 -5
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
2
|
import { getDocument } from '@atlaskit/browser-apis';
|
|
3
3
|
import { EXPERIENCE_FAILURE_REASON, popupWithNestedElement } from '@atlaskit/editor-common/experiences';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Popup check type determines how popups are observed based on their DOM location:
|
|
7
|
+
* - 'inline': Popups appearing in toolbar button-groups (emoji, media, table selector, image)
|
|
8
|
+
* - 'editorRoot': Popups attached to editor root (e.g., mention popups)
|
|
9
|
+
* - 'editorContent': Content-level popups or modals in portal containers (e.g., block menu)
|
|
10
|
+
*/
|
|
11
|
+
|
|
4
12
|
/**
|
|
5
13
|
* DOM marker selectors for node types inserted via toolbar actions.
|
|
6
14
|
* Matches outermost wrapper elements set synchronously by ReactNodeView
|
|
@@ -21,42 +29,71 @@ export const isToolbarButtonClick = (target, testId) => {
|
|
|
21
29
|
}
|
|
22
30
|
return !button.disabled && button.getAttribute('aria-disabled') !== 'true';
|
|
23
31
|
};
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* ExperienceCheck that observes popup mount point and all its
|
|
27
|
-
* `[data-editor-popup]` children with `{ childList: true }` (no subtree).
|
|
28
|
-
*
|
|
29
|
-
* Detects when a popup containing the given nested element is added to the
|
|
30
|
-
* DOM — either as a new `[data-editor-popup]` direct child, or as content
|
|
31
|
-
* rendered inside an existing `[data-editor-popup]` wrapper.
|
|
32
|
-
*/
|
|
33
|
-
export const TYPEAHEAD_DECORATION_SELECTOR = '[data-type-ahead="typeaheadDecoration"]';
|
|
34
|
-
export const handleTypeAheadOpenDomMutation = ({
|
|
35
|
-
mutations
|
|
36
|
-
}) => {
|
|
37
|
-
for (const mutation of mutations) {
|
|
38
|
-
if (mutation.type !== 'childList') {
|
|
39
|
-
continue;
|
|
40
|
-
}
|
|
41
|
-
for (const node of mutation.addedNodes) {
|
|
42
|
-
if (!(node instanceof HTMLElement)) {
|
|
43
|
-
continue;
|
|
44
|
-
}
|
|
45
|
-
if (node.matches(TYPEAHEAD_DECORATION_SELECTOR) || node.querySelector(TYPEAHEAD_DECORATION_SELECTOR)) {
|
|
46
|
-
return {
|
|
47
|
-
status: 'success'
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
return undefined;
|
|
53
|
-
};
|
|
54
32
|
export class ExperienceCheckPopupMutation {
|
|
55
|
-
constructor(nestedElementQuery, getTarget, getEditorDom) {
|
|
33
|
+
constructor(nestedElementQuery, getTarget, getEditorDom, type = 'editorRoot') {
|
|
56
34
|
_defineProperty(this, "observers", []);
|
|
57
35
|
this.nestedElementQuery = nestedElementQuery;
|
|
58
36
|
this.getTarget = getTarget;
|
|
59
37
|
this.getEditorDom = getEditorDom;
|
|
38
|
+
this.type = type;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Returns the list of DOM elements to observe based on popup type.
|
|
43
|
+
*/
|
|
44
|
+
getObserveTargets() {
|
|
45
|
+
switch (this.type) {
|
|
46
|
+
case 'inline':
|
|
47
|
+
return this.getInlineTargets();
|
|
48
|
+
case 'editorRoot':
|
|
49
|
+
return this.getEditorRootTargets();
|
|
50
|
+
}
|
|
51
|
+
// Should never reach here - all types handled above
|
|
52
|
+
return [];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* For 'inline' type: observe only the button-group container.
|
|
57
|
+
* The target passed in should be the button-group (or button within it) from getInlinePopupTarget().
|
|
58
|
+
* Inline popups appear as direct children of button-group elements.
|
|
59
|
+
*/
|
|
60
|
+
getInlineTargets() {
|
|
61
|
+
const target = this.getTarget();
|
|
62
|
+
if (!target) {
|
|
63
|
+
return [];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Walk up to find the button-group container
|
|
67
|
+
const buttonGroup = target.closest('[data-toolbar-component="button-group"]');
|
|
68
|
+
|
|
69
|
+
// Target is already the button-group or button from getInlinePopupTarget()
|
|
70
|
+
// Just observe this single element
|
|
71
|
+
return buttonGroup ? [buttonGroup, target] : [target];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* For 'editorRoot' type: observe the actual editor root container.
|
|
76
|
+
* The editorDom is the ProseMirror element, but popups appear as direct children
|
|
77
|
+
* of the parent .akEditor container. So we observe the parent of editorDom.
|
|
78
|
+
* No portal observation needed.
|
|
79
|
+
*/
|
|
80
|
+
getEditorRootTargets() {
|
|
81
|
+
const targets = [];
|
|
82
|
+
const editorDom = this.getEditorDom();
|
|
83
|
+
if (editorDom) {
|
|
84
|
+
// Find the actual editor root (.akEditor) by walking up the DOM
|
|
85
|
+
const editorRoot = editorDom.closest('.akEditor') || editorDom.parentElement;
|
|
86
|
+
if (editorRoot instanceof HTMLElement) {
|
|
87
|
+
targets.push(editorRoot);
|
|
88
|
+
|
|
89
|
+
// Observe existing [data-editor-popup] wrappers
|
|
90
|
+
const wrappers = editorRoot.querySelectorAll('[data-editor-popup]');
|
|
91
|
+
for (const wrapper of wrappers) {
|
|
92
|
+
targets.push(wrapper);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return targets;
|
|
60
97
|
}
|
|
61
98
|
start(callback) {
|
|
62
99
|
this.stop();
|
|
@@ -86,7 +123,8 @@ export class ExperienceCheckPopupMutation {
|
|
|
86
123
|
if (!(node instanceof HTMLElement)) {
|
|
87
124
|
continue;
|
|
88
125
|
}
|
|
89
|
-
|
|
126
|
+
const found = popupWithNestedElement(node, query) || node.matches(query) || !!node.querySelector(query);
|
|
127
|
+
if (found) {
|
|
90
128
|
this.stop();
|
|
91
129
|
callback({
|
|
92
130
|
status: 'success'
|
|
@@ -103,66 +141,12 @@ export class ExperienceCheckPopupMutation {
|
|
|
103
141
|
});
|
|
104
142
|
this.observers.push(observer);
|
|
105
143
|
};
|
|
106
|
-
observe(target);
|
|
107
|
-
for (const wrapper of target.querySelectorAll('[data-editor-popup]')) {
|
|
108
|
-
observe(wrapper);
|
|
109
|
-
}
|
|
110
|
-
const portalContainer = doc.querySelector('.atlaskit-portal-container');
|
|
111
|
-
if (portalContainer instanceof HTMLElement) {
|
|
112
|
-
const observePortal = portal => {
|
|
113
|
-
observe(portal);
|
|
114
|
-
for (const child of portal.children) {
|
|
115
|
-
if (child instanceof HTMLElement) {
|
|
116
|
-
observe(child);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
};
|
|
120
|
-
const containerObserver = new MutationObserver(mutations => {
|
|
121
|
-
for (const mutation of mutations) {
|
|
122
|
-
if (mutation.type !== 'childList') {
|
|
123
|
-
continue;
|
|
124
|
-
}
|
|
125
|
-
for (const node of mutation.addedNodes) {
|
|
126
|
-
if (node instanceof HTMLElement) {
|
|
127
|
-
observePortal(node);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
onMutation(mutations);
|
|
132
|
-
});
|
|
133
|
-
containerObserver.observe(portalContainer, {
|
|
134
|
-
childList: true
|
|
135
|
-
});
|
|
136
|
-
this.observers.push(containerObserver);
|
|
137
|
-
for (const portal of portalContainer.querySelectorAll('.atlaskit-portal')) {
|
|
138
|
-
observePortal(portal);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
const editorDom = this.getEditorDom();
|
|
142
|
-
if (editorDom !== null && editorDom !== void 0 && editorDom.parentElement) {
|
|
143
|
-
observe(editorDom.parentElement);
|
|
144
|
-
}
|
|
145
144
|
|
|
146
|
-
//
|
|
147
|
-
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
callback({
|
|
152
|
-
status: 'success'
|
|
153
|
-
});
|
|
154
|
-
return;
|
|
155
|
-
}
|
|
156
|
-
requestAnimationFrame(() => {
|
|
157
|
-
if (doc.querySelector(query)) {
|
|
158
|
-
this.stop();
|
|
159
|
-
callback({
|
|
160
|
-
status: 'success'
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
|
-
});
|
|
164
|
-
};
|
|
165
|
-
requestAnimationFrame(checkDom);
|
|
145
|
+
// Get type-specific targets and observe them
|
|
146
|
+
const observeTargets = this.getObserveTargets();
|
|
147
|
+
for (const observeTarget of observeTargets) {
|
|
148
|
+
observe(observeTarget);
|
|
149
|
+
}
|
|
166
150
|
}
|
|
167
151
|
stop() {
|
|
168
152
|
for (const observer of this.observers) {
|
|
@@ -4,7 +4,7 @@ import { Experience, EXPERIENCE_ID, ExperienceCheckDomMutation, ExperienceCheckT
|
|
|
4
4
|
import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
|
|
5
5
|
import { TOOLBAR_BUTTON_TEST_ID } from '@atlaskit/editor-common/toolbar';
|
|
6
6
|
import { PluginKey } from '@atlaskit/editor-prosemirror/state';
|
|
7
|
-
import { ExperienceCheckPopupMutation, getParentDOMAtSelection, handleEditorNodeInsertDomMutation,
|
|
7
|
+
import { ExperienceCheckPopupMutation, getParentDOMAtSelection, handleEditorNodeInsertDomMutation, isToolbarButtonClick } from './toolbar-experience-utils';
|
|
8
8
|
var pluginKey = new PluginKey('toolbarActionExperiences');
|
|
9
9
|
var TIMEOUT_DURATION = 1000;
|
|
10
10
|
var PRIMARY_TOOLBAR = 'primaryToolbar';
|
|
@@ -17,6 +17,7 @@ export var getToolbarActionExperiencesPlugin = function getToolbarActionExperien
|
|
|
17
17
|
dispatchAnalyticsEvent = _ref.dispatchAnalyticsEvent;
|
|
18
18
|
var editorView;
|
|
19
19
|
var popupTargetEl;
|
|
20
|
+
var lastClickedToolbarButton;
|
|
20
21
|
var getPopupsTarget = function getPopupsTarget() {
|
|
21
22
|
if (!popupTargetEl) {
|
|
22
23
|
var _editorView;
|
|
@@ -31,6 +32,17 @@ export var getToolbarActionExperiencesPlugin = function getToolbarActionExperien
|
|
|
31
32
|
}
|
|
32
33
|
return null;
|
|
33
34
|
};
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* For inline popups, returns the button-group ancestor of the clicked toolbar button.
|
|
38
|
+
* This allows inline popup checks to observe only the relevant button-group.
|
|
39
|
+
*/
|
|
40
|
+
var getInlinePopupTarget = function getInlinePopupTarget() {
|
|
41
|
+
if (!lastClickedToolbarButton) {
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
return lastClickedToolbarButton;
|
|
45
|
+
};
|
|
34
46
|
var narrowParentObserveConfig = function narrowParentObserveConfig() {
|
|
35
47
|
var _getParentDOMAtSelect;
|
|
36
48
|
return {
|
|
@@ -65,45 +77,39 @@ export var getToolbarActionExperiencesPlugin = function getToolbarActionExperien
|
|
|
65
77
|
});
|
|
66
78
|
};
|
|
67
79
|
var createPopupExperience = function createPopupExperience(action, popupSelector) {
|
|
80
|
+
var type = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'editorRoot';
|
|
68
81
|
return new Experience(EXPERIENCE_ID.TOOLBAR_ACTION, {
|
|
69
82
|
action: action,
|
|
70
83
|
actionSubjectId: PRIMARY_TOOLBAR,
|
|
71
84
|
dispatchAnalyticsEvent: dispatchAnalyticsEvent,
|
|
72
85
|
checks: [new ExperienceCheckTimeout({
|
|
73
86
|
durationMs: TIMEOUT_DURATION
|
|
74
|
-
}), new ExperienceCheckPopupMutation(popupSelector, getPopupsTarget, getEditorDom)]
|
|
87
|
+
}), new ExperienceCheckPopupMutation(popupSelector, type === 'inline' ? getInlinePopupTarget : getPopupsTarget, getEditorDom, type)]
|
|
75
88
|
});
|
|
76
89
|
};
|
|
77
90
|
var experienceButtonMappings = [{
|
|
78
|
-
experience: createPopupExperience('
|
|
91
|
+
experience: createPopupExperience('insert', '[data-testid="popup-wrapper"]', 'inline'),
|
|
92
|
+
buttonTestId: TOOLBAR_BUTTON_TEST_ID.INSERT
|
|
93
|
+
}, {
|
|
94
|
+
experience: createPopupExperience('emoji', '[data-emoji-picker-container], [data-emoji-picker-container="true"], [data-testid="popup-wrapper"]', 'inline'),
|
|
79
95
|
buttonTestId: TOOLBAR_BUTTON_TEST_ID.EMOJI
|
|
80
96
|
}, {
|
|
81
|
-
experience: createPopupExperience('media', '[
|
|
97
|
+
experience: createPopupExperience('media', '[data-testid="popup-wrapper"]', 'inline'),
|
|
82
98
|
buttonTestId: TOOLBAR_BUTTON_TEST_ID.MEDIA
|
|
83
99
|
}, {
|
|
84
|
-
experience:
|
|
85
|
-
action: 'mention',
|
|
86
|
-
actionSubjectId: PRIMARY_TOOLBAR,
|
|
87
|
-
dispatchAnalyticsEvent: dispatchAnalyticsEvent,
|
|
88
|
-
checks: [new ExperienceCheckTimeout({
|
|
89
|
-
durationMs: TIMEOUT_DURATION
|
|
90
|
-
}), new ExperienceCheckDomMutation({
|
|
91
|
-
onDomMutation: handleTypeAheadOpenDomMutation,
|
|
92
|
-
observeConfig: narrowParentObserveConfig
|
|
93
|
-
})]
|
|
94
|
-
}),
|
|
100
|
+
experience: createPopupExperience('mention', '[data-testid="popup-wrapper"], [data-type-ahead="typeaheadDecoration"]', 'editorRoot'),
|
|
95
101
|
buttonTestId: TOOLBAR_BUTTON_TEST_ID.MENTION
|
|
96
102
|
}, {
|
|
97
103
|
experience: createNodeInsertExperience('table'),
|
|
98
104
|
buttonTestId: TOOLBAR_BUTTON_TEST_ID.TABLE
|
|
99
105
|
}, {
|
|
100
|
-
experience: createPopupExperience('tableSelector', '[aria-label*="table size"], [data-testid*="table-selector"]'),
|
|
106
|
+
experience: createPopupExperience('tableSelector', '[aria-label*="table size"], [data-testid*="table-selector"]', 'inline'),
|
|
101
107
|
buttonTestId: TOOLBAR_BUTTON_TEST_ID.TABLE_SELECTOR
|
|
102
108
|
}, {
|
|
103
109
|
experience: createNodeInsertExperience('layout'),
|
|
104
110
|
buttonTestId: TOOLBAR_BUTTON_TEST_ID.LAYOUT
|
|
105
111
|
}, {
|
|
106
|
-
experience: createPopupExperience('image', '[
|
|
112
|
+
experience: createPopupExperience('image', '[data-testid="popup-wrapper"]', 'inline'),
|
|
107
113
|
buttonTestId: TOOLBAR_BUTTON_TEST_ID.IMAGE
|
|
108
114
|
}, {
|
|
109
115
|
experience: createNodeInsertExperience('action'),
|
|
@@ -115,6 +121,8 @@ export var getToolbarActionExperiencesPlugin = function getToolbarActionExperien
|
|
|
115
121
|
experience = _experienceButtonMapp2.experience,
|
|
116
122
|
buttonTestId = _experienceButtonMapp2.buttonTestId;
|
|
117
123
|
if (isToolbarButtonClick(target, buttonTestId)) {
|
|
124
|
+
// Store the clicked button so inline popup checks can find its button-group
|
|
125
|
+
lastClickedToolbarButton = target;
|
|
118
126
|
experience.start({
|
|
119
127
|
forceRestart: true
|
|
120
128
|
});
|