@atlaskit/editor-plugin-block-controls 8.6.4 → 8.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/block-decoration-utils/package.json +17 -0
- package/dist/cjs/blockControlsPlugin.js +15 -1
- package/dist/cjs/pm-plugins/main.js +56 -29
- package/dist/cjs/ui/block-decoration-utils.js +53 -0
- package/dist/cjs/ui/consts.js +1 -9
- package/dist/es2019/blockControlsPlugin.js +273 -259
- package/dist/es2019/pm-plugins/main.js +25 -29
- package/dist/es2019/ui/block-decoration-utils.js +9 -0
- package/dist/es2019/ui/consts.js +0 -8
- package/dist/esm/blockControlsPlugin.js +15 -1
- package/dist/esm/pm-plugins/main.js +56 -29
- package/dist/esm/ui/block-decoration-utils.js +9 -0
- package/dist/esm/ui/consts.js +0 -8
- package/dist/types/blockControlsPluginType.d.ts +20 -2
- package/dist/types/index.d.ts +1 -1
- package/dist/types/pm-plugins/main.d.ts +3 -3
- package/dist/types/ui/block-decoration-utils.d.ts +6 -0
- package/dist/types/ui/consts.d.ts +0 -8
- package/dist/types-ts4.5/blockControlsPluginType.d.ts +20 -2
- package/dist/types-ts4.5/index.d.ts +1 -1
- package/dist/types-ts4.5/pm-plugins/main.d.ts +3 -3
- package/dist/types-ts4.5/ui/block-decoration-utils.d.ts +6 -0
- package/dist/types-ts4.5/ui/consts.d.ts +0 -8
- package/package.json +5 -2
- package/dist/cjs/pm-plugins/decorations-remix-button.js +0 -67
- package/dist/cjs/ui/remix-button.js +0 -163
- package/dist/es2019/pm-plugins/decorations-remix-button.js +0 -56
- package/dist/es2019/ui/remix-button.js +0 -144
- package/dist/esm/pm-plugins/decorations-remix-button.js +0 -59
- package/dist/esm/ui/remix-button.js +0 -154
- package/dist/types/pm-plugins/decorations-remix-button.d.ts +0 -21
- package/dist/types/ui/remix-button.d.ts +0 -17
- package/dist/types-ts4.5/pm-plugins/decorations-remix-button.d.ts +0 -21
- package/dist/types-ts4.5/ui/remix-button.d.ts +0 -17
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
-
var _typeof = require("@babel/runtime/helpers/typeof");
|
|
5
|
-
Object.defineProperty(exports, "__esModule", {
|
|
6
|
-
value: true
|
|
7
|
-
});
|
|
8
|
-
exports.RemixButton = void 0;
|
|
9
|
-
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
|
|
10
|
-
var _react = _interopRequireWildcard(require("react"));
|
|
11
|
-
var _react2 = require("@emotion/react");
|
|
12
|
-
var _bindEventListener = require("bind-event-listener");
|
|
13
|
-
var _new = require("@atlaskit/button/new");
|
|
14
|
-
var _hooks = require("@atlaskit/editor-common/hooks");
|
|
15
|
-
var _randomize = _interopRequireDefault(require("@atlaskit/icon-lab/core/randomize"));
|
|
16
|
-
var _dragHandlePositions = require("../pm-plugins/utils/drag-handle-positions");
|
|
17
|
-
var _widgetPositions = require("../pm-plugins/utils/widget-positions");
|
|
18
|
-
var _consts = require("./consts");
|
|
19
|
-
var _anchorName = require("./utils/anchor-name");
|
|
20
|
-
var _domAttrName = require("./utils/dom-attr-name");
|
|
21
|
-
var _visibilityContainer = require("./visibility-container");
|
|
22
|
-
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); }
|
|
23
|
-
/**
|
|
24
|
-
* Remix block control: positioned at the right edge of the block.
|
|
25
|
-
* Uses anchor(anchorName end) or getRightPositionForRootElement (same coordinate system
|
|
26
|
-
* as left controls). The widget span has no position:relative so position:absolute
|
|
27
|
-
* uses the same containing block as the node.
|
|
28
|
-
*/
|
|
29
|
-
/* @jsxRuntime classic */
|
|
30
|
-
/**
|
|
31
|
-
* @jsxRuntime classic
|
|
32
|
-
* @jsx jsx
|
|
33
|
-
*/
|
|
34
|
-
|
|
35
|
-
// eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
|
|
36
|
-
|
|
37
|
-
var containerBaseStyles = (0, _react2.css)({
|
|
38
|
-
position: 'absolute',
|
|
39
|
-
zIndex: 100,
|
|
40
|
-
display: 'flex',
|
|
41
|
-
alignItems: 'center',
|
|
42
|
-
justifyContent: 'center'
|
|
43
|
-
});
|
|
44
|
-
var RemixButton = exports.RemixButton = function RemixButton(_ref) {
|
|
45
|
-
var view = _ref.view,
|
|
46
|
-
api = _ref.api,
|
|
47
|
-
getPos = _ref.getPos,
|
|
48
|
-
anchorName = _ref.anchorName,
|
|
49
|
-
rootAnchorName = _ref.rootAnchorName,
|
|
50
|
-
rootNodeType = _ref.rootNodeType;
|
|
51
|
-
var _useSharedPluginState = (0, _hooks.useSharedPluginStateWithSelector)(api, ['featureFlags'], function (states) {
|
|
52
|
-
var _states$featureFlagsS;
|
|
53
|
-
return {
|
|
54
|
-
macroInteractionUpdates: (_states$featureFlagsS = states.featureFlagsState) === null || _states$featureFlagsS === void 0 ? void 0 : _states$featureFlagsS.macroInteractionUpdates
|
|
55
|
-
};
|
|
56
|
-
}),
|
|
57
|
-
macroInteractionUpdates = _useSharedPluginState.macroInteractionUpdates;
|
|
58
|
-
var _useState = (0, _react.useState)({
|
|
59
|
-
display: 'none'
|
|
60
|
-
}),
|
|
61
|
-
_useState2 = (0, _slicedToArray2.default)(_useState, 2),
|
|
62
|
-
positionStyles = _useState2[0],
|
|
63
|
-
setPositionStyles = _useState2[1];
|
|
64
|
-
|
|
65
|
-
// Same positioning pattern as quick insert / drag handle: anchor(start/end) or offset-based left/top
|
|
66
|
-
var calculatePosition = (0, _react.useCallback)(function () {
|
|
67
|
-
var _dom$offsetLeft;
|
|
68
|
-
var safeAnchorName = (0, _anchorName.refreshAnchorName)({
|
|
69
|
-
getPos: getPos,
|
|
70
|
-
view: view,
|
|
71
|
-
anchorName: rootAnchorName !== null && rootAnchorName !== void 0 ? rootAnchorName : anchorName
|
|
72
|
-
});
|
|
73
|
-
var dom = view.dom.querySelector("[".concat((0, _domAttrName.getAnchorAttrName)(), "=\"").concat(safeAnchorName, "\"]"));
|
|
74
|
-
if (!dom) {
|
|
75
|
-
return {
|
|
76
|
-
display: 'none'
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
var hasResizer = rootNodeType === 'table' || rootNodeType === 'mediaSingle';
|
|
80
|
-
var isExtension = rootNodeType === 'extension' || rootNodeType === 'bodiedExtension';
|
|
81
|
-
var isBlockCard = rootNodeType === 'blockCard';
|
|
82
|
-
var isEmbedCard = rootNodeType === 'embedCard';
|
|
83
|
-
var isMacroInteractionUpdates = macroInteractionUpdates && isExtension;
|
|
84
|
-
var innerContainer = null;
|
|
85
|
-
if (dom) {
|
|
86
|
-
if (isEmbedCard) {
|
|
87
|
-
innerContainer = dom.querySelector('.rich-media-item');
|
|
88
|
-
} else if (hasResizer) {
|
|
89
|
-
innerContainer = dom.querySelector('.resizer-item');
|
|
90
|
-
} else if (isExtension) {
|
|
91
|
-
innerContainer = dom.querySelector('.extension-container[data-layout]');
|
|
92
|
-
} else if (isBlockCard) {
|
|
93
|
-
innerContainer = dom.querySelector('.datasourceView-content-inner-wrap');
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
var isEdgeCase = (hasResizer || isExtension || isEmbedCard || isBlockCard) && innerContainer;
|
|
97
|
-
|
|
98
|
-
// Check anchor first (no reflow). Only call expensive getRightPositionForRootElement when fallback needed.
|
|
99
|
-
var supportsAnchorRight = CSS.supports('left', "anchor(".concat(safeAnchorName, " end)")) && CSS.supports('top', "anchor(".concat(safeAnchorName, " start)"));
|
|
100
|
-
if (supportsAnchorRight && !isEdgeCase) {
|
|
101
|
-
return {
|
|
102
|
-
left: "calc(anchor(".concat(safeAnchorName, " end) - ").concat(_consts.REMIX_BUTTON_DIMENSIONS.width, "px - ").concat((0, _consts.rootElementGap)(rootNodeType), "px + ").concat(_consts.REMIX_BUTTON_RIGHT_OFFSET, "px)"),
|
|
103
|
-
top: "calc(anchor(".concat(safeAnchorName, " start) + ").concat((0, _consts.topPositionAdjustment)(rootNodeType), "px)"),
|
|
104
|
-
height: "".concat(_consts.REMIX_BUTTON_DIMENSIONS.height, "px"),
|
|
105
|
-
bottom: 'unset'
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
// Fallback: offset-based (triggers reflow). When isEdgeCase add dom.offsetLeft (same as left controls).
|
|
109
|
-
var rightEdgeLeft = (0, _widgetPositions.getRightPositionForRootElement)(dom, rootNodeType, _consts.REMIX_BUTTON_DIMENSIONS, innerContainer !== null && innerContainer !== void 0 ? innerContainer : undefined, isMacroInteractionUpdates);
|
|
110
|
-
return {
|
|
111
|
-
left: isEdgeCase ? "calc(".concat((_dom$offsetLeft = dom === null || dom === void 0 ? void 0 : dom.offsetLeft) !== null && _dom$offsetLeft !== void 0 ? _dom$offsetLeft : 0, "px + (").concat(rightEdgeLeft, ") + ").concat(_consts.REMIX_BUTTON_RIGHT_OFFSET, "px)") : "calc(".concat(rightEdgeLeft, " + ").concat(_consts.REMIX_BUTTON_RIGHT_OFFSET, "px)"),
|
|
112
|
-
top: (0, _dragHandlePositions.getTopPosition)(dom, rootNodeType),
|
|
113
|
-
height: "".concat(_consts.REMIX_BUTTON_DIMENSIONS.height, "px"),
|
|
114
|
-
bottom: 'unset'
|
|
115
|
-
};
|
|
116
|
-
}, [view, getPos, anchorName, rootAnchorName, rootNodeType, macroInteractionUpdates]);
|
|
117
|
-
|
|
118
|
-
// Recompute button position on mount and when extension/embedCard layout changes (e.g. expand/collapse).
|
|
119
|
-
// For extension/embedCard we listen to transitionend so position updates after CSS transitions finish.
|
|
120
|
-
(0, _react.useEffect)(function () {
|
|
121
|
-
var cleanUpTransitionListener;
|
|
122
|
-
if (rootNodeType === 'extension' || rootNodeType === 'embedCard') {
|
|
123
|
-
var anchorDom = view.dom.querySelector("[".concat((0, _domAttrName.getAnchorAttrName)(), "=\"").concat(rootAnchorName !== null && rootAnchorName !== void 0 ? rootAnchorName : anchorName, "\"]"));
|
|
124
|
-
if (anchorDom) {
|
|
125
|
-
cleanUpTransitionListener = (0, _bindEventListener.bind)(anchorDom, {
|
|
126
|
-
type: 'transitionend',
|
|
127
|
-
listener: function listener() {
|
|
128
|
-
return setPositionStyles(calculatePosition());
|
|
129
|
-
}
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
var id = requestAnimationFrame(function () {
|
|
134
|
-
return setPositionStyles(calculatePosition());
|
|
135
|
-
});
|
|
136
|
-
return function () {
|
|
137
|
-
var _cleanUpTransitionLis;
|
|
138
|
-
cancelAnimationFrame(id);
|
|
139
|
-
(_cleanUpTransitionLis = cleanUpTransitionListener) === null || _cleanUpTransitionLis === void 0 || _cleanUpTransitionLis();
|
|
140
|
-
};
|
|
141
|
-
}, [calculatePosition, view.dom, rootAnchorName, rootNodeType, anchorName]);
|
|
142
|
-
return (0, _react2.jsx)(_visibilityContainer.VisibilityContainer, {
|
|
143
|
-
api: api
|
|
144
|
-
}, (0, _react2.jsx)("div", {
|
|
145
|
-
css: containerBaseStyles
|
|
146
|
-
// eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Dynamic positioning (left, top, height) calculated at runtime
|
|
147
|
-
,
|
|
148
|
-
style: positionStyles,
|
|
149
|
-
"data-testid": "block-ctrl-remix-button"
|
|
150
|
-
}, (0, _react2.jsx)(_new.IconButton, {
|
|
151
|
-
spacing: "compact",
|
|
152
|
-
appearance: "subtle",
|
|
153
|
-
label: "Remix",
|
|
154
|
-
icon: function icon() {
|
|
155
|
-
return (0, _react2.jsx)(_randomize.default, {
|
|
156
|
-
label: ""
|
|
157
|
-
});
|
|
158
|
-
},
|
|
159
|
-
onMouseDown: function onMouseDown(e) {
|
|
160
|
-
return e.preventDefault();
|
|
161
|
-
}
|
|
162
|
-
})));
|
|
163
|
-
};
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { createElement } from 'react';
|
|
2
|
-
// eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead
|
|
3
|
-
import uuid from 'uuid';
|
|
4
|
-
import { getDocument } from '@atlaskit/browser-apis';
|
|
5
|
-
import { Decoration } from '@atlaskit/editor-prosemirror/view';
|
|
6
|
-
import { fg } from '@atlaskit/platform-feature-flags';
|
|
7
|
-
import { RemixButton } from '../ui/remix-button';
|
|
8
|
-
const TYPE_REMIX_BUTTON = 'REMIX_BUTTON';
|
|
9
|
-
export const findRemixButtonDecoration = (decorations, from, to) => {
|
|
10
|
-
return decorations.find(from, to, spec => spec.type === TYPE_REMIX_BUTTON);
|
|
11
|
-
};
|
|
12
|
-
/** Right-edge Remix button: same gutter as left controls (side: -4) but positioned at block right edge. */
|
|
13
|
-
export const remixButtonDecoration = ({
|
|
14
|
-
api,
|
|
15
|
-
formatMessage,
|
|
16
|
-
rootPos,
|
|
17
|
-
anchorName,
|
|
18
|
-
nodeType,
|
|
19
|
-
nodeViewPortalProviderAPI,
|
|
20
|
-
rootAnchorName,
|
|
21
|
-
rootNodeType
|
|
22
|
-
}) => {
|
|
23
|
-
// eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead
|
|
24
|
-
const key = uuid();
|
|
25
|
-
const widgetSpec = {
|
|
26
|
-
side: -4,
|
|
27
|
-
type: TYPE_REMIX_BUTTON,
|
|
28
|
-
destroy: _ => {
|
|
29
|
-
if (fg('platform_editor_fix_widget_destroy')) {
|
|
30
|
-
nodeViewPortalProviderAPI.remove(key);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
};
|
|
34
|
-
return Decoration.widget(rootPos, (view, getPos) => {
|
|
35
|
-
const doc = getDocument();
|
|
36
|
-
if (!doc) {
|
|
37
|
-
throw new Error('Document not available');
|
|
38
|
-
}
|
|
39
|
-
const element = doc.createElement('span');
|
|
40
|
-
element.style.display = 'block';
|
|
41
|
-
element.contentEditable = 'false';
|
|
42
|
-
element.setAttribute('data-blocks-remix-button-container', 'true');
|
|
43
|
-
element.setAttribute('data-testid', 'block-ctrl-remix-button-container');
|
|
44
|
-
nodeViewPortalProviderAPI.render(() => /*#__PURE__*/createElement(RemixButton, {
|
|
45
|
-
api,
|
|
46
|
-
getPos,
|
|
47
|
-
formatMessage,
|
|
48
|
-
view,
|
|
49
|
-
nodeType,
|
|
50
|
-
anchorName,
|
|
51
|
-
rootAnchorName,
|
|
52
|
-
rootNodeType: rootNodeType !== null && rootNodeType !== void 0 ? rootNodeType : nodeType
|
|
53
|
-
}), element, key, undefined, true);
|
|
54
|
-
return element;
|
|
55
|
-
}, widgetSpec);
|
|
56
|
-
};
|
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Remix block control: positioned at the right edge of the block.
|
|
3
|
-
* Uses anchor(anchorName end) or getRightPositionForRootElement (same coordinate system
|
|
4
|
-
* as left controls). The widget span has no position:relative so position:absolute
|
|
5
|
-
* uses the same containing block as the node.
|
|
6
|
-
*/
|
|
7
|
-
/* @jsxRuntime classic */
|
|
8
|
-
/**
|
|
9
|
-
* @jsxRuntime classic
|
|
10
|
-
* @jsx jsx
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
import React, { useCallback, useEffect, useState } from 'react';
|
|
14
|
-
|
|
15
|
-
// eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
|
|
16
|
-
import { css, jsx } from '@emotion/react';
|
|
17
|
-
import { bind } from 'bind-event-listener';
|
|
18
|
-
import { IconButton } from '@atlaskit/button/new';
|
|
19
|
-
import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
|
|
20
|
-
import RandomizeIcon from '@atlaskit/icon-lab/core/randomize';
|
|
21
|
-
import { getTopPosition } from '../pm-plugins/utils/drag-handle-positions';
|
|
22
|
-
import { getRightPositionForRootElement } from '../pm-plugins/utils/widget-positions';
|
|
23
|
-
import { REMIX_BUTTON_DIMENSIONS, REMIX_BUTTON_RIGHT_OFFSET, rootElementGap, topPositionAdjustment } from './consts';
|
|
24
|
-
import { refreshAnchorName } from './utils/anchor-name';
|
|
25
|
-
import { getAnchorAttrName } from './utils/dom-attr-name';
|
|
26
|
-
import { VisibilityContainer } from './visibility-container';
|
|
27
|
-
const containerBaseStyles = css({
|
|
28
|
-
position: 'absolute',
|
|
29
|
-
zIndex: 100,
|
|
30
|
-
display: 'flex',
|
|
31
|
-
alignItems: 'center',
|
|
32
|
-
justifyContent: 'center'
|
|
33
|
-
});
|
|
34
|
-
export const RemixButton = ({
|
|
35
|
-
view,
|
|
36
|
-
api,
|
|
37
|
-
getPos,
|
|
38
|
-
anchorName,
|
|
39
|
-
rootAnchorName,
|
|
40
|
-
rootNodeType
|
|
41
|
-
}) => {
|
|
42
|
-
const {
|
|
43
|
-
macroInteractionUpdates
|
|
44
|
-
} = useSharedPluginStateWithSelector(api, ['featureFlags'], states => {
|
|
45
|
-
var _states$featureFlagsS;
|
|
46
|
-
return {
|
|
47
|
-
macroInteractionUpdates: (_states$featureFlagsS = states.featureFlagsState) === null || _states$featureFlagsS === void 0 ? void 0 : _states$featureFlagsS.macroInteractionUpdates
|
|
48
|
-
};
|
|
49
|
-
});
|
|
50
|
-
const [positionStyles, setPositionStyles] = useState({
|
|
51
|
-
display: 'none'
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
// Same positioning pattern as quick insert / drag handle: anchor(start/end) or offset-based left/top
|
|
55
|
-
const calculatePosition = useCallback(() => {
|
|
56
|
-
var _innerContainer, _dom$offsetLeft;
|
|
57
|
-
const safeAnchorName = refreshAnchorName({
|
|
58
|
-
getPos,
|
|
59
|
-
view,
|
|
60
|
-
anchorName: rootAnchorName !== null && rootAnchorName !== void 0 ? rootAnchorName : anchorName
|
|
61
|
-
});
|
|
62
|
-
const dom = view.dom.querySelector(`[${getAnchorAttrName()}="${safeAnchorName}"]`);
|
|
63
|
-
if (!dom) {
|
|
64
|
-
return {
|
|
65
|
-
display: 'none'
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
const hasResizer = rootNodeType === 'table' || rootNodeType === 'mediaSingle';
|
|
69
|
-
const isExtension = rootNodeType === 'extension' || rootNodeType === 'bodiedExtension';
|
|
70
|
-
const isBlockCard = rootNodeType === 'blockCard';
|
|
71
|
-
const isEmbedCard = rootNodeType === 'embedCard';
|
|
72
|
-
const isMacroInteractionUpdates = macroInteractionUpdates && isExtension;
|
|
73
|
-
let innerContainer = null;
|
|
74
|
-
if (dom) {
|
|
75
|
-
if (isEmbedCard) {
|
|
76
|
-
innerContainer = dom.querySelector('.rich-media-item');
|
|
77
|
-
} else if (hasResizer) {
|
|
78
|
-
innerContainer = dom.querySelector('.resizer-item');
|
|
79
|
-
} else if (isExtension) {
|
|
80
|
-
innerContainer = dom.querySelector('.extension-container[data-layout]');
|
|
81
|
-
} else if (isBlockCard) {
|
|
82
|
-
innerContainer = dom.querySelector('.datasourceView-content-inner-wrap');
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
const isEdgeCase = (hasResizer || isExtension || isEmbedCard || isBlockCard) && innerContainer;
|
|
86
|
-
|
|
87
|
-
// Check anchor first (no reflow). Only call expensive getRightPositionForRootElement when fallback needed.
|
|
88
|
-
const supportsAnchorRight = CSS.supports('left', `anchor(${safeAnchorName} end)`) && CSS.supports('top', `anchor(${safeAnchorName} start)`);
|
|
89
|
-
if (supportsAnchorRight && !isEdgeCase) {
|
|
90
|
-
return {
|
|
91
|
-
left: `calc(anchor(${safeAnchorName} end) - ${REMIX_BUTTON_DIMENSIONS.width}px - ${rootElementGap(rootNodeType)}px + ${REMIX_BUTTON_RIGHT_OFFSET}px)`,
|
|
92
|
-
top: `calc(anchor(${safeAnchorName} start) + ${topPositionAdjustment(rootNodeType)}px)`,
|
|
93
|
-
height: `${REMIX_BUTTON_DIMENSIONS.height}px`,
|
|
94
|
-
bottom: 'unset'
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
// Fallback: offset-based (triggers reflow). When isEdgeCase add dom.offsetLeft (same as left controls).
|
|
98
|
-
const rightEdgeLeft = getRightPositionForRootElement(dom, rootNodeType, REMIX_BUTTON_DIMENSIONS, (_innerContainer = innerContainer) !== null && _innerContainer !== void 0 ? _innerContainer : undefined, isMacroInteractionUpdates);
|
|
99
|
-
return {
|
|
100
|
-
left: isEdgeCase ? `calc(${(_dom$offsetLeft = dom === null || dom === void 0 ? void 0 : dom.offsetLeft) !== null && _dom$offsetLeft !== void 0 ? _dom$offsetLeft : 0}px + (${rightEdgeLeft}) + ${REMIX_BUTTON_RIGHT_OFFSET}px)` : `calc(${rightEdgeLeft} + ${REMIX_BUTTON_RIGHT_OFFSET}px)`,
|
|
101
|
-
top: getTopPosition(dom, rootNodeType),
|
|
102
|
-
height: `${REMIX_BUTTON_DIMENSIONS.height}px`,
|
|
103
|
-
bottom: 'unset'
|
|
104
|
-
};
|
|
105
|
-
}, [view, getPos, anchorName, rootAnchorName, rootNodeType, macroInteractionUpdates]);
|
|
106
|
-
|
|
107
|
-
// Recompute button position on mount and when extension/embedCard layout changes (e.g. expand/collapse).
|
|
108
|
-
// For extension/embedCard we listen to transitionend so position updates after CSS transitions finish.
|
|
109
|
-
useEffect(() => {
|
|
110
|
-
let cleanUpTransitionListener;
|
|
111
|
-
if (rootNodeType === 'extension' || rootNodeType === 'embedCard') {
|
|
112
|
-
const anchorDom = view.dom.querySelector(`[${getAnchorAttrName()}="${rootAnchorName !== null && rootAnchorName !== void 0 ? rootAnchorName : anchorName}"]`);
|
|
113
|
-
if (anchorDom) {
|
|
114
|
-
cleanUpTransitionListener = bind(anchorDom, {
|
|
115
|
-
type: 'transitionend',
|
|
116
|
-
listener: () => setPositionStyles(calculatePosition())
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
const id = requestAnimationFrame(() => setPositionStyles(calculatePosition()));
|
|
121
|
-
return () => {
|
|
122
|
-
var _cleanUpTransitionLis;
|
|
123
|
-
cancelAnimationFrame(id);
|
|
124
|
-
(_cleanUpTransitionLis = cleanUpTransitionListener) === null || _cleanUpTransitionLis === void 0 ? void 0 : _cleanUpTransitionLis();
|
|
125
|
-
};
|
|
126
|
-
}, [calculatePosition, view.dom, rootAnchorName, rootNodeType, anchorName]);
|
|
127
|
-
return jsx(VisibilityContainer, {
|
|
128
|
-
api: api
|
|
129
|
-
}, jsx("div", {
|
|
130
|
-
css: containerBaseStyles
|
|
131
|
-
// eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Dynamic positioning (left, top, height) calculated at runtime
|
|
132
|
-
,
|
|
133
|
-
style: positionStyles,
|
|
134
|
-
"data-testid": "block-ctrl-remix-button"
|
|
135
|
-
}, jsx(IconButton, {
|
|
136
|
-
spacing: "compact",
|
|
137
|
-
appearance: "subtle",
|
|
138
|
-
label: "Remix",
|
|
139
|
-
icon: () => jsx(RandomizeIcon, {
|
|
140
|
-
label: ""
|
|
141
|
-
}),
|
|
142
|
-
onMouseDown: e => e.preventDefault()
|
|
143
|
-
})));
|
|
144
|
-
};
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { createElement } from 'react';
|
|
2
|
-
// eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead
|
|
3
|
-
import uuid from 'uuid';
|
|
4
|
-
import { getDocument } from '@atlaskit/browser-apis';
|
|
5
|
-
import { Decoration } from '@atlaskit/editor-prosemirror/view';
|
|
6
|
-
import { fg } from '@atlaskit/platform-feature-flags';
|
|
7
|
-
import { RemixButton } from '../ui/remix-button';
|
|
8
|
-
var TYPE_REMIX_BUTTON = 'REMIX_BUTTON';
|
|
9
|
-
export var findRemixButtonDecoration = function findRemixButtonDecoration(decorations, from, to) {
|
|
10
|
-
return decorations.find(from, to, function (spec) {
|
|
11
|
-
return spec.type === TYPE_REMIX_BUTTON;
|
|
12
|
-
});
|
|
13
|
-
};
|
|
14
|
-
/** Right-edge Remix button: same gutter as left controls (side: -4) but positioned at block right edge. */
|
|
15
|
-
export var remixButtonDecoration = function remixButtonDecoration(_ref) {
|
|
16
|
-
var api = _ref.api,
|
|
17
|
-
formatMessage = _ref.formatMessage,
|
|
18
|
-
rootPos = _ref.rootPos,
|
|
19
|
-
anchorName = _ref.anchorName,
|
|
20
|
-
nodeType = _ref.nodeType,
|
|
21
|
-
nodeViewPortalProviderAPI = _ref.nodeViewPortalProviderAPI,
|
|
22
|
-
rootAnchorName = _ref.rootAnchorName,
|
|
23
|
-
rootNodeType = _ref.rootNodeType;
|
|
24
|
-
// eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead
|
|
25
|
-
var key = uuid();
|
|
26
|
-
var widgetSpec = {
|
|
27
|
-
side: -4,
|
|
28
|
-
type: TYPE_REMIX_BUTTON,
|
|
29
|
-
destroy: function destroy(_) {
|
|
30
|
-
if (fg('platform_editor_fix_widget_destroy')) {
|
|
31
|
-
nodeViewPortalProviderAPI.remove(key);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
};
|
|
35
|
-
return Decoration.widget(rootPos, function (view, getPos) {
|
|
36
|
-
var doc = getDocument();
|
|
37
|
-
if (!doc) {
|
|
38
|
-
throw new Error('Document not available');
|
|
39
|
-
}
|
|
40
|
-
var element = doc.createElement('span');
|
|
41
|
-
element.style.display = 'block';
|
|
42
|
-
element.contentEditable = 'false';
|
|
43
|
-
element.setAttribute('data-blocks-remix-button-container', 'true');
|
|
44
|
-
element.setAttribute('data-testid', 'block-ctrl-remix-button-container');
|
|
45
|
-
nodeViewPortalProviderAPI.render(function () {
|
|
46
|
-
return /*#__PURE__*/createElement(RemixButton, {
|
|
47
|
-
api: api,
|
|
48
|
-
getPos: getPos,
|
|
49
|
-
formatMessage: formatMessage,
|
|
50
|
-
view: view,
|
|
51
|
-
nodeType: nodeType,
|
|
52
|
-
anchorName: anchorName,
|
|
53
|
-
rootAnchorName: rootAnchorName,
|
|
54
|
-
rootNodeType: rootNodeType !== null && rootNodeType !== void 0 ? rootNodeType : nodeType
|
|
55
|
-
});
|
|
56
|
-
}, element, key, undefined, true);
|
|
57
|
-
return element;
|
|
58
|
-
}, widgetSpec);
|
|
59
|
-
};
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
2
|
-
/**
|
|
3
|
-
* Remix block control: positioned at the right edge of the block.
|
|
4
|
-
* Uses anchor(anchorName end) or getRightPositionForRootElement (same coordinate system
|
|
5
|
-
* as left controls). The widget span has no position:relative so position:absolute
|
|
6
|
-
* uses the same containing block as the node.
|
|
7
|
-
*/
|
|
8
|
-
/* @jsxRuntime classic */
|
|
9
|
-
/**
|
|
10
|
-
* @jsxRuntime classic
|
|
11
|
-
* @jsx jsx
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
import React, { useCallback, useEffect, useState } from 'react';
|
|
15
|
-
|
|
16
|
-
// eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
|
|
17
|
-
import { css, jsx } from '@emotion/react';
|
|
18
|
-
import { bind } from 'bind-event-listener';
|
|
19
|
-
import { IconButton } from '@atlaskit/button/new';
|
|
20
|
-
import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
|
|
21
|
-
import RandomizeIcon from '@atlaskit/icon-lab/core/randomize';
|
|
22
|
-
import { getTopPosition } from '../pm-plugins/utils/drag-handle-positions';
|
|
23
|
-
import { getRightPositionForRootElement } from '../pm-plugins/utils/widget-positions';
|
|
24
|
-
import { REMIX_BUTTON_DIMENSIONS, REMIX_BUTTON_RIGHT_OFFSET, rootElementGap, topPositionAdjustment } from './consts';
|
|
25
|
-
import { refreshAnchorName } from './utils/anchor-name';
|
|
26
|
-
import { getAnchorAttrName } from './utils/dom-attr-name';
|
|
27
|
-
import { VisibilityContainer } from './visibility-container';
|
|
28
|
-
var containerBaseStyles = css({
|
|
29
|
-
position: 'absolute',
|
|
30
|
-
zIndex: 100,
|
|
31
|
-
display: 'flex',
|
|
32
|
-
alignItems: 'center',
|
|
33
|
-
justifyContent: 'center'
|
|
34
|
-
});
|
|
35
|
-
export var RemixButton = function RemixButton(_ref) {
|
|
36
|
-
var view = _ref.view,
|
|
37
|
-
api = _ref.api,
|
|
38
|
-
getPos = _ref.getPos,
|
|
39
|
-
anchorName = _ref.anchorName,
|
|
40
|
-
rootAnchorName = _ref.rootAnchorName,
|
|
41
|
-
rootNodeType = _ref.rootNodeType;
|
|
42
|
-
var _useSharedPluginState = useSharedPluginStateWithSelector(api, ['featureFlags'], function (states) {
|
|
43
|
-
var _states$featureFlagsS;
|
|
44
|
-
return {
|
|
45
|
-
macroInteractionUpdates: (_states$featureFlagsS = states.featureFlagsState) === null || _states$featureFlagsS === void 0 ? void 0 : _states$featureFlagsS.macroInteractionUpdates
|
|
46
|
-
};
|
|
47
|
-
}),
|
|
48
|
-
macroInteractionUpdates = _useSharedPluginState.macroInteractionUpdates;
|
|
49
|
-
var _useState = useState({
|
|
50
|
-
display: 'none'
|
|
51
|
-
}),
|
|
52
|
-
_useState2 = _slicedToArray(_useState, 2),
|
|
53
|
-
positionStyles = _useState2[0],
|
|
54
|
-
setPositionStyles = _useState2[1];
|
|
55
|
-
|
|
56
|
-
// Same positioning pattern as quick insert / drag handle: anchor(start/end) or offset-based left/top
|
|
57
|
-
var calculatePosition = useCallback(function () {
|
|
58
|
-
var _dom$offsetLeft;
|
|
59
|
-
var safeAnchorName = refreshAnchorName({
|
|
60
|
-
getPos: getPos,
|
|
61
|
-
view: view,
|
|
62
|
-
anchorName: rootAnchorName !== null && rootAnchorName !== void 0 ? rootAnchorName : anchorName
|
|
63
|
-
});
|
|
64
|
-
var dom = view.dom.querySelector("[".concat(getAnchorAttrName(), "=\"").concat(safeAnchorName, "\"]"));
|
|
65
|
-
if (!dom) {
|
|
66
|
-
return {
|
|
67
|
-
display: 'none'
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
var hasResizer = rootNodeType === 'table' || rootNodeType === 'mediaSingle';
|
|
71
|
-
var isExtension = rootNodeType === 'extension' || rootNodeType === 'bodiedExtension';
|
|
72
|
-
var isBlockCard = rootNodeType === 'blockCard';
|
|
73
|
-
var isEmbedCard = rootNodeType === 'embedCard';
|
|
74
|
-
var isMacroInteractionUpdates = macroInteractionUpdates && isExtension;
|
|
75
|
-
var innerContainer = null;
|
|
76
|
-
if (dom) {
|
|
77
|
-
if (isEmbedCard) {
|
|
78
|
-
innerContainer = dom.querySelector('.rich-media-item');
|
|
79
|
-
} else if (hasResizer) {
|
|
80
|
-
innerContainer = dom.querySelector('.resizer-item');
|
|
81
|
-
} else if (isExtension) {
|
|
82
|
-
innerContainer = dom.querySelector('.extension-container[data-layout]');
|
|
83
|
-
} else if (isBlockCard) {
|
|
84
|
-
innerContainer = dom.querySelector('.datasourceView-content-inner-wrap');
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
var isEdgeCase = (hasResizer || isExtension || isEmbedCard || isBlockCard) && innerContainer;
|
|
88
|
-
|
|
89
|
-
// Check anchor first (no reflow). Only call expensive getRightPositionForRootElement when fallback needed.
|
|
90
|
-
var supportsAnchorRight = CSS.supports('left', "anchor(".concat(safeAnchorName, " end)")) && CSS.supports('top', "anchor(".concat(safeAnchorName, " start)"));
|
|
91
|
-
if (supportsAnchorRight && !isEdgeCase) {
|
|
92
|
-
return {
|
|
93
|
-
left: "calc(anchor(".concat(safeAnchorName, " end) - ").concat(REMIX_BUTTON_DIMENSIONS.width, "px - ").concat(rootElementGap(rootNodeType), "px + ").concat(REMIX_BUTTON_RIGHT_OFFSET, "px)"),
|
|
94
|
-
top: "calc(anchor(".concat(safeAnchorName, " start) + ").concat(topPositionAdjustment(rootNodeType), "px)"),
|
|
95
|
-
height: "".concat(REMIX_BUTTON_DIMENSIONS.height, "px"),
|
|
96
|
-
bottom: 'unset'
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
// Fallback: offset-based (triggers reflow). When isEdgeCase add dom.offsetLeft (same as left controls).
|
|
100
|
-
var rightEdgeLeft = getRightPositionForRootElement(dom, rootNodeType, REMIX_BUTTON_DIMENSIONS, innerContainer !== null && innerContainer !== void 0 ? innerContainer : undefined, isMacroInteractionUpdates);
|
|
101
|
-
return {
|
|
102
|
-
left: isEdgeCase ? "calc(".concat((_dom$offsetLeft = dom === null || dom === void 0 ? void 0 : dom.offsetLeft) !== null && _dom$offsetLeft !== void 0 ? _dom$offsetLeft : 0, "px + (").concat(rightEdgeLeft, ") + ").concat(REMIX_BUTTON_RIGHT_OFFSET, "px)") : "calc(".concat(rightEdgeLeft, " + ").concat(REMIX_BUTTON_RIGHT_OFFSET, "px)"),
|
|
103
|
-
top: getTopPosition(dom, rootNodeType),
|
|
104
|
-
height: "".concat(REMIX_BUTTON_DIMENSIONS.height, "px"),
|
|
105
|
-
bottom: 'unset'
|
|
106
|
-
};
|
|
107
|
-
}, [view, getPos, anchorName, rootAnchorName, rootNodeType, macroInteractionUpdates]);
|
|
108
|
-
|
|
109
|
-
// Recompute button position on mount and when extension/embedCard layout changes (e.g. expand/collapse).
|
|
110
|
-
// For extension/embedCard we listen to transitionend so position updates after CSS transitions finish.
|
|
111
|
-
useEffect(function () {
|
|
112
|
-
var cleanUpTransitionListener;
|
|
113
|
-
if (rootNodeType === 'extension' || rootNodeType === 'embedCard') {
|
|
114
|
-
var anchorDom = view.dom.querySelector("[".concat(getAnchorAttrName(), "=\"").concat(rootAnchorName !== null && rootAnchorName !== void 0 ? rootAnchorName : anchorName, "\"]"));
|
|
115
|
-
if (anchorDom) {
|
|
116
|
-
cleanUpTransitionListener = bind(anchorDom, {
|
|
117
|
-
type: 'transitionend',
|
|
118
|
-
listener: function listener() {
|
|
119
|
-
return setPositionStyles(calculatePosition());
|
|
120
|
-
}
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
var id = requestAnimationFrame(function () {
|
|
125
|
-
return setPositionStyles(calculatePosition());
|
|
126
|
-
});
|
|
127
|
-
return function () {
|
|
128
|
-
var _cleanUpTransitionLis;
|
|
129
|
-
cancelAnimationFrame(id);
|
|
130
|
-
(_cleanUpTransitionLis = cleanUpTransitionListener) === null || _cleanUpTransitionLis === void 0 || _cleanUpTransitionLis();
|
|
131
|
-
};
|
|
132
|
-
}, [calculatePosition, view.dom, rootAnchorName, rootNodeType, anchorName]);
|
|
133
|
-
return jsx(VisibilityContainer, {
|
|
134
|
-
api: api
|
|
135
|
-
}, jsx("div", {
|
|
136
|
-
css: containerBaseStyles
|
|
137
|
-
// eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Dynamic positioning (left, top, height) calculated at runtime
|
|
138
|
-
,
|
|
139
|
-
style: positionStyles,
|
|
140
|
-
"data-testid": "block-ctrl-remix-button"
|
|
141
|
-
}, jsx(IconButton, {
|
|
142
|
-
spacing: "compact",
|
|
143
|
-
appearance: "subtle",
|
|
144
|
-
label: "Remix",
|
|
145
|
-
icon: function icon() {
|
|
146
|
-
return jsx(RandomizeIcon, {
|
|
147
|
-
label: ""
|
|
148
|
-
});
|
|
149
|
-
},
|
|
150
|
-
onMouseDown: function onMouseDown(e) {
|
|
151
|
-
return e.preventDefault();
|
|
152
|
-
}
|
|
153
|
-
})));
|
|
154
|
-
};
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { type IntlShape } from 'react-intl-next';
|
|
2
|
-
import type { PortalProviderAPI } from '@atlaskit/editor-common/portal';
|
|
3
|
-
import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
|
|
4
|
-
import { type EditorState } from '@atlaskit/editor-prosemirror/state';
|
|
5
|
-
import { Decoration, type DecorationSet } from '@atlaskit/editor-prosemirror/view';
|
|
6
|
-
import type { BlockControlsPlugin } from '../blockControlsPluginType';
|
|
7
|
-
export declare const findRemixButtonDecoration: (decorations: DecorationSet, from?: number, to?: number) => Decoration[];
|
|
8
|
-
type RemixButtonDecorationParams = {
|
|
9
|
-
anchorName: string;
|
|
10
|
-
api: ExtractInjectionAPI<BlockControlsPlugin>;
|
|
11
|
-
editorState: EditorState;
|
|
12
|
-
formatMessage: IntlShape['formatMessage'];
|
|
13
|
-
nodeType: string;
|
|
14
|
-
nodeViewPortalProviderAPI: PortalProviderAPI;
|
|
15
|
-
rootAnchorName?: string;
|
|
16
|
-
rootNodeType?: string;
|
|
17
|
-
rootPos: number;
|
|
18
|
-
};
|
|
19
|
-
/** Right-edge Remix button: same gutter as left controls (side: -4) but positioned at block right edge. */
|
|
20
|
-
export declare const remixButtonDecoration: ({ api, formatMessage, rootPos, anchorName, nodeType, nodeViewPortalProviderAPI, rootAnchorName, rootNodeType, }: RemixButtonDecorationParams) => Decoration;
|
|
21
|
-
export {};
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { jsx } from '@emotion/react';
|
|
2
|
-
import type { IntlShape } from 'react-intl-next';
|
|
3
|
-
import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
|
|
4
|
-
import type { EditorView } from '@atlaskit/editor-prosemirror/view';
|
|
5
|
-
import type { BlockControlsPlugin } from '../blockControlsPluginType';
|
|
6
|
-
type RemixButtonProps = {
|
|
7
|
-
anchorName: string;
|
|
8
|
-
api: ExtractInjectionAPI<BlockControlsPlugin>;
|
|
9
|
-
formatMessage: IntlShape['formatMessage'];
|
|
10
|
-
getPos: () => number | undefined;
|
|
11
|
-
nodeType: string;
|
|
12
|
-
rootAnchorName?: string;
|
|
13
|
-
rootNodeType: string;
|
|
14
|
-
view: EditorView;
|
|
15
|
-
};
|
|
16
|
-
export declare const RemixButton: ({ view, api, getPos, anchorName, rootAnchorName, rootNodeType, }: RemixButtonProps) => jsx.JSX.Element;
|
|
17
|
-
export {};
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { type IntlShape } from 'react-intl-next';
|
|
2
|
-
import type { PortalProviderAPI } from '@atlaskit/editor-common/portal';
|
|
3
|
-
import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
|
|
4
|
-
import { type EditorState } from '@atlaskit/editor-prosemirror/state';
|
|
5
|
-
import { Decoration, type DecorationSet } from '@atlaskit/editor-prosemirror/view';
|
|
6
|
-
import type { BlockControlsPlugin } from '../blockControlsPluginType';
|
|
7
|
-
export declare const findRemixButtonDecoration: (decorations: DecorationSet, from?: number, to?: number) => Decoration[];
|
|
8
|
-
type RemixButtonDecorationParams = {
|
|
9
|
-
anchorName: string;
|
|
10
|
-
api: ExtractInjectionAPI<BlockControlsPlugin>;
|
|
11
|
-
editorState: EditorState;
|
|
12
|
-
formatMessage: IntlShape['formatMessage'];
|
|
13
|
-
nodeType: string;
|
|
14
|
-
nodeViewPortalProviderAPI: PortalProviderAPI;
|
|
15
|
-
rootAnchorName?: string;
|
|
16
|
-
rootNodeType?: string;
|
|
17
|
-
rootPos: number;
|
|
18
|
-
};
|
|
19
|
-
/** Right-edge Remix button: same gutter as left controls (side: -4) but positioned at block right edge. */
|
|
20
|
-
export declare const remixButtonDecoration: ({ api, formatMessage, rootPos, anchorName, nodeType, nodeViewPortalProviderAPI, rootAnchorName, rootNodeType, }: RemixButtonDecorationParams) => Decoration;
|
|
21
|
-
export {};
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { jsx } from '@emotion/react';
|
|
2
|
-
import type { IntlShape } from 'react-intl-next';
|
|
3
|
-
import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
|
|
4
|
-
import type { EditorView } from '@atlaskit/editor-prosemirror/view';
|
|
5
|
-
import type { BlockControlsPlugin } from '../blockControlsPluginType';
|
|
6
|
-
type RemixButtonProps = {
|
|
7
|
-
anchorName: string;
|
|
8
|
-
api: ExtractInjectionAPI<BlockControlsPlugin>;
|
|
9
|
-
formatMessage: IntlShape['formatMessage'];
|
|
10
|
-
getPos: () => number | undefined;
|
|
11
|
-
nodeType: string;
|
|
12
|
-
rootAnchorName?: string;
|
|
13
|
-
rootNodeType: string;
|
|
14
|
-
view: EditorView;
|
|
15
|
-
};
|
|
16
|
-
export declare const RemixButton: ({ view, api, getPos, anchorName, rootAnchorName, rootNodeType, }: RemixButtonProps) => jsx.JSX.Element;
|
|
17
|
-
export {};
|