@atlaskit/editor-common 96.4.1 → 96.5.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 +17 -0
- package/dist/cjs/extensibility/Extension/Lozenge/EditToggle.js +22 -4
- package/dist/cjs/hooks/useSharedPluginState.js +3 -0
- package/dist/cjs/hooks/useSharedPluginStateSelector/index.js +12 -0
- package/dist/cjs/hooks/useSharedPluginStateSelector/useSharedPluginStateSelector.js +114 -0
- package/dist/cjs/monitoring/error.js +1 -1
- package/dist/cjs/ui/DropList/index.js +1 -1
- package/dist/cjs/utils/profiler/render-count.js +2 -0
- package/dist/es2019/extensibility/Extension/Lozenge/EditToggle.js +18 -4
- package/dist/es2019/hooks/useSharedPluginState.js +3 -0
- package/dist/es2019/hooks/useSharedPluginStateSelector/index.js +2 -0
- package/dist/es2019/hooks/useSharedPluginStateSelector/useSharedPluginStateSelector.js +98 -0
- package/dist/es2019/monitoring/error.js +1 -1
- package/dist/es2019/ui/DropList/index.js +1 -1
- package/dist/es2019/utils/profiler/render-count.js +2 -0
- package/dist/esm/extensibility/Extension/Lozenge/EditToggle.js +22 -4
- package/dist/esm/hooks/useSharedPluginState.js +3 -0
- package/dist/esm/hooks/useSharedPluginStateSelector/index.js +2 -0
- package/dist/esm/hooks/useSharedPluginStateSelector/useSharedPluginStateSelector.js +108 -0
- package/dist/esm/monitoring/error.js +1 -1
- package/dist/esm/ui/DropList/index.js +1 -1
- package/dist/esm/utils/profiler/render-count.js +2 -0
- package/dist/types/hooks/useSharedPluginState.d.ts +5 -3
- package/dist/types/hooks/useSharedPluginStateSelector/index.d.ts +1 -0
- package/dist/types/hooks/useSharedPluginStateSelector/useSharedPluginStateSelector.d.ts +74 -0
- package/dist/types-ts4.5/hooks/useSharedPluginState.d.ts +5 -3
- package/dist/types-ts4.5/hooks/useSharedPluginStateSelector/index.d.ts +1 -0
- package/dist/types-ts4.5/hooks/useSharedPluginStateSelector/useSharedPluginStateSelector.d.ts +74 -0
- package/package.json +2 -1
- package/use-shared-plugin-state-selector/package.json +15 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# @atlaskit/editor-common
|
|
2
2
|
|
|
3
|
+
## 96.5.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#178536](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/178536)
|
|
8
|
+
[`2809409329363`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/2809409329363) -
|
|
9
|
+
Adds keyboard events to select/de-select the bodied macros EditToggle for accessibility
|
|
10
|
+
|
|
11
|
+
## 96.5.0
|
|
12
|
+
|
|
13
|
+
### Minor Changes
|
|
14
|
+
|
|
15
|
+
- [#175556](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/175556)
|
|
16
|
+
[`e883046c970ff`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/e883046c970ff) -
|
|
17
|
+
Introduces new usePluginStateSelector hook which can be used to efficiently listen to a slice of
|
|
18
|
+
an editor plugins state.
|
|
19
|
+
|
|
3
20
|
## 96.4.1
|
|
4
21
|
|
|
5
22
|
### Patch Changes
|
|
@@ -41,7 +41,11 @@ var buttonStyles = (0, _react2.css)({
|
|
|
41
41
|
font: "var(--ds-font-body, normal 400 14px/20px ui-sans-serif, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Ubuntu, system-ui, \"Helvetica Neue\", sans-serif)",
|
|
42
42
|
'&:hover': {
|
|
43
43
|
backgroundColor: "var(--ds-background-neutral-subtle-hovered, #091E420F)"
|
|
44
|
-
}
|
|
44
|
+
},
|
|
45
|
+
outlineColor: "var(--ds-border-focused, #388BFF)",
|
|
46
|
+
border: 'none',
|
|
47
|
+
backgroundColor: "var(--ds-background-neutral-subtle, #00000000)",
|
|
48
|
+
color: "var(--ds-text-subtle, #44546F)"
|
|
45
49
|
});
|
|
46
50
|
var showButtonContainerStyle = (0, _react2.css)({
|
|
47
51
|
opacity: 1
|
|
@@ -80,6 +84,11 @@ var EditToggle = exports.EditToggle = function EditToggle(_ref) {
|
|
|
80
84
|
var handleClick = (0, _react.useCallback)(function () {
|
|
81
85
|
setShowBodiedExtensionRendererView === null || setShowBodiedExtensionRendererView === void 0 || setShowBodiedExtensionRendererView(!showBodiedExtensionRendererView);
|
|
82
86
|
}, [showBodiedExtensionRendererView, setShowBodiedExtensionRendererView]);
|
|
87
|
+
var handleKeyDown = (0, _react.useCallback)(function (event) {
|
|
88
|
+
if (event.key === 'Enter') {
|
|
89
|
+
handleClick();
|
|
90
|
+
}
|
|
91
|
+
}, [handleClick]);
|
|
83
92
|
return (
|
|
84
93
|
// eslint-disable-next-line jsx-a11y/no-static-element-interactions
|
|
85
94
|
(0, _react2.jsx)("div", {
|
|
@@ -100,8 +109,10 @@ var EditToggle = exports.EditToggle = function EditToggle(_ref) {
|
|
|
100
109
|
},
|
|
101
110
|
onMouseLeave: function onMouseLeave() {
|
|
102
111
|
return setIsNodeHovered === null || setIsNodeHovered === void 0 ? void 0 : setIsNodeHovered(false);
|
|
103
|
-
}
|
|
104
|
-
|
|
112
|
+
},
|
|
113
|
+
tabIndex: -1
|
|
114
|
+
}, (0, _react2.jsx)("button", {
|
|
115
|
+
type: "button",
|
|
105
116
|
"data-testid": "edit-toggle"
|
|
106
117
|
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
|
|
107
118
|
,
|
|
@@ -109,7 +120,14 @@ var EditToggle = exports.EditToggle = function EditToggle(_ref) {
|
|
|
109
120
|
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
|
|
110
121
|
,
|
|
111
122
|
className: "extension-edit-toggle",
|
|
112
|
-
onClick: handleClick
|
|
123
|
+
onClick: handleClick,
|
|
124
|
+
onKeyDown: handleKeyDown,
|
|
125
|
+
onFocus: function onFocus() {
|
|
126
|
+
return setIsNodeHovered === null || setIsNodeHovered === void 0 ? void 0 : setIsNodeHovered(true);
|
|
127
|
+
},
|
|
128
|
+
onBlur: function onBlur() {
|
|
129
|
+
return setIsNodeHovered === null || setIsNodeHovered === void 0 ? void 0 : setIsNodeHovered(false);
|
|
130
|
+
}
|
|
113
131
|
}, (0, _react2.jsx)(_primitives.Flex, {
|
|
114
132
|
as: "span",
|
|
115
133
|
xcss: iconStyles
|
|
@@ -40,6 +40,9 @@ function useStaticPlugins(plugins) {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
/**
|
|
43
|
+
*
|
|
44
|
+
* NOTE: Generally you may want to use `usePluginStateSelector` over this which behaves similarly
|
|
45
|
+
* but selects a slice of the state which is more performant.
|
|
43
46
|
*
|
|
44
47
|
* ⚠️⚠️⚠️ This is a debounced hook ⚠️⚠️⚠️
|
|
45
48
|
* If the plugins you are listening to generate multiple shared states while the user is typing,
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
Object.defineProperty(exports, "useSharedPluginStateSelector", {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: function get() {
|
|
9
|
+
return _useSharedPluginStateSelector.useSharedPluginStateSelector;
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
var _useSharedPluginStateSelector = require("./useSharedPluginStateSelector");
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.useSharedPluginStateSelector = useSharedPluginStateSelector;
|
|
8
|
+
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
|
|
9
|
+
var _toArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toArray"));
|
|
10
|
+
var _react = require("react");
|
|
11
|
+
var _get = _interopRequireDefault(require("lodash/get"));
|
|
12
|
+
var _isEqual = _interopRequireDefault(require("lodash/isEqual"));
|
|
13
|
+
var _usePluginStateEffect = require("../usePluginStateEffect");
|
|
14
|
+
/**
|
|
15
|
+
* This is designed to iterate through an object to get the path of its result
|
|
16
|
+
* based on separation via "."
|
|
17
|
+
*
|
|
18
|
+
* Example:
|
|
19
|
+
* ```typescript
|
|
20
|
+
* type Test = { deepObject: { value: number } };
|
|
21
|
+
* // Type should be `"deepObject" | "deepObject.value"`
|
|
22
|
+
* type Result = NestedKeys<Test>;
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* This is designed to iterate through a path of an object to get the type of its result
|
|
28
|
+
* based on separation via "."
|
|
29
|
+
*
|
|
30
|
+
* Example:
|
|
31
|
+
* ```typescript
|
|
32
|
+
* type Test = { deepObject: { value: number } }
|
|
33
|
+
* // Type should be `number`
|
|
34
|
+
* type Result = Path<Test, 'deepObject.value'>
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
*
|
|
40
|
+
* ⚠️⚠️⚠️ This is a debounced hook ⚠️⚠️⚠️
|
|
41
|
+
* If the plugins you are listening to generate multiple shared states while the user is typing,
|
|
42
|
+
* your React Component will get only the last one.
|
|
43
|
+
*
|
|
44
|
+
* Used to return the current plugin state of input dependencies.
|
|
45
|
+
* It will recursively retrieve a slice of the state using a "." to separate
|
|
46
|
+
* parts of the state.
|
|
47
|
+
*
|
|
48
|
+
* Example:
|
|
49
|
+
*
|
|
50
|
+
* ```typescript
|
|
51
|
+
* const pluginA: NextEditorPlugin<
|
|
52
|
+
'pluginA',
|
|
53
|
+
{
|
|
54
|
+
sharedState: { deepObj: { value: number | undefined } };
|
|
55
|
+
}
|
|
56
|
+
>
|
|
57
|
+
* ```
|
|
58
|
+
* You can use `const value = useSharedPluginStateSelector(api, 'pluginA.deepObj.value')` to retrieve the value
|
|
59
|
+
*
|
|
60
|
+
* Example in plugin:
|
|
61
|
+
*
|
|
62
|
+
* ```typescript
|
|
63
|
+
* function ExampleContent({ api }: Props) {
|
|
64
|
+
* const title = useSharedPluginStateSelector(api, 'dog.title')
|
|
65
|
+
* return <p>{ title } { exampleState.description }</p>
|
|
66
|
+
* }
|
|
67
|
+
*
|
|
68
|
+
* const examplePlugin: NextEditorPlugin<'example', { dependencies: [typeof pluginDog] }> = ({ api }) => {
|
|
69
|
+
* return {
|
|
70
|
+
* name: 'example',
|
|
71
|
+
* contentComponent: () => <ExampleContent api={api} />
|
|
72
|
+
* }
|
|
73
|
+
* }
|
|
74
|
+
* ```
|
|
75
|
+
*
|
|
76
|
+
* NOTE: If you pass an invalid path, `undefined` will be returned
|
|
77
|
+
*
|
|
78
|
+
* @param api
|
|
79
|
+
* @param plugin
|
|
80
|
+
* @returns
|
|
81
|
+
*/
|
|
82
|
+
function useSharedPluginStateSelector(api, plugin) {
|
|
83
|
+
var transformer = (0, _react.useCallback)(function (pluginState) {
|
|
84
|
+
var _plugin$split = plugin.split('.'),
|
|
85
|
+
_plugin$split2 = (0, _toArray2.default)(_plugin$split),
|
|
86
|
+
pluginName = _plugin$split2[0],
|
|
87
|
+
properties = _plugin$split2.slice(1);
|
|
88
|
+
if (!pluginState || (properties === null || properties === void 0 ? void 0 : properties.length) === 0) {
|
|
89
|
+
return undefined;
|
|
90
|
+
}
|
|
91
|
+
return (0, _get.default)(pluginState === null || pluginState === void 0 ? void 0 : pluginState["".concat(pluginName, "State")], properties);
|
|
92
|
+
}, [plugin]);
|
|
93
|
+
var pluginNameArray = (0, _react.useMemo)(function () {
|
|
94
|
+
var _plugin$split3 = plugin.split('.'),
|
|
95
|
+
_plugin$split4 = (0, _slicedToArray2.default)(_plugin$split3, 1),
|
|
96
|
+
pluginName = _plugin$split4[0];
|
|
97
|
+
return [pluginName];
|
|
98
|
+
}, [plugin]);
|
|
99
|
+
return useSharedPluginStateSelectorInternal(api, pluginNameArray, transformer);
|
|
100
|
+
}
|
|
101
|
+
function useSharedPluginStateSelectorInternal(api, plugins, transformer) {
|
|
102
|
+
var _useState = (0, _react.useState)(),
|
|
103
|
+
_useState2 = (0, _slicedToArray2.default)(_useState, 2),
|
|
104
|
+
selectedPluginState = _useState2[0],
|
|
105
|
+
setSelectedPluginState = _useState2[1];
|
|
106
|
+
(0, _usePluginStateEffect.usePluginStateEffect)(api, plugins, function (pluginStates) {
|
|
107
|
+
// `pluginStates`: This is the same type through inference - but typescript doesn't recognise them as they are computed slightly differently
|
|
108
|
+
var transformedValue = transformer(pluginStates);
|
|
109
|
+
if (!(0, _isEqual.default)(transformedValue, selectedPluginState)) {
|
|
110
|
+
setSelectedPluginState(transformedValue);
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
return selectedPluginState;
|
|
114
|
+
}
|
|
@@ -17,7 +17,7 @@ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return
|
|
|
17
17
|
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
18
18
|
var SENTRY_DSN = 'https://0b10c8e02fb44d8796c047b102c9bee8@o55978.ingest.sentry.io/4505129224110080';
|
|
19
19
|
var packageName = 'editor-common'; // Sentry doesn't accept '/' in its releases https://docs.sentry.io/platforms/javascript/configuration/releases/
|
|
20
|
-
var packageVersion = "96.
|
|
20
|
+
var packageVersion = "96.5.1";
|
|
21
21
|
var sanitiseSentryEvents = function sanitiseSentryEvents(data, _hint) {
|
|
22
22
|
// Remove URL as it has UGC
|
|
23
23
|
// TODO: Sanitise the URL instead of just removing it
|
|
@@ -23,7 +23,7 @@ function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.
|
|
|
23
23
|
* @jsx jsx
|
|
24
24
|
*/ // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
|
|
25
25
|
var packageName = "@atlaskit/editor-common";
|
|
26
|
-
var packageVersion = "96.
|
|
26
|
+
var packageVersion = "96.5.1";
|
|
27
27
|
var halfFocusRing = 1;
|
|
28
28
|
var dropOffset = '0, 8';
|
|
29
29
|
var DropList = /*#__PURE__*/function (_Component) {
|
|
@@ -77,6 +77,7 @@ var RenderCountProfiler = exports.RenderCountProfiler = /*#__PURE__*/function ()
|
|
|
77
77
|
var componentId = _ref3.componentId;
|
|
78
78
|
var component = (_this$store$PROFILER_ = (_this$store3 = this.store) === null || _this$store3 === void 0 || (_this$store3 = _this$store3[PROFILER_KEY]) === null || _this$store3 === void 0 || (_this$store3 = _this$store3.components) === null || _this$store3 === void 0 ? void 0 : _this$store3[componentId]) !== null && _this$store$PROFILER_ !== void 0 ? _this$store$PROFILER_ : {};
|
|
79
79
|
var counters = [];
|
|
80
|
+
// eslint-disable-next-line guard-for-in
|
|
80
81
|
for (var instanceId in component) {
|
|
81
82
|
var counter = {
|
|
82
83
|
instanceId: instanceId,
|
|
@@ -93,6 +94,7 @@ var RenderCountProfiler = exports.RenderCountProfiler = /*#__PURE__*/function ()
|
|
|
93
94
|
var componentId = _ref4.componentId;
|
|
94
95
|
var component = (_this$store$PROFILER_2 = (_this$store4 = this.store) === null || _this$store4 === void 0 || (_this$store4 = _this$store4[PROFILER_KEY]) === null || _this$store4 === void 0 || (_this$store4 = _this$store4.components) === null || _this$store4 === void 0 ? void 0 : _this$store4[componentId]) !== null && _this$store$PROFILER_2 !== void 0 ? _this$store$PROFILER_2 : {};
|
|
95
96
|
var total = 0;
|
|
97
|
+
// eslint-disable-next-line guard-for-in
|
|
96
98
|
for (var instanceId in component) {
|
|
97
99
|
total += component[instanceId].count;
|
|
98
100
|
}
|
|
@@ -34,7 +34,11 @@ const buttonStyles = css({
|
|
|
34
34
|
font: "var(--ds-font-body, normal 400 14px/20px ui-sans-serif, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Ubuntu, system-ui, \"Helvetica Neue\", sans-serif)",
|
|
35
35
|
'&:hover': {
|
|
36
36
|
backgroundColor: "var(--ds-background-neutral-subtle-hovered, #091E420F)"
|
|
37
|
-
}
|
|
37
|
+
},
|
|
38
|
+
outlineColor: "var(--ds-border-focused, #388BFF)",
|
|
39
|
+
border: 'none',
|
|
40
|
+
backgroundColor: "var(--ds-background-neutral-subtle, #00000000)",
|
|
41
|
+
color: "var(--ds-text-subtle, #44546F)"
|
|
38
42
|
});
|
|
39
43
|
const showButtonContainerStyle = css({
|
|
40
44
|
opacity: 1
|
|
@@ -74,6 +78,11 @@ export const EditToggle = ({
|
|
|
74
78
|
const handleClick = useCallback(() => {
|
|
75
79
|
setShowBodiedExtensionRendererView === null || setShowBodiedExtensionRendererView === void 0 ? void 0 : setShowBodiedExtensionRendererView(!showBodiedExtensionRendererView);
|
|
76
80
|
}, [showBodiedExtensionRendererView, setShowBodiedExtensionRendererView]);
|
|
81
|
+
const handleKeyDown = useCallback(event => {
|
|
82
|
+
if (event.key === 'Enter') {
|
|
83
|
+
handleClick();
|
|
84
|
+
}
|
|
85
|
+
}, [handleClick]);
|
|
77
86
|
return (
|
|
78
87
|
// eslint-disable-next-line jsx-a11y/no-static-element-interactions
|
|
79
88
|
jsx("div", {
|
|
@@ -90,8 +99,10 @@ export const EditToggle = ({
|
|
|
90
99
|
// eslint-disable-next-line jsx-a11y/mouse-events-have-key-events
|
|
91
100
|
,
|
|
92
101
|
onMouseOver: () => setIsNodeHovered === null || setIsNodeHovered === void 0 ? void 0 : setIsNodeHovered(true),
|
|
93
|
-
onMouseLeave: () => setIsNodeHovered === null || setIsNodeHovered === void 0 ? void 0 : setIsNodeHovered(false)
|
|
94
|
-
|
|
102
|
+
onMouseLeave: () => setIsNodeHovered === null || setIsNodeHovered === void 0 ? void 0 : setIsNodeHovered(false),
|
|
103
|
+
tabIndex: -1
|
|
104
|
+
}, jsx("button", {
|
|
105
|
+
type: "button",
|
|
95
106
|
"data-testid": "edit-toggle"
|
|
96
107
|
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
|
|
97
108
|
,
|
|
@@ -99,7 +110,10 @@ export const EditToggle = ({
|
|
|
99
110
|
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
|
|
100
111
|
,
|
|
101
112
|
className: "extension-edit-toggle",
|
|
102
|
-
onClick: handleClick
|
|
113
|
+
onClick: handleClick,
|
|
114
|
+
onKeyDown: handleKeyDown,
|
|
115
|
+
onFocus: () => setIsNodeHovered === null || setIsNodeHovered === void 0 ? void 0 : setIsNodeHovered(true),
|
|
116
|
+
onBlur: () => setIsNodeHovered === null || setIsNodeHovered === void 0 ? void 0 : setIsNodeHovered(false)
|
|
103
117
|
}, jsx(Flex, {
|
|
104
118
|
as: "span",
|
|
105
119
|
xcss: iconStyles
|
|
@@ -25,6 +25,9 @@ function useStaticPlugins(plugins) {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
|
+
*
|
|
29
|
+
* NOTE: Generally you may want to use `usePluginStateSelector` over this which behaves similarly
|
|
30
|
+
* but selects a slice of the state which is more performant.
|
|
28
31
|
*
|
|
29
32
|
* ⚠️⚠️⚠️ This is a debounced hook ⚠️⚠️⚠️
|
|
30
33
|
* If the plugins you are listening to generate multiple shared states while the user is typing,
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { useState, useCallback, useMemo } from 'react';
|
|
2
|
+
import get from 'lodash/get';
|
|
3
|
+
import isEqual from 'lodash/isEqual';
|
|
4
|
+
import { usePluginStateEffect } from '../usePluginStateEffect';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* This is designed to iterate through an object to get the path of its result
|
|
8
|
+
* based on separation via "."
|
|
9
|
+
*
|
|
10
|
+
* Example:
|
|
11
|
+
* ```typescript
|
|
12
|
+
* type Test = { deepObject: { value: number } };
|
|
13
|
+
* // Type should be `"deepObject" | "deepObject.value"`
|
|
14
|
+
* type Result = NestedKeys<Test>;
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* This is designed to iterate through a path of an object to get the type of its result
|
|
20
|
+
* based on separation via "."
|
|
21
|
+
*
|
|
22
|
+
* Example:
|
|
23
|
+
* ```typescript
|
|
24
|
+
* type Test = { deepObject: { value: number } }
|
|
25
|
+
* // Type should be `number`
|
|
26
|
+
* type Result = Path<Test, 'deepObject.value'>
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
*
|
|
32
|
+
* ⚠️⚠️⚠️ This is a debounced hook ⚠️⚠️⚠️
|
|
33
|
+
* If the plugins you are listening to generate multiple shared states while the user is typing,
|
|
34
|
+
* your React Component will get only the last one.
|
|
35
|
+
*
|
|
36
|
+
* Used to return the current plugin state of input dependencies.
|
|
37
|
+
* It will recursively retrieve a slice of the state using a "." to separate
|
|
38
|
+
* parts of the state.
|
|
39
|
+
*
|
|
40
|
+
* Example:
|
|
41
|
+
*
|
|
42
|
+
* ```typescript
|
|
43
|
+
* const pluginA: NextEditorPlugin<
|
|
44
|
+
'pluginA',
|
|
45
|
+
{
|
|
46
|
+
sharedState: { deepObj: { value: number | undefined } };
|
|
47
|
+
}
|
|
48
|
+
>
|
|
49
|
+
* ```
|
|
50
|
+
* You can use `const value = useSharedPluginStateSelector(api, 'pluginA.deepObj.value')` to retrieve the value
|
|
51
|
+
*
|
|
52
|
+
* Example in plugin:
|
|
53
|
+
*
|
|
54
|
+
* ```typescript
|
|
55
|
+
* function ExampleContent({ api }: Props) {
|
|
56
|
+
* const title = useSharedPluginStateSelector(api, 'dog.title')
|
|
57
|
+
* return <p>{ title } { exampleState.description }</p>
|
|
58
|
+
* }
|
|
59
|
+
*
|
|
60
|
+
* const examplePlugin: NextEditorPlugin<'example', { dependencies: [typeof pluginDog] }> = ({ api }) => {
|
|
61
|
+
* return {
|
|
62
|
+
* name: 'example',
|
|
63
|
+
* contentComponent: () => <ExampleContent api={api} />
|
|
64
|
+
* }
|
|
65
|
+
* }
|
|
66
|
+
* ```
|
|
67
|
+
*
|
|
68
|
+
* NOTE: If you pass an invalid path, `undefined` will be returned
|
|
69
|
+
*
|
|
70
|
+
* @param api
|
|
71
|
+
* @param plugin
|
|
72
|
+
* @returns
|
|
73
|
+
*/
|
|
74
|
+
export function useSharedPluginStateSelector(api, plugin) {
|
|
75
|
+
const transformer = useCallback(pluginState => {
|
|
76
|
+
const [pluginName, ...properties] = plugin.split('.');
|
|
77
|
+
if (!pluginState || (properties === null || properties === void 0 ? void 0 : properties.length) === 0) {
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
80
|
+
return get(pluginState === null || pluginState === void 0 ? void 0 : pluginState[`${pluginName}State`], properties);
|
|
81
|
+
}, [plugin]);
|
|
82
|
+
const pluginNameArray = useMemo(() => {
|
|
83
|
+
const [pluginName] = plugin.split('.');
|
|
84
|
+
return [pluginName];
|
|
85
|
+
}, [plugin]);
|
|
86
|
+
return useSharedPluginStateSelectorInternal(api, pluginNameArray, transformer);
|
|
87
|
+
}
|
|
88
|
+
function useSharedPluginStateSelectorInternal(api, plugins, transformer) {
|
|
89
|
+
const [selectedPluginState, setSelectedPluginState] = useState();
|
|
90
|
+
usePluginStateEffect(api, plugins, pluginStates => {
|
|
91
|
+
// `pluginStates`: This is the same type through inference - but typescript doesn't recognise them as they are computed slightly differently
|
|
92
|
+
const transformedValue = transformer(pluginStates);
|
|
93
|
+
if (!isEqual(transformedValue, selectedPluginState)) {
|
|
94
|
+
setSelectedPluginState(transformedValue);
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
return selectedPluginState;
|
|
98
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { isFedRamp } from './environment';
|
|
2
2
|
const SENTRY_DSN = 'https://0b10c8e02fb44d8796c047b102c9bee8@o55978.ingest.sentry.io/4505129224110080';
|
|
3
3
|
const packageName = 'editor-common'; // Sentry doesn't accept '/' in its releases https://docs.sentry.io/platforms/javascript/configuration/releases/
|
|
4
|
-
const packageVersion = "96.
|
|
4
|
+
const packageVersion = "96.5.1";
|
|
5
5
|
const sanitiseSentryEvents = (data, _hint) => {
|
|
6
6
|
// Remove URL as it has UGC
|
|
7
7
|
// TODO: Sanitise the URL instead of just removing it
|
|
@@ -13,7 +13,7 @@ import withAnalyticsContext from '@atlaskit/analytics-next/withAnalyticsContext'
|
|
|
13
13
|
import withAnalyticsEvents from '@atlaskit/analytics-next/withAnalyticsEvents';
|
|
14
14
|
import Layer from '../Layer';
|
|
15
15
|
const packageName = "@atlaskit/editor-common";
|
|
16
|
-
const packageVersion = "96.
|
|
16
|
+
const packageVersion = "96.5.1";
|
|
17
17
|
const halfFocusRing = 1;
|
|
18
18
|
const dropOffset = '0, 8';
|
|
19
19
|
class DropList extends Component {
|
|
@@ -71,6 +71,7 @@ export class RenderCountProfiler {
|
|
|
71
71
|
var _this$store$PROFILER_, _this$store3, _this$store3$PROFILER, _this$store3$PROFILER2;
|
|
72
72
|
const component = (_this$store$PROFILER_ = (_this$store3 = this.store) === null || _this$store3 === void 0 ? void 0 : (_this$store3$PROFILER = _this$store3[PROFILER_KEY]) === null || _this$store3$PROFILER === void 0 ? void 0 : (_this$store3$PROFILER2 = _this$store3$PROFILER.components) === null || _this$store3$PROFILER2 === void 0 ? void 0 : _this$store3$PROFILER2[componentId]) !== null && _this$store$PROFILER_ !== void 0 ? _this$store$PROFILER_ : {};
|
|
73
73
|
const counters = [];
|
|
74
|
+
// eslint-disable-next-line guard-for-in
|
|
74
75
|
for (let instanceId in component) {
|
|
75
76
|
const counter = {
|
|
76
77
|
instanceId,
|
|
@@ -86,6 +87,7 @@ export class RenderCountProfiler {
|
|
|
86
87
|
var _this$store$PROFILER_2, _this$store4, _this$store4$PROFILER, _this$store4$PROFILER2;
|
|
87
88
|
const component = (_this$store$PROFILER_2 = (_this$store4 = this.store) === null || _this$store4 === void 0 ? void 0 : (_this$store4$PROFILER = _this$store4[PROFILER_KEY]) === null || _this$store4$PROFILER === void 0 ? void 0 : (_this$store4$PROFILER2 = _this$store4$PROFILER.components) === null || _this$store4$PROFILER2 === void 0 ? void 0 : _this$store4$PROFILER2[componentId]) !== null && _this$store$PROFILER_2 !== void 0 ? _this$store$PROFILER_2 : {};
|
|
88
89
|
let total = 0;
|
|
90
|
+
// eslint-disable-next-line guard-for-in
|
|
89
91
|
for (let instanceId in component) {
|
|
90
92
|
total += component[instanceId].count;
|
|
91
93
|
}
|
|
@@ -34,7 +34,11 @@ var buttonStyles = css({
|
|
|
34
34
|
font: "var(--ds-font-body, normal 400 14px/20px ui-sans-serif, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Ubuntu, system-ui, \"Helvetica Neue\", sans-serif)",
|
|
35
35
|
'&:hover': {
|
|
36
36
|
backgroundColor: "var(--ds-background-neutral-subtle-hovered, #091E420F)"
|
|
37
|
-
}
|
|
37
|
+
},
|
|
38
|
+
outlineColor: "var(--ds-border-focused, #388BFF)",
|
|
39
|
+
border: 'none',
|
|
40
|
+
backgroundColor: "var(--ds-background-neutral-subtle, #00000000)",
|
|
41
|
+
color: "var(--ds-text-subtle, #44546F)"
|
|
38
42
|
});
|
|
39
43
|
var showButtonContainerStyle = css({
|
|
40
44
|
opacity: 1
|
|
@@ -73,6 +77,11 @@ export var EditToggle = function EditToggle(_ref) {
|
|
|
73
77
|
var handleClick = useCallback(function () {
|
|
74
78
|
setShowBodiedExtensionRendererView === null || setShowBodiedExtensionRendererView === void 0 || setShowBodiedExtensionRendererView(!showBodiedExtensionRendererView);
|
|
75
79
|
}, [showBodiedExtensionRendererView, setShowBodiedExtensionRendererView]);
|
|
80
|
+
var handleKeyDown = useCallback(function (event) {
|
|
81
|
+
if (event.key === 'Enter') {
|
|
82
|
+
handleClick();
|
|
83
|
+
}
|
|
84
|
+
}, [handleClick]);
|
|
76
85
|
return (
|
|
77
86
|
// eslint-disable-next-line jsx-a11y/no-static-element-interactions
|
|
78
87
|
jsx("div", {
|
|
@@ -93,8 +102,10 @@ export var EditToggle = function EditToggle(_ref) {
|
|
|
93
102
|
},
|
|
94
103
|
onMouseLeave: function onMouseLeave() {
|
|
95
104
|
return setIsNodeHovered === null || setIsNodeHovered === void 0 ? void 0 : setIsNodeHovered(false);
|
|
96
|
-
}
|
|
97
|
-
|
|
105
|
+
},
|
|
106
|
+
tabIndex: -1
|
|
107
|
+
}, jsx("button", {
|
|
108
|
+
type: "button",
|
|
98
109
|
"data-testid": "edit-toggle"
|
|
99
110
|
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
|
|
100
111
|
,
|
|
@@ -102,7 +113,14 @@ export var EditToggle = function EditToggle(_ref) {
|
|
|
102
113
|
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
|
|
103
114
|
,
|
|
104
115
|
className: "extension-edit-toggle",
|
|
105
|
-
onClick: handleClick
|
|
116
|
+
onClick: handleClick,
|
|
117
|
+
onKeyDown: handleKeyDown,
|
|
118
|
+
onFocus: function onFocus() {
|
|
119
|
+
return setIsNodeHovered === null || setIsNodeHovered === void 0 ? void 0 : setIsNodeHovered(true);
|
|
120
|
+
},
|
|
121
|
+
onBlur: function onBlur() {
|
|
122
|
+
return setIsNodeHovered === null || setIsNodeHovered === void 0 ? void 0 : setIsNodeHovered(false);
|
|
123
|
+
}
|
|
106
124
|
}, jsx(Flex, {
|
|
107
125
|
as: "span",
|
|
108
126
|
xcss: iconStyles
|
|
@@ -33,6 +33,9 @@ function useStaticPlugins(plugins) {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
/**
|
|
36
|
+
*
|
|
37
|
+
* NOTE: Generally you may want to use `usePluginStateSelector` over this which behaves similarly
|
|
38
|
+
* but selects a slice of the state which is more performant.
|
|
36
39
|
*
|
|
37
40
|
* ⚠️⚠️⚠️ This is a debounced hook ⚠️⚠️⚠️
|
|
38
41
|
* If the plugins you are listening to generate multiple shared states while the user is typing,
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
2
|
+
import _toArray from "@babel/runtime/helpers/toArray";
|
|
3
|
+
import { useState, useCallback, useMemo } from 'react';
|
|
4
|
+
import get from 'lodash/get';
|
|
5
|
+
import isEqual from 'lodash/isEqual';
|
|
6
|
+
import { usePluginStateEffect } from '../usePluginStateEffect';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* This is designed to iterate through an object to get the path of its result
|
|
10
|
+
* based on separation via "."
|
|
11
|
+
*
|
|
12
|
+
* Example:
|
|
13
|
+
* ```typescript
|
|
14
|
+
* type Test = { deepObject: { value: number } };
|
|
15
|
+
* // Type should be `"deepObject" | "deepObject.value"`
|
|
16
|
+
* type Result = NestedKeys<Test>;
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* This is designed to iterate through a path of an object to get the type of its result
|
|
22
|
+
* based on separation via "."
|
|
23
|
+
*
|
|
24
|
+
* Example:
|
|
25
|
+
* ```typescript
|
|
26
|
+
* type Test = { deepObject: { value: number } }
|
|
27
|
+
* // Type should be `number`
|
|
28
|
+
* type Result = Path<Test, 'deepObject.value'>
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
*
|
|
34
|
+
* ⚠️⚠️⚠️ This is a debounced hook ⚠️⚠️⚠️
|
|
35
|
+
* If the plugins you are listening to generate multiple shared states while the user is typing,
|
|
36
|
+
* your React Component will get only the last one.
|
|
37
|
+
*
|
|
38
|
+
* Used to return the current plugin state of input dependencies.
|
|
39
|
+
* It will recursively retrieve a slice of the state using a "." to separate
|
|
40
|
+
* parts of the state.
|
|
41
|
+
*
|
|
42
|
+
* Example:
|
|
43
|
+
*
|
|
44
|
+
* ```typescript
|
|
45
|
+
* const pluginA: NextEditorPlugin<
|
|
46
|
+
'pluginA',
|
|
47
|
+
{
|
|
48
|
+
sharedState: { deepObj: { value: number | undefined } };
|
|
49
|
+
}
|
|
50
|
+
>
|
|
51
|
+
* ```
|
|
52
|
+
* You can use `const value = useSharedPluginStateSelector(api, 'pluginA.deepObj.value')` to retrieve the value
|
|
53
|
+
*
|
|
54
|
+
* Example in plugin:
|
|
55
|
+
*
|
|
56
|
+
* ```typescript
|
|
57
|
+
* function ExampleContent({ api }: Props) {
|
|
58
|
+
* const title = useSharedPluginStateSelector(api, 'dog.title')
|
|
59
|
+
* return <p>{ title } { exampleState.description }</p>
|
|
60
|
+
* }
|
|
61
|
+
*
|
|
62
|
+
* const examplePlugin: NextEditorPlugin<'example', { dependencies: [typeof pluginDog] }> = ({ api }) => {
|
|
63
|
+
* return {
|
|
64
|
+
* name: 'example',
|
|
65
|
+
* contentComponent: () => <ExampleContent api={api} />
|
|
66
|
+
* }
|
|
67
|
+
* }
|
|
68
|
+
* ```
|
|
69
|
+
*
|
|
70
|
+
* NOTE: If you pass an invalid path, `undefined` will be returned
|
|
71
|
+
*
|
|
72
|
+
* @param api
|
|
73
|
+
* @param plugin
|
|
74
|
+
* @returns
|
|
75
|
+
*/
|
|
76
|
+
export function useSharedPluginStateSelector(api, plugin) {
|
|
77
|
+
var transformer = useCallback(function (pluginState) {
|
|
78
|
+
var _plugin$split = plugin.split('.'),
|
|
79
|
+
_plugin$split2 = _toArray(_plugin$split),
|
|
80
|
+
pluginName = _plugin$split2[0],
|
|
81
|
+
properties = _plugin$split2.slice(1);
|
|
82
|
+
if (!pluginState || (properties === null || properties === void 0 ? void 0 : properties.length) === 0) {
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
return get(pluginState === null || pluginState === void 0 ? void 0 : pluginState["".concat(pluginName, "State")], properties);
|
|
86
|
+
}, [plugin]);
|
|
87
|
+
var pluginNameArray = useMemo(function () {
|
|
88
|
+
var _plugin$split3 = plugin.split('.'),
|
|
89
|
+
_plugin$split4 = _slicedToArray(_plugin$split3, 1),
|
|
90
|
+
pluginName = _plugin$split4[0];
|
|
91
|
+
return [pluginName];
|
|
92
|
+
}, [plugin]);
|
|
93
|
+
return useSharedPluginStateSelectorInternal(api, pluginNameArray, transformer);
|
|
94
|
+
}
|
|
95
|
+
function useSharedPluginStateSelectorInternal(api, plugins, transformer) {
|
|
96
|
+
var _useState = useState(),
|
|
97
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
98
|
+
selectedPluginState = _useState2[0],
|
|
99
|
+
setSelectedPluginState = _useState2[1];
|
|
100
|
+
usePluginStateEffect(api, plugins, function (pluginStates) {
|
|
101
|
+
// `pluginStates`: This is the same type through inference - but typescript doesn't recognise them as they are computed slightly differently
|
|
102
|
+
var transformedValue = transformer(pluginStates);
|
|
103
|
+
if (!isEqual(transformedValue, selectedPluginState)) {
|
|
104
|
+
setSelectedPluginState(transformedValue);
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
return selectedPluginState;
|
|
108
|
+
}
|
|
@@ -7,7 +7,7 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
|
|
|
7
7
|
import { isFedRamp } from './environment';
|
|
8
8
|
var SENTRY_DSN = 'https://0b10c8e02fb44d8796c047b102c9bee8@o55978.ingest.sentry.io/4505129224110080';
|
|
9
9
|
var packageName = 'editor-common'; // Sentry doesn't accept '/' in its releases https://docs.sentry.io/platforms/javascript/configuration/releases/
|
|
10
|
-
var packageVersion = "96.
|
|
10
|
+
var packageVersion = "96.5.1";
|
|
11
11
|
var sanitiseSentryEvents = function sanitiseSentryEvents(data, _hint) {
|
|
12
12
|
// Remove URL as it has UGC
|
|
13
13
|
// TODO: Sanitise the URL instead of just removing it
|
|
@@ -20,7 +20,7 @@ import withAnalyticsContext from '@atlaskit/analytics-next/withAnalyticsContext'
|
|
|
20
20
|
import withAnalyticsEvents from '@atlaskit/analytics-next/withAnalyticsEvents';
|
|
21
21
|
import Layer from '../Layer';
|
|
22
22
|
var packageName = "@atlaskit/editor-common";
|
|
23
|
-
var packageVersion = "96.
|
|
23
|
+
var packageVersion = "96.5.1";
|
|
24
24
|
var halfFocusRing = 1;
|
|
25
25
|
var dropOffset = '0, 8';
|
|
26
26
|
var DropList = /*#__PURE__*/function (_Component) {
|
|
@@ -70,6 +70,7 @@ export var RenderCountProfiler = /*#__PURE__*/function () {
|
|
|
70
70
|
var componentId = _ref3.componentId;
|
|
71
71
|
var component = (_this$store$PROFILER_ = (_this$store3 = this.store) === null || _this$store3 === void 0 || (_this$store3 = _this$store3[PROFILER_KEY]) === null || _this$store3 === void 0 || (_this$store3 = _this$store3.components) === null || _this$store3 === void 0 ? void 0 : _this$store3[componentId]) !== null && _this$store$PROFILER_ !== void 0 ? _this$store$PROFILER_ : {};
|
|
72
72
|
var counters = [];
|
|
73
|
+
// eslint-disable-next-line guard-for-in
|
|
73
74
|
for (var instanceId in component) {
|
|
74
75
|
var counter = {
|
|
75
76
|
instanceId: instanceId,
|
|
@@ -86,6 +87,7 @@ export var RenderCountProfiler = /*#__PURE__*/function () {
|
|
|
86
87
|
var componentId = _ref4.componentId;
|
|
87
88
|
var component = (_this$store$PROFILER_2 = (_this$store4 = this.store) === null || _this$store4 === void 0 || (_this$store4 = _this$store4[PROFILER_KEY]) === null || _this$store4 === void 0 || (_this$store4 = _this$store4.components) === null || _this$store4 === void 0 ? void 0 : _this$store4[componentId]) !== null && _this$store$PROFILER_2 !== void 0 ? _this$store$PROFILER_2 : {};
|
|
88
89
|
var total = 0;
|
|
90
|
+
// eslint-disable-next-line guard-for-in
|
|
89
91
|
for (var instanceId in component) {
|
|
90
92
|
total += component[instanceId].count;
|
|
91
93
|
}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import type { BasePluginDependenciesAPI, EditorInjectionAPI, ExtractInjectionAPI, ExtractPluginSharedState, NextEditorPlugin, NextEditorPluginMetadata } from '../types/next-editor-plugin';
|
|
2
|
-
type NamedPluginStatesFromInjectionAPI<API extends ExtractInjectionAPI<NextEditorPlugin<any, any>>, PluginNames extends string | number | symbol> = Readonly<{
|
|
2
|
+
export type NamedPluginStatesFromInjectionAPI<API extends ExtractInjectionAPI<NextEditorPlugin<any, any>>, PluginNames extends string | number | symbol> = Readonly<{
|
|
3
3
|
[K in PluginNames as `${K extends string ? K : never}State`]: API[K] extends BasePluginDependenciesAPI<any> | undefined ? Exclude<API[K], undefined> extends BasePluginDependenciesAPI<infer Metadata> ? Metadata extends NextEditorPluginMetadata ? ExtractPluginSharedState<Metadata> | undefined : never : never : never;
|
|
4
4
|
}>;
|
|
5
|
-
type ExtractPluginNames<API extends EditorInjectionAPI<any, any>> = keyof API;
|
|
5
|
+
export type ExtractPluginNames<API extends EditorInjectionAPI<any, any>> = keyof API;
|
|
6
6
|
/**
|
|
7
|
+
*
|
|
8
|
+
* NOTE: Generally you may want to use `usePluginStateSelector` over this which behaves similarly
|
|
9
|
+
* but selects a slice of the state which is more performant.
|
|
7
10
|
*
|
|
8
11
|
* ⚠️⚠️⚠️ This is a debounced hook ⚠️⚠️⚠️
|
|
9
12
|
* If the plugins you are listening to generate multiple shared states while the user is typing,
|
|
@@ -65,4 +68,3 @@ type ExtractPluginNames<API extends EditorInjectionAPI<any, any>> = keyof API;
|
|
|
65
68
|
* the values are the shared state exposed by that plugin.
|
|
66
69
|
*/
|
|
67
70
|
export declare function useSharedPluginState<API extends EditorInjectionAPI<any, any>, PluginNames extends ExtractPluginNames<API>>(injectionApi: API | null | undefined, plugins: PluginNames[]): NamedPluginStatesFromInjectionAPI<API, PluginNames>;
|
|
68
|
-
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useSharedPluginStateSelector } from './useSharedPluginStateSelector';
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { EditorInjectionAPI } from '../../types/next-editor-plugin';
|
|
2
|
+
type ExtractPluginNames<API extends EditorInjectionAPI<any, any>> = keyof API extends string ? keyof API : never;
|
|
3
|
+
/**
|
|
4
|
+
* This is designed to iterate through an object to get the path of its result
|
|
5
|
+
* based on separation via "."
|
|
6
|
+
*
|
|
7
|
+
* Example:
|
|
8
|
+
* ```typescript
|
|
9
|
+
* type Test = { deepObject: { value: number } };
|
|
10
|
+
* // Type should be `"deepObject" | "deepObject.value"`
|
|
11
|
+
* type Result = NestedKeys<Test>;
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
type NestedKeys<T> = {
|
|
15
|
+
[K in keyof T]: T[K] extends object ? T[K] extends any[] ? K extends string ? K : never : T[K] extends object ? K extends string ? K | `${K}.${NestedKeys<T[K]>}` : never : never : K extends string ? K : never;
|
|
16
|
+
}[keyof T];
|
|
17
|
+
/**
|
|
18
|
+
* This is designed to iterate through a path of an object to get the type of its result
|
|
19
|
+
* based on separation via "."
|
|
20
|
+
*
|
|
21
|
+
* Example:
|
|
22
|
+
* ```typescript
|
|
23
|
+
* type Test = { deepObject: { value: number } }
|
|
24
|
+
* // Type should be `number`
|
|
25
|
+
* type Result = Path<Test, 'deepObject.value'>
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
type Path<T, K extends string> = K extends `${infer Key}.${infer Rest}` ? Key extends keyof T ? Path<T[Key], Rest> : never : K extends keyof T ? T[K] : never;
|
|
29
|
+
/**
|
|
30
|
+
*
|
|
31
|
+
* ⚠️⚠️⚠️ This is a debounced hook ⚠️⚠️⚠️
|
|
32
|
+
* If the plugins you are listening to generate multiple shared states while the user is typing,
|
|
33
|
+
* your React Component will get only the last one.
|
|
34
|
+
*
|
|
35
|
+
* Used to return the current plugin state of input dependencies.
|
|
36
|
+
* It will recursively retrieve a slice of the state using a "." to separate
|
|
37
|
+
* parts of the state.
|
|
38
|
+
*
|
|
39
|
+
* Example:
|
|
40
|
+
*
|
|
41
|
+
* ```typescript
|
|
42
|
+
* const pluginA: NextEditorPlugin<
|
|
43
|
+
'pluginA',
|
|
44
|
+
{
|
|
45
|
+
sharedState: { deepObj: { value: number | undefined } };
|
|
46
|
+
}
|
|
47
|
+
>
|
|
48
|
+
* ```
|
|
49
|
+
* You can use `const value = useSharedPluginStateSelector(api, 'pluginA.deepObj.value')` to retrieve the value
|
|
50
|
+
*
|
|
51
|
+
* Example in plugin:
|
|
52
|
+
*
|
|
53
|
+
* ```typescript
|
|
54
|
+
* function ExampleContent({ api }: Props) {
|
|
55
|
+
* const title = useSharedPluginStateSelector(api, 'dog.title')
|
|
56
|
+
* return <p>{ title } { exampleState.description }</p>
|
|
57
|
+
* }
|
|
58
|
+
*
|
|
59
|
+
* const examplePlugin: NextEditorPlugin<'example', { dependencies: [typeof pluginDog] }> = ({ api }) => {
|
|
60
|
+
* return {
|
|
61
|
+
* name: 'example',
|
|
62
|
+
* contentComponent: () => <ExampleContent api={api} />
|
|
63
|
+
* }
|
|
64
|
+
* }
|
|
65
|
+
* ```
|
|
66
|
+
*
|
|
67
|
+
* NOTE: If you pass an invalid path, `undefined` will be returned
|
|
68
|
+
*
|
|
69
|
+
* @param api
|
|
70
|
+
* @param plugin
|
|
71
|
+
* @returns
|
|
72
|
+
*/
|
|
73
|
+
export declare function useSharedPluginStateSelector<API extends EditorInjectionAPI<any, any>, PluginName extends ExtractPluginNames<API>, SharedState extends ReturnType<Exclude<API[PluginName], null | undefined>['sharedState']['currentState']>, Key extends NestedKeys<Exclude<SharedState, null | undefined>>, Result extends Path<Exclude<SharedState, null | undefined>, Key>>(api: API | undefined | null, plugin: `${PluginName}.${Key}`): Result | undefined;
|
|
74
|
+
export {};
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import type { BasePluginDependenciesAPI, EditorInjectionAPI, ExtractInjectionAPI, ExtractPluginSharedState, NextEditorPlugin, NextEditorPluginMetadata } from '../types/next-editor-plugin';
|
|
2
|
-
type NamedPluginStatesFromInjectionAPI<API extends ExtractInjectionAPI<NextEditorPlugin<any, any>>, PluginNames extends string | number | symbol> = Readonly<{
|
|
2
|
+
export type NamedPluginStatesFromInjectionAPI<API extends ExtractInjectionAPI<NextEditorPlugin<any, any>>, PluginNames extends string | number | symbol> = Readonly<{
|
|
3
3
|
[K in PluginNames as `${K extends string ? K : never}State`]: API[K] extends BasePluginDependenciesAPI<any> | undefined ? Exclude<API[K], undefined> extends BasePluginDependenciesAPI<infer Metadata> ? Metadata extends NextEditorPluginMetadata ? ExtractPluginSharedState<Metadata> | undefined : never : never : never;
|
|
4
4
|
}>;
|
|
5
|
-
type ExtractPluginNames<API extends EditorInjectionAPI<any, any>> = keyof API;
|
|
5
|
+
export type ExtractPluginNames<API extends EditorInjectionAPI<any, any>> = keyof API;
|
|
6
6
|
/**
|
|
7
|
+
*
|
|
8
|
+
* NOTE: Generally you may want to use `usePluginStateSelector` over this which behaves similarly
|
|
9
|
+
* but selects a slice of the state which is more performant.
|
|
7
10
|
*
|
|
8
11
|
* ⚠️⚠️⚠️ This is a debounced hook ⚠️⚠️⚠️
|
|
9
12
|
* If the plugins you are listening to generate multiple shared states while the user is typing,
|
|
@@ -65,4 +68,3 @@ type ExtractPluginNames<API extends EditorInjectionAPI<any, any>> = keyof API;
|
|
|
65
68
|
* the values are the shared state exposed by that plugin.
|
|
66
69
|
*/
|
|
67
70
|
export declare function useSharedPluginState<API extends EditorInjectionAPI<any, any>, PluginNames extends ExtractPluginNames<API>>(injectionApi: API | null | undefined, plugins: PluginNames[]): NamedPluginStatesFromInjectionAPI<API, PluginNames>;
|
|
68
|
-
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useSharedPluginStateSelector } from './useSharedPluginStateSelector';
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { EditorInjectionAPI } from '../../types/next-editor-plugin';
|
|
2
|
+
type ExtractPluginNames<API extends EditorInjectionAPI<any, any>> = keyof API extends string ? keyof API : never;
|
|
3
|
+
/**
|
|
4
|
+
* This is designed to iterate through an object to get the path of its result
|
|
5
|
+
* based on separation via "."
|
|
6
|
+
*
|
|
7
|
+
* Example:
|
|
8
|
+
* ```typescript
|
|
9
|
+
* type Test = { deepObject: { value: number } };
|
|
10
|
+
* // Type should be `"deepObject" | "deepObject.value"`
|
|
11
|
+
* type Result = NestedKeys<Test>;
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
type NestedKeys<T> = {
|
|
15
|
+
[K in keyof T]: T[K] extends object ? T[K] extends any[] ? K extends string ? K : never : T[K] extends object ? K extends string ? K | `${K}.${NestedKeys<T[K]>}` : never : never : K extends string ? K : never;
|
|
16
|
+
}[keyof T];
|
|
17
|
+
/**
|
|
18
|
+
* This is designed to iterate through a path of an object to get the type of its result
|
|
19
|
+
* based on separation via "."
|
|
20
|
+
*
|
|
21
|
+
* Example:
|
|
22
|
+
* ```typescript
|
|
23
|
+
* type Test = { deepObject: { value: number } }
|
|
24
|
+
* // Type should be `number`
|
|
25
|
+
* type Result = Path<Test, 'deepObject.value'>
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
type Path<T, K extends string> = K extends `${infer Key}.${infer Rest}` ? Key extends keyof T ? Path<T[Key], Rest> : never : K extends keyof T ? T[K] : never;
|
|
29
|
+
/**
|
|
30
|
+
*
|
|
31
|
+
* ⚠️⚠️⚠️ This is a debounced hook ⚠️⚠️⚠️
|
|
32
|
+
* If the plugins you are listening to generate multiple shared states while the user is typing,
|
|
33
|
+
* your React Component will get only the last one.
|
|
34
|
+
*
|
|
35
|
+
* Used to return the current plugin state of input dependencies.
|
|
36
|
+
* It will recursively retrieve a slice of the state using a "." to separate
|
|
37
|
+
* parts of the state.
|
|
38
|
+
*
|
|
39
|
+
* Example:
|
|
40
|
+
*
|
|
41
|
+
* ```typescript
|
|
42
|
+
* const pluginA: NextEditorPlugin<
|
|
43
|
+
'pluginA',
|
|
44
|
+
{
|
|
45
|
+
sharedState: { deepObj: { value: number | undefined } };
|
|
46
|
+
}
|
|
47
|
+
>
|
|
48
|
+
* ```
|
|
49
|
+
* You can use `const value = useSharedPluginStateSelector(api, 'pluginA.deepObj.value')` to retrieve the value
|
|
50
|
+
*
|
|
51
|
+
* Example in plugin:
|
|
52
|
+
*
|
|
53
|
+
* ```typescript
|
|
54
|
+
* function ExampleContent({ api }: Props) {
|
|
55
|
+
* const title = useSharedPluginStateSelector(api, 'dog.title')
|
|
56
|
+
* return <p>{ title } { exampleState.description }</p>
|
|
57
|
+
* }
|
|
58
|
+
*
|
|
59
|
+
* const examplePlugin: NextEditorPlugin<'example', { dependencies: [typeof pluginDog] }> = ({ api }) => {
|
|
60
|
+
* return {
|
|
61
|
+
* name: 'example',
|
|
62
|
+
* contentComponent: () => <ExampleContent api={api} />
|
|
63
|
+
* }
|
|
64
|
+
* }
|
|
65
|
+
* ```
|
|
66
|
+
*
|
|
67
|
+
* NOTE: If you pass an invalid path, `undefined` will be returned
|
|
68
|
+
*
|
|
69
|
+
* @param api
|
|
70
|
+
* @param plugin
|
|
71
|
+
* @returns
|
|
72
|
+
*/
|
|
73
|
+
export declare function useSharedPluginStateSelector<API extends EditorInjectionAPI<any, any>, PluginName extends ExtractPluginNames<API>, SharedState extends ReturnType<Exclude<API[PluginName], null | undefined>['sharedState']['currentState']>, Key extends NestedKeys<Exclude<SharedState, null | undefined>>, Result extends Path<Exclude<SharedState, null | undefined>, Key>>(api: API | undefined | null, plugin: `${PluginName}.${Key}`): Result | undefined;
|
|
74
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/editor-common",
|
|
3
|
-
"version": "96.
|
|
3
|
+
"version": "96.5.1",
|
|
4
4
|
"description": "A package that contains common classes and components for editor and renderer",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"registry": "https://registry.npmjs.org/"
|
|
@@ -105,6 +105,7 @@
|
|
|
105
105
|
"./code-block": "./src/code-block/index.ts",
|
|
106
106
|
"./table": "./src/table/index.ts",
|
|
107
107
|
"./use-plugin-state-effect": "./src/hooks/usePluginStateEffect.ts",
|
|
108
|
+
"./use-shared-plugin-state-selector": "./src/hooks/useSharedPluginStateSelector/index.ts",
|
|
108
109
|
"./lazy-node-view": "./src/lazy-node-view/index.ts",
|
|
109
110
|
"./nesting": "./src/nesting/utilities.ts",
|
|
110
111
|
"./UNSAFE_do_not_use_editor_context": "./src/ui/EditorContext/index.ts"
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@atlaskit/editor-common/use-shared-plugin-state-selector",
|
|
3
|
+
"main": "../dist/cjs/hooks/useSharedPluginStateSelector/index.js",
|
|
4
|
+
"module": "../dist/esm/hooks/useSharedPluginStateSelector/index.js",
|
|
5
|
+
"module:es2019": "../dist/es2019/hooks/useSharedPluginStateSelector/index.js",
|
|
6
|
+
"sideEffects": false,
|
|
7
|
+
"types": "../dist/types/hooks/useSharedPluginStateSelector/index.d.ts",
|
|
8
|
+
"typesVersions": {
|
|
9
|
+
">=4.5 <5.4": {
|
|
10
|
+
"*": [
|
|
11
|
+
"../dist/types-ts4.5/hooks/useSharedPluginStateSelector/index.d.ts"
|
|
12
|
+
]
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|