@atlaskit/editor-plugin-mentions 13.2.0 → 13.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +81 -0
- package/dist/cjs/nodeviews/disabledTooltipRenderer.compiled.css +1 -0
- package/dist/cjs/nodeviews/disabledTooltipRenderer.js +193 -0
- package/dist/cjs/nodeviews/mentionNodeView.js +128 -12
- package/dist/cjs/pm-plugins/main.js +1 -1
- package/dist/es2019/nodeviews/disabledTooltipRenderer.compiled.css +1 -0
- package/dist/es2019/nodeviews/disabledTooltipRenderer.js +168 -0
- package/dist/es2019/nodeviews/mentionNodeView.js +123 -12
- package/dist/es2019/pm-plugins/main.js +1 -1
- package/dist/esm/nodeviews/disabledTooltipRenderer.compiled.css +1 -0
- package/dist/esm/nodeviews/disabledTooltipRenderer.js +184 -0
- package/dist/esm/nodeviews/mentionNodeView.js +128 -12
- package/dist/esm/pm-plugins/main.js +1 -1
- package/dist/types/nodeviews/disabledTooltipRenderer.d.ts +25 -0
- package/dist/types/nodeviews/mentionNodeView.d.ts +18 -1
- package/dist/types-ts4.5/nodeviews/disabledTooltipRenderer.d.ts +25 -0
- package/dist/types-ts4.5/nodeviews/mentionNodeView.d.ts +18 -1
- package/package.json +7 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,86 @@
|
|
|
1
1
|
# @atlaskit/editor-plugin-mentions
|
|
2
2
|
|
|
3
|
+
## 13.3.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies
|
|
8
|
+
|
|
9
|
+
## 13.3.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- [`971e92e232624`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/971e92e232624) -
|
|
14
|
+
Added a new `DISABLED` visual variant for mention chips so rendering surfaces (such as the editor
|
|
15
|
+
mentions plugin) can render a chip in a non-interactive disabled state with an explanatory
|
|
16
|
+
tooltip. Includes optional `MentionProvider` hooks that let consumers drive the disabled state
|
|
17
|
+
reactively and observe mention deletions.
|
|
18
|
+
|
|
19
|
+
**`@atlaskit/mention`**
|
|
20
|
+
- New `MentionType.DISABLED` enum value and matching style on `PrimitiveMention`.
|
|
21
|
+
- New optional `isDisabled` and `disabledTooltip` props on the React `<Mention>` component. When
|
|
22
|
+
`isDisabled` is set the chip becomes non-clickable, exposes `aria-disabled="true"`, remains
|
|
23
|
+
keyboard-focusable (`tabindex="0"`), and — when `disabledTooltip` is also set — is wrapped in an
|
|
24
|
+
ADS `<Tooltip>` whose content is mirrored into `aria-label` for screen readers.
|
|
25
|
+
- New `MentionDisabledState` (`{ disabled: boolean; tooltip?: string }`) and
|
|
26
|
+
`MentionDisabledStateInput` (`{ id: string }`) types, re-exported from `@atlaskit/mention` and
|
|
27
|
+
`@atlaskit/mention/resource`.
|
|
28
|
+
- New optional `MentionResource` config option `getMentionDisabledState` (forwarded by
|
|
29
|
+
`ContextMentionResource`) that surfaces through three new optional methods on the
|
|
30
|
+
`MentionProvider` interface:
|
|
31
|
+
- `getMentionDisabledState?(mention)` — predicate the editor calls to determine whether a chip
|
|
32
|
+
should render disabled.
|
|
33
|
+
- `subscribeToDisabledStateChanges?(listener)` — lets the editor re-evaluate the predicate when
|
|
34
|
+
the consumer's inputs change.
|
|
35
|
+
- `notifyMentionDestroyed?(mention)` — lets the consumer observe chip removals (e.g. to update
|
|
36
|
+
its source of truth).
|
|
37
|
+
|
|
38
|
+
All three methods are optional so existing `MentionProvider` implementations continue to compile
|
|
39
|
+
and behave identically.
|
|
40
|
+
|
|
41
|
+
**`@atlaskit/editor-plugin-mentions` + `@atlaskit/editor-core`**
|
|
42
|
+
- The mention `NodeView` now reads `MentionProvider.getMentionDisabledState?.({ id })` on every
|
|
43
|
+
state update and re-evaluates whenever `subscribeToDisabledStateChanges` notifies. When the
|
|
44
|
+
predicate returns `{ disabled: true }` the chip gets a new `.mention-disabled` class,
|
|
45
|
+
`aria-disabled="true"`, and an ADS `<Tooltip>` (anchored to the chip via `portalProviderAPI`)
|
|
46
|
+
carrying the `tooltip` text. The chip remains keyboard-focusable.
|
|
47
|
+
- The mention `NodeView.destroy()` calls `notifyMentionDestroyed?.({ id })` on the subscribed
|
|
48
|
+
provider so consumers can react to chip removals without depending on the editor's `onChange`.
|
|
49
|
+
- Added a matching `.editor-mention-primitive.mention-disabled` style in `@atlaskit/editor-core`
|
|
50
|
+
so the new class renders correctly inside the editor content container.
|
|
51
|
+
- Providers that don't implement the new optional methods are entirely unaffected.
|
|
52
|
+
|
|
53
|
+
**`@atlassian/conversation-assistant`, `@atlassian/conversation-assistant-widget` (chat store)**
|
|
54
|
+
- New `addSelectedAgentId({ conversationId, agentId })` action — append-only, no-dedup push onto
|
|
55
|
+
the conversation's `selectedAgentIds` history. Each call adds exactly one entry; duplicates are
|
|
56
|
+
preserved so the history is a 1-to-1 log of every agent chip currently in the editor.
|
|
57
|
+
- New `removeSelectedAgentId({ conversationId, agentId })` action — removes the **rightmost**
|
|
58
|
+
occurrence of an id (preserving order of other entries) for use when a single agent chip is
|
|
59
|
+
deleted from the editor.
|
|
60
|
+
- `setSelectedAgentIds` retains its wholesale-replace semantics (unchanged externally).
|
|
61
|
+
- The picker callback in `chat-input-refresh` is now wired to `addSelectedAgentId`; chip-deletion
|
|
62
|
+
is wired to `removeSelectedAgentId`. The active agent is always `selectedAgentIds.at(-1)`.
|
|
63
|
+
|
|
64
|
+
**`@atlassian/conversation-assistant-chat-prompt-input`**
|
|
65
|
+
- `useChatMentionResource` accepts new options `getSelectedAgentIds`, `disabledAgentTooltip`, and
|
|
66
|
+
`onAgentMentionDestroyed` that wire the new `MentionProvider` capabilities described above.
|
|
67
|
+
- `withAgentSupport` extended with the same options, plus a `notifyMentionDestroyed`
|
|
68
|
+
implementation that forwards to the consumer when a known agent chip is destroyed (sourced from
|
|
69
|
+
the editor `NodeView` rather than from `onChange`, which is not reliably called on every chat
|
|
70
|
+
surface).
|
|
71
|
+
- `<RovoChatPromptInput>` exposes new optional `selectedAgentIds`, `disabledAgentTooltip`, and
|
|
72
|
+
`onAgentMentionDeleted` props for consumers that want to drive the disabled-agent chip state
|
|
73
|
+
from their own store.
|
|
74
|
+
|
|
75
|
+
**`@atlassian/conversation-assistant-store`**
|
|
76
|
+
- JSDoc on the `selectedAgentIds` conversation field updated to document the new append-only /
|
|
77
|
+
rightmost-remove semantics and the canonical read pattern (`.at(-1)` for the active agent). No
|
|
78
|
+
runtime or type-shape change.
|
|
79
|
+
|
|
80
|
+
### Patch Changes
|
|
81
|
+
|
|
82
|
+
- Updated dependencies
|
|
83
|
+
|
|
3
84
|
## 13.2.0
|
|
4
85
|
|
|
5
86
|
### Minor Changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
._1e0cglyw{display:none}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/* disabledTooltipRenderer.tsx generated by @compiled/babel-plugin v0.39.1 */
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
5
|
+
var _typeof = require("@babel/runtime/helpers/typeof");
|
|
6
|
+
Object.defineProperty(exports, "__esModule", {
|
|
7
|
+
value: true
|
|
8
|
+
});
|
|
9
|
+
exports.disabledTooltipRenderer = void 0;
|
|
10
|
+
require("./disabledTooltipRenderer.compiled.css");
|
|
11
|
+
var _runtime = require("@compiled/react/runtime");
|
|
12
|
+
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
|
|
13
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
14
|
+
var _bindEventListener = require("bind-event-listener");
|
|
15
|
+
var _v = _interopRequireDefault(require("uuid/v4"));
|
|
16
|
+
var _tooltip = _interopRequireDefault(require("@atlaskit/tooltip"));
|
|
17
|
+
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); }
|
|
18
|
+
// eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- mirror existing renderer pattern
|
|
19
|
+
var styles = {
|
|
20
|
+
hiddenTrigger: "_1e0cglyw"
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* ADS `<Tooltip>` hands us a ref via its render-prop child. That ref may be
|
|
25
|
+
* either a callback ref or a mutable ref object — React supports both shapes
|
|
26
|
+
* and ADS's typing keeps both possible. This helper assigns the supplied
|
|
27
|
+
* element to whichever ref shape was provided so the tooltip ends up using
|
|
28
|
+
* the chip's bounding box for positioning and its DOM for trigger events.
|
|
29
|
+
*/
|
|
30
|
+
var assignRef = function assignRef(ref, element) {
|
|
31
|
+
if (typeof ref === 'function') {
|
|
32
|
+
ref(element);
|
|
33
|
+
} else if (ref) {
|
|
34
|
+
ref.current = element;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Names of the React-style trigger-prop handlers we forward from ADS
|
|
40
|
+
* `<Tooltip>` onto the chip element.
|
|
41
|
+
*/
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Maps each React-style trigger-prop handler ADS `<Tooltip>` hands us in its
|
|
45
|
+
* render-prop callback to the DOM event name we attach to the chip via
|
|
46
|
+
* `bind-event-listener`. The chip lives in the ProseMirror document and is
|
|
47
|
+
* not a React child of the tooltip, so we have to bridge React handlers to
|
|
48
|
+
* native event listeners ourselves.
|
|
49
|
+
*
|
|
50
|
+
* Names are listed in the same order ADS internally registers them.
|
|
51
|
+
*/
|
|
52
|
+
var TRIGGER_EVENT_MAP = [['onMouseOver', 'mouseover'], ['onMouseOut', 'mouseout'], ['onMouseMove', 'mousemove'], ['onMouseDown', 'mousedown'], ['onFocus', 'focusin'], ['onBlur', 'focusout']];
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Anchors an ADS `<Tooltip>` to a ProseMirror chip element that is **not** a
|
|
56
|
+
* React child of the tooltip. The chip itself stays in the PM document; this
|
|
57
|
+
* renderer mounts an always-present React subtree via `portalProviderAPI` whose
|
|
58
|
+
* sole job is to host the tooltip and forward the ADS-provided trigger ref +
|
|
59
|
+
* event handlers onto the chip.
|
|
60
|
+
*
|
|
61
|
+
* The forwarding is deliberate: ADS `<Tooltip>` expects to attach its hover /
|
|
62
|
+
* focus / blur listeners to its render-prop child, but our render-prop child
|
|
63
|
+
* is a `display: none` placeholder span that no real event can reach. We bridge
|
|
64
|
+
* those listeners to the chip via `addEventListener` so the tooltip opens and
|
|
65
|
+
* closes in response to the user actually interacting with the chip — keyboard
|
|
66
|
+
* focus, mouse hover, screen-reader focus, the lot.
|
|
67
|
+
*/
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Hook that mirrors ADS Tooltip's React trigger props onto a DOM element
|
|
71
|
+
* which is not a React child of the tooltip. Re-attaches whenever ADS hands
|
|
72
|
+
* us a fresh set of props (which happens on every render of the render-prop
|
|
73
|
+
* child) and cleans up on unmount.
|
|
74
|
+
*
|
|
75
|
+
* We use `bind-event-listener`'s `bindAll` rather than raw
|
|
76
|
+
* `addEventListener` / `removeEventListener` calls so the lifetime of every
|
|
77
|
+
* subscription is paired with a single `UnbindFn` — the AFM-mandated pattern
|
|
78
|
+
* for keeping listener bookkeeping leak-free.
|
|
79
|
+
*/
|
|
80
|
+
var useBridgedTriggerListeners = function useBridgedTriggerListeners(chip, triggerProps) {
|
|
81
|
+
(0, _react.useEffect)(function () {
|
|
82
|
+
// Build the bindAll bindings array out of only the handlers ADS actually
|
|
83
|
+
// supplied. Each React handler is wrapped in a thin adapter so the
|
|
84
|
+
// listener signature matches the native `EventListener` shape; ADS
|
|
85
|
+
// handlers ignore the synthetic-event-only fields they don't use
|
|
86
|
+
// (target, currentTarget), so passing the raw DOM event through
|
|
87
|
+
// `unknown` is safe in practice.
|
|
88
|
+
var bindings = TRIGGER_EVENT_MAP.flatMap(function (_ref) {
|
|
89
|
+
var _ref2 = (0, _slicedToArray2.default)(_ref, 2),
|
|
90
|
+
propName = _ref2[0],
|
|
91
|
+
eventName = _ref2[1];
|
|
92
|
+
var handler = triggerProps[propName];
|
|
93
|
+
if (!handler) {
|
|
94
|
+
return [];
|
|
95
|
+
}
|
|
96
|
+
return [{
|
|
97
|
+
type: eventName,
|
|
98
|
+
listener: function listener(event) {
|
|
99
|
+
handler(event);
|
|
100
|
+
}
|
|
101
|
+
}];
|
|
102
|
+
});
|
|
103
|
+
if (bindings.length === 0) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
var unbind = (0, _bindEventListener.bindAll)(chip, bindings);
|
|
107
|
+
return unbind;
|
|
108
|
+
}, [chip, triggerProps]);
|
|
109
|
+
};
|
|
110
|
+
var AnchoredTooltip = function AnchoredTooltip(_ref3) {
|
|
111
|
+
var subscribe = _ref3.subscribe,
|
|
112
|
+
getInitialTooltip = _ref3.getInitialTooltip,
|
|
113
|
+
referenceElement = _ref3.referenceElement;
|
|
114
|
+
var _useState = (0, _react.useState)(getInitialTooltip),
|
|
115
|
+
_useState2 = (0, _slicedToArray2.default)(_useState, 2),
|
|
116
|
+
tooltip = _useState2[0],
|
|
117
|
+
setTooltipState = _useState2[1];
|
|
118
|
+
(0, _react.useEffect)(function () {
|
|
119
|
+
return subscribe(setTooltipState);
|
|
120
|
+
}, [subscribe]);
|
|
121
|
+
if (!tooltip) {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
return /*#__PURE__*/_react.default.createElement(_tooltip.default, {
|
|
125
|
+
content: tooltip,
|
|
126
|
+
position: "top"
|
|
127
|
+
}, function (tooltipProps) {
|
|
128
|
+
return /*#__PURE__*/_react.default.createElement(TriggerBridge, {
|
|
129
|
+
referenceElement: referenceElement,
|
|
130
|
+
tooltipProps: tooltipProps
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Render-prop child for ADS `<Tooltip>`. The element it returns is a
|
|
137
|
+
* `display: none` placeholder that satisfies the render-prop API; the
|
|
138
|
+
* real trigger surface is the chip in the PM document, which receives
|
|
139
|
+
* both the ADS ref and the bridged event listeners via the side-effects
|
|
140
|
+
* declared on this component.
|
|
141
|
+
*/
|
|
142
|
+
var TriggerBridge = function TriggerBridge(_ref4) {
|
|
143
|
+
var referenceElement = _ref4.referenceElement,
|
|
144
|
+
tooltipProps = _ref4.tooltipProps;
|
|
145
|
+
useBridgedTriggerListeners(referenceElement, tooltipProps);
|
|
146
|
+
return /*#__PURE__*/_react.default.createElement("span", {
|
|
147
|
+
ref: function ref() {
|
|
148
|
+
return assignRef(tooltipProps.ref, referenceElement);
|
|
149
|
+
},
|
|
150
|
+
"aria-hidden": "true",
|
|
151
|
+
className: (0, _runtime.ax)([styles.hiddenTrigger])
|
|
152
|
+
});
|
|
153
|
+
};
|
|
154
|
+
var disabledTooltipRenderer = exports.disabledTooltipRenderer = function disabledTooltipRenderer(_ref5) {
|
|
155
|
+
var chipElement = _ref5.chipElement,
|
|
156
|
+
portalProviderAPI = _ref5.portalProviderAPI;
|
|
157
|
+
// eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- mirror existing renderer pattern
|
|
158
|
+
var key = (0, _v.default)();
|
|
159
|
+
var currentTooltip;
|
|
160
|
+
var listeners = new Set();
|
|
161
|
+
var broadcast = function broadcast() {
|
|
162
|
+
listeners.forEach(function (listener) {
|
|
163
|
+
return listener(currentTooltip);
|
|
164
|
+
});
|
|
165
|
+
};
|
|
166
|
+
var getInitialTooltip = function getInitialTooltip() {
|
|
167
|
+
return currentTooltip;
|
|
168
|
+
};
|
|
169
|
+
var subscribe = function subscribe(listener) {
|
|
170
|
+
listeners.add(listener);
|
|
171
|
+
return function () {
|
|
172
|
+
listeners.delete(listener);
|
|
173
|
+
};
|
|
174
|
+
};
|
|
175
|
+
var renderElement = function renderElement() {
|
|
176
|
+
return /*#__PURE__*/_react.default.createElement(AnchoredTooltip, {
|
|
177
|
+
referenceElement: chipElement,
|
|
178
|
+
getInitialTooltip: getInitialTooltip,
|
|
179
|
+
subscribe: subscribe
|
|
180
|
+
});
|
|
181
|
+
};
|
|
182
|
+
portalProviderAPI.render(renderElement, chipElement, key);
|
|
183
|
+
return {
|
|
184
|
+
setTooltip: function setTooltip(text) {
|
|
185
|
+
currentTooltip = text;
|
|
186
|
+
broadcast();
|
|
187
|
+
},
|
|
188
|
+
destroy: function destroy() {
|
|
189
|
+
portalProviderAPI.remove(key);
|
|
190
|
+
listeners.clear();
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
};
|
|
@@ -17,6 +17,7 @@ var _resource = require("@atlaskit/mention/resource");
|
|
|
17
17
|
var _types = require("@atlaskit/mention/types");
|
|
18
18
|
var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
|
|
19
19
|
var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
|
|
20
|
+
var _disabledTooltipRenderer = require("./disabledTooltipRenderer");
|
|
20
21
|
var _profileCardRenderer2 = require("./profileCardRenderer");
|
|
21
22
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
22
23
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
@@ -88,7 +89,10 @@ var handleProviderName = /*#__PURE__*/function () {
|
|
|
88
89
|
return _ref.apply(this, arguments);
|
|
89
90
|
};
|
|
90
91
|
}();
|
|
91
|
-
var getNewState = function getNewState(isHighlighted, isRestricted) {
|
|
92
|
+
var getNewState = function getNewState(isHighlighted, isRestricted, isDisabled) {
|
|
93
|
+
if (isDisabled) {
|
|
94
|
+
return 'disabled';
|
|
95
|
+
}
|
|
92
96
|
if (isHighlighted) {
|
|
93
97
|
return 'self';
|
|
94
98
|
}
|
|
@@ -103,7 +107,6 @@ var MentionNodeView = exports.MentionNodeView = /*#__PURE__*/function () {
|
|
|
103
107
|
_api$mention$sharedSt,
|
|
104
108
|
_this = this;
|
|
105
109
|
(0, _classCallCheck2.default)(this, MentionNodeView);
|
|
106
|
-
(0, _defineProperty2.default)(this, "state", 'default');
|
|
107
110
|
var options = config.options,
|
|
108
111
|
api = config.api,
|
|
109
112
|
portalProviderAPI = config.portalProviderAPI;
|
|
@@ -119,9 +122,11 @@ var MentionNodeView = exports.MentionNodeView = /*#__PURE__*/function () {
|
|
|
119
122
|
var _ref2 = (_api$mention$sharedSt = api === null || api === void 0 ? void 0 : api.mention.sharedState.currentState()) !== null && _api$mention$sharedSt !== void 0 ? _api$mention$sharedSt : {},
|
|
120
123
|
mentionProvider = _ref2.mentionProvider;
|
|
121
124
|
this.updateState(mentionProvider);
|
|
125
|
+
this.subscribeToProviderDisabledStateChanges(mentionProvider);
|
|
122
126
|
this.cleanup = api === null || api === void 0 ? void 0 : api.mention.sharedState.onChange(function (_ref3) {
|
|
123
127
|
var nextSharedState = _ref3.nextSharedState;
|
|
124
128
|
_this.updateState(nextSharedState === null || nextSharedState === void 0 ? void 0 : nextSharedState.mentionProvider);
|
|
129
|
+
_this.subscribeToProviderDisabledStateChanges(nextSharedState === null || nextSharedState === void 0 ? void 0 : nextSharedState.mentionProvider);
|
|
125
130
|
});
|
|
126
131
|
var _profileCardRenderer = (0, _profileCardRenderer2.profileCardRenderer)({
|
|
127
132
|
dom: dom,
|
|
@@ -147,10 +152,93 @@ var MentionNodeView = exports.MentionNodeView = /*#__PURE__*/function () {
|
|
|
147
152
|
}
|
|
148
153
|
return (0, _createClass2.default)(MentionNodeView, [{
|
|
149
154
|
key: "setClassList",
|
|
150
|
-
value: function setClassList(state) {
|
|
151
|
-
var _this$mentionPrimitiv, _this$mentionPrimitiv2;
|
|
155
|
+
value: function setClassList(state, disabledTooltip) {
|
|
156
|
+
var _this$mentionPrimitiv, _this$mentionPrimitiv2, _this$mentionPrimitiv3;
|
|
152
157
|
(_this$mentionPrimitiv = this.mentionPrimitiveElement) === null || _this$mentionPrimitiv === void 0 || _this$mentionPrimitiv.classList.toggle('mention-self', state === 'self');
|
|
153
158
|
(_this$mentionPrimitiv2 = this.mentionPrimitiveElement) === null || _this$mentionPrimitiv2 === void 0 || _this$mentionPrimitiv2.classList.toggle('mention-restricted', state === 'restricted');
|
|
159
|
+
(_this$mentionPrimitiv3 = this.mentionPrimitiveElement) === null || _this$mentionPrimitiv3 === void 0 || _this$mentionPrimitiv3.classList.toggle('mention-disabled', state === 'disabled');
|
|
160
|
+
// Mirror the React `<Mention>` a11y behaviour: when the chip is
|
|
161
|
+
// disabled, expose `aria-disabled` so assistive tech announces it as
|
|
162
|
+
// such. Also surface the tooltip text via `aria-label` so screen-reader
|
|
163
|
+
// users hear *why* the chip is disabled, matching the React `<Mention>`
|
|
164
|
+
// behaviour at `Mention/index.tsx` line 152.
|
|
165
|
+
if (this.domElement) {
|
|
166
|
+
if (state === 'disabled') {
|
|
167
|
+
this.domElement.setAttribute('aria-disabled', 'true');
|
|
168
|
+
if (disabledTooltip) {
|
|
169
|
+
var text = this.node.attrs.text || '@...';
|
|
170
|
+
this.domElement.setAttribute('aria-label', "".concat(text, " \u2014 ").concat(disabledTooltip));
|
|
171
|
+
}
|
|
172
|
+
} else {
|
|
173
|
+
this.domElement.removeAttribute('aria-disabled');
|
|
174
|
+
this.domElement.removeAttribute('aria-label');
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}, {
|
|
179
|
+
key: "getDisabledState",
|
|
180
|
+
value: function getDisabledState(mentionProvider) {
|
|
181
|
+
var _mentionProvider$getM;
|
|
182
|
+
var input = {
|
|
183
|
+
id: this.node.attrs.id
|
|
184
|
+
};
|
|
185
|
+
return mentionProvider === null || mentionProvider === void 0 || (_mentionProvider$getM = mentionProvider.getMentionDisabledState) === null || _mentionProvider$getM === void 0 ? void 0 : _mentionProvider$getM.call(mentionProvider, input);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Subscribes this NodeView to disabled-state-change notifications on the
|
|
190
|
+
* supplied provider so already-rendered chips can re-evaluate themselves
|
|
191
|
+
* when the consumer's predicate inputs change (e.g. the active agent
|
|
192
|
+
* selection toggling in Rovo Chat). No-op for providers that don't
|
|
193
|
+
* implement `subscribeToDisabledStateChanges`.
|
|
194
|
+
*
|
|
195
|
+
* Idempotent: re-calling with the same provider keeps the existing
|
|
196
|
+
* subscription; passing a different provider tears the old subscription
|
|
197
|
+
* down before attaching the new one. Safe to call from the sharedState
|
|
198
|
+
* `onChange` handler when the editor swaps providers.
|
|
199
|
+
*/
|
|
200
|
+
}, {
|
|
201
|
+
key: "subscribeToProviderDisabledStateChanges",
|
|
202
|
+
value: function subscribeToProviderDisabledStateChanges(mentionProvider) {
|
|
203
|
+
var _this$unsubscribeFrom,
|
|
204
|
+
_this2 = this;
|
|
205
|
+
if (this.subscribedProvider === mentionProvider) {
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
(_this$unsubscribeFrom = this.unsubscribeFromDisabledStateChanges) === null || _this$unsubscribeFrom === void 0 || _this$unsubscribeFrom.call(this);
|
|
209
|
+
this.unsubscribeFromDisabledStateChanges = undefined;
|
|
210
|
+
this.subscribedProvider = mentionProvider;
|
|
211
|
+
if (!(mentionProvider !== null && mentionProvider !== void 0 && mentionProvider.subscribeToDisabledStateChanges)) {
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
this.unsubscribeFromDisabledStateChanges = mentionProvider.subscribeToDisabledStateChanges(function () {
|
|
215
|
+
_this2.updateState(_this2.subscribedProvider);
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
}, {
|
|
219
|
+
key: "syncDisabledTooltip",
|
|
220
|
+
value: function syncDisabledTooltip(disabledState) {
|
|
221
|
+
// Capture the tooltip text into a local so the rest of the method can
|
|
222
|
+
// branch on a truthy string instead of re-asserting non-null fields
|
|
223
|
+
// off of `disabledState`.
|
|
224
|
+
var tooltipText = disabledState !== null && disabledState !== void 0 && disabledState.disabled ? disabledState.tooltip : undefined;
|
|
225
|
+
var chip = this.mentionPrimitiveElement;
|
|
226
|
+
var portalProviderAPI = this.config.portalProviderAPI;
|
|
227
|
+
if (!chip || !portalProviderAPI) {
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
if (tooltipText) {
|
|
231
|
+
if (!this.disabledTooltip) {
|
|
232
|
+
this.disabledTooltip = (0, _disabledTooltipRenderer.disabledTooltipRenderer)({
|
|
233
|
+
chipElement: chip,
|
|
234
|
+
portalProviderAPI: portalProviderAPI
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
this.disabledTooltip.setTooltip(tooltipText);
|
|
238
|
+
} else if (this.disabledTooltip) {
|
|
239
|
+
this.disabledTooltip.destroy();
|
|
240
|
+
this.disabledTooltip = undefined;
|
|
241
|
+
}
|
|
154
242
|
}
|
|
155
243
|
}, {
|
|
156
244
|
key: "setTextContent",
|
|
@@ -180,24 +268,34 @@ var MentionNodeView = exports.MentionNodeView = /*#__PURE__*/function () {
|
|
|
180
268
|
value: function () {
|
|
181
269
|
var _updateState = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(mentionProvider) {
|
|
182
270
|
var _mentionProvider$shou2, _this$config$options2;
|
|
183
|
-
var isHighlighted, newState, name;
|
|
271
|
+
var isHighlighted, disabledState, isDisabled, newState, disabledTooltip, name;
|
|
184
272
|
return _regenerator.default.wrap(function (_context2) {
|
|
185
273
|
while (1) switch (_context2.prev = _context2.next) {
|
|
186
274
|
case 0:
|
|
187
275
|
isHighlighted = (0, _expValEquals.expValEquals)('platform_editor_vc90_transition_mentions', 'isEnabled', true) ? this.shouldHighlightMention(mentionProvider) : (_mentionProvider$shou2 = mentionProvider === null || mentionProvider === void 0 ? void 0 : mentionProvider.shouldHighlightMention({
|
|
188
276
|
id: this.node.attrs.id
|
|
189
277
|
})) !== null && _mentionProvider$shou2 !== void 0 ? _mentionProvider$shou2 : false;
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
278
|
+
disabledState = this.getDisabledState(mentionProvider);
|
|
279
|
+
isDisabled = !!(disabledState !== null && disabledState !== void 0 && disabledState.disabled);
|
|
280
|
+
newState = getNewState(isHighlighted, (0, _types.isRestricted)(this.node.attrs.accessLevel), isDisabled);
|
|
281
|
+
disabledTooltip = disabledState !== null && disabledState !== void 0 && disabledState.disabled ? disabledState.tooltip : undefined; // `setClassList` always runs so the aria-label (which depends on the
|
|
282
|
+
// tooltip text) stays in sync when the tooltip reason changes while
|
|
283
|
+
// the chip remains disabled. State-change-only writes would leave a
|
|
284
|
+
// stale aria-label after a tooltip-text-only update.
|
|
285
|
+
this.setClassList(newState, disabledTooltip);
|
|
286
|
+
// Tooltip wiring runs every update (not just on state change) so that
|
|
287
|
+
// the tooltip text stays in sync if the disabled reason changes while
|
|
288
|
+
// the chip is already disabled.
|
|
289
|
+
this.syncDisabledTooltip(disabledState);
|
|
195
290
|
_context2.next = 1;
|
|
196
291
|
return handleProviderName(mentionProvider, this.node);
|
|
197
292
|
case 1:
|
|
198
293
|
name = _context2.sent;
|
|
199
294
|
this.setTextContent(name);
|
|
200
|
-
|
|
295
|
+
// Only overwrite the disabled-state aria-label with the name-based one
|
|
296
|
+
// when the chip is NOT disabled; otherwise the disabled reason set in
|
|
297
|
+
// `setClassList` would be silently clobbered, regressing a11y.
|
|
298
|
+
if (name && this.domElement && (_this$config$options2 = this.config.options) !== null && _this$config$options2 !== void 0 && _this$config$options2.profilecardProvider && newState !== 'disabled') {
|
|
201
299
|
this.domElement.setAttribute('aria-label', getAccessibilityLabelFromName(name));
|
|
202
300
|
}
|
|
203
301
|
case 2:
|
|
@@ -236,9 +334,27 @@ var MentionNodeView = exports.MentionNodeView = /*#__PURE__*/function () {
|
|
|
236
334
|
}, {
|
|
237
335
|
key: "destroy",
|
|
238
336
|
value: function destroy() {
|
|
239
|
-
var _this$cleanup, _this$destroyProfileC;
|
|
337
|
+
var _this$cleanup, _this$destroyProfileC, _this$disabledTooltip, _this$unsubscribeFrom2;
|
|
338
|
+
// Surface the destruction to the provider before tearing down so the
|
|
339
|
+
// chat layer can react (e.g. drop the agent id from `selectedAgentIds`).
|
|
340
|
+
// This is the lowest-level deletion signal — fires for backspace,
|
|
341
|
+
// select-and-delete, programmatic doc replaces, and editor unmount.
|
|
342
|
+
try {
|
|
343
|
+
var _this$subscribedProvi, _this$subscribedProvi2;
|
|
344
|
+
(_this$subscribedProvi = this.subscribedProvider) === null || _this$subscribedProvi === void 0 || (_this$subscribedProvi2 = _this$subscribedProvi.notifyMentionDestroyed) === null || _this$subscribedProvi2 === void 0 || _this$subscribedProvi2.call(_this$subscribedProvi, {
|
|
345
|
+
id: this.node.attrs.id
|
|
346
|
+
});
|
|
347
|
+
} catch (_error) {
|
|
348
|
+
// Defensive: never let consumer-side notification errors prevent
|
|
349
|
+
// the NodeView from cleaning up its own resources below.
|
|
350
|
+
}
|
|
240
351
|
(_this$cleanup = this.cleanup) === null || _this$cleanup === void 0 || _this$cleanup.call(this);
|
|
241
352
|
(_this$destroyProfileC = this.destroyProfileCard) === null || _this$destroyProfileC === void 0 || _this$destroyProfileC.call(this);
|
|
353
|
+
(_this$disabledTooltip = this.disabledTooltip) === null || _this$disabledTooltip === void 0 || _this$disabledTooltip.destroy();
|
|
354
|
+
this.disabledTooltip = undefined;
|
|
355
|
+
(_this$unsubscribeFrom2 = this.unsubscribeFromDisabledStateChanges) === null || _this$unsubscribeFrom2 === void 0 || _this$unsubscribeFrom2.call(this);
|
|
356
|
+
this.unsubscribeFromDisabledStateChanges = undefined;
|
|
357
|
+
this.subscribedProvider = undefined;
|
|
242
358
|
}
|
|
243
359
|
}, {
|
|
244
360
|
key: "deselectNode",
|
|
@@ -32,7 +32,7 @@ var ACTIONS = exports.ACTIONS = {
|
|
|
32
32
|
var AGENT_USER_TYPES = new Set(['APP', 'AGENT']);
|
|
33
33
|
var AI_STREAMING_TRANSFORMATION_META_KEY = 'isAIStreamingTransformation';
|
|
34
34
|
var PACKAGE_NAME = "@atlaskit/editor-plugin-mentions";
|
|
35
|
-
var PACKAGE_VERSION = "13.
|
|
35
|
+
var PACKAGE_VERSION = "13.3.0";
|
|
36
36
|
var setProvider = function setProvider(provider) {
|
|
37
37
|
return function (state, dispatch) {
|
|
38
38
|
if (dispatch) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
._1e0cglyw{display:none}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/* disabledTooltipRenderer.tsx generated by @compiled/babel-plugin v0.39.1 */
|
|
2
|
+
import "./disabledTooltipRenderer.compiled.css";
|
|
3
|
+
import { ax, ix } from "@compiled/react/runtime";
|
|
4
|
+
import React, { useEffect, useState } from 'react';
|
|
5
|
+
import { bindAll } from 'bind-event-listener';
|
|
6
|
+
// eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- mirror existing renderer pattern
|
|
7
|
+
import uuid from 'uuid/v4';
|
|
8
|
+
import Tooltip from '@atlaskit/tooltip';
|
|
9
|
+
const styles = {
|
|
10
|
+
hiddenTrigger: "_1e0cglyw"
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* ADS `<Tooltip>` hands us a ref via its render-prop child. That ref may be
|
|
15
|
+
* either a callback ref or a mutable ref object — React supports both shapes
|
|
16
|
+
* and ADS's typing keeps both possible. This helper assigns the supplied
|
|
17
|
+
* element to whichever ref shape was provided so the tooltip ends up using
|
|
18
|
+
* the chip's bounding box for positioning and its DOM for trigger events.
|
|
19
|
+
*/
|
|
20
|
+
const assignRef = (ref, element) => {
|
|
21
|
+
if (typeof ref === 'function') {
|
|
22
|
+
ref(element);
|
|
23
|
+
} else if (ref) {
|
|
24
|
+
ref.current = element;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Names of the React-style trigger-prop handlers we forward from ADS
|
|
30
|
+
* `<Tooltip>` onto the chip element.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Maps each React-style trigger-prop handler ADS `<Tooltip>` hands us in its
|
|
35
|
+
* render-prop callback to the DOM event name we attach to the chip via
|
|
36
|
+
* `bind-event-listener`. The chip lives in the ProseMirror document and is
|
|
37
|
+
* not a React child of the tooltip, so we have to bridge React handlers to
|
|
38
|
+
* native event listeners ourselves.
|
|
39
|
+
*
|
|
40
|
+
* Names are listed in the same order ADS internally registers them.
|
|
41
|
+
*/
|
|
42
|
+
const TRIGGER_EVENT_MAP = [['onMouseOver', 'mouseover'], ['onMouseOut', 'mouseout'], ['onMouseMove', 'mousemove'], ['onMouseDown', 'mousedown'], ['onFocus', 'focusin'], ['onBlur', 'focusout']];
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Anchors an ADS `<Tooltip>` to a ProseMirror chip element that is **not** a
|
|
46
|
+
* React child of the tooltip. The chip itself stays in the PM document; this
|
|
47
|
+
* renderer mounts an always-present React subtree via `portalProviderAPI` whose
|
|
48
|
+
* sole job is to host the tooltip and forward the ADS-provided trigger ref +
|
|
49
|
+
* event handlers onto the chip.
|
|
50
|
+
*
|
|
51
|
+
* The forwarding is deliberate: ADS `<Tooltip>` expects to attach its hover /
|
|
52
|
+
* focus / blur listeners to its render-prop child, but our render-prop child
|
|
53
|
+
* is a `display: none` placeholder span that no real event can reach. We bridge
|
|
54
|
+
* those listeners to the chip via `addEventListener` so the tooltip opens and
|
|
55
|
+
* closes in response to the user actually interacting with the chip — keyboard
|
|
56
|
+
* focus, mouse hover, screen-reader focus, the lot.
|
|
57
|
+
*/
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Hook that mirrors ADS Tooltip's React trigger props onto a DOM element
|
|
61
|
+
* which is not a React child of the tooltip. Re-attaches whenever ADS hands
|
|
62
|
+
* us a fresh set of props (which happens on every render of the render-prop
|
|
63
|
+
* child) and cleans up on unmount.
|
|
64
|
+
*
|
|
65
|
+
* We use `bind-event-listener`'s `bindAll` rather than raw
|
|
66
|
+
* `addEventListener` / `removeEventListener` calls so the lifetime of every
|
|
67
|
+
* subscription is paired with a single `UnbindFn` — the AFM-mandated pattern
|
|
68
|
+
* for keeping listener bookkeeping leak-free.
|
|
69
|
+
*/
|
|
70
|
+
const useBridgedTriggerListeners = (chip, triggerProps) => {
|
|
71
|
+
useEffect(() => {
|
|
72
|
+
// Build the bindAll bindings array out of only the handlers ADS actually
|
|
73
|
+
// supplied. Each React handler is wrapped in a thin adapter so the
|
|
74
|
+
// listener signature matches the native `EventListener` shape; ADS
|
|
75
|
+
// handlers ignore the synthetic-event-only fields they don't use
|
|
76
|
+
// (target, currentTarget), so passing the raw DOM event through
|
|
77
|
+
// `unknown` is safe in practice.
|
|
78
|
+
const bindings = TRIGGER_EVENT_MAP.flatMap(([propName, eventName]) => {
|
|
79
|
+
const handler = triggerProps[propName];
|
|
80
|
+
if (!handler) {
|
|
81
|
+
return [];
|
|
82
|
+
}
|
|
83
|
+
return [{
|
|
84
|
+
type: eventName,
|
|
85
|
+
listener: event => {
|
|
86
|
+
handler(event);
|
|
87
|
+
}
|
|
88
|
+
}];
|
|
89
|
+
});
|
|
90
|
+
if (bindings.length === 0) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const unbind = bindAll(chip, bindings);
|
|
94
|
+
return unbind;
|
|
95
|
+
}, [chip, triggerProps]);
|
|
96
|
+
};
|
|
97
|
+
const AnchoredTooltip = ({
|
|
98
|
+
subscribe,
|
|
99
|
+
getInitialTooltip,
|
|
100
|
+
referenceElement
|
|
101
|
+
}) => {
|
|
102
|
+
const [tooltip, setTooltipState] = useState(getInitialTooltip);
|
|
103
|
+
useEffect(() => subscribe(setTooltipState), [subscribe]);
|
|
104
|
+
if (!tooltip) {
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
return /*#__PURE__*/React.createElement(Tooltip, {
|
|
108
|
+
content: tooltip,
|
|
109
|
+
position: "top"
|
|
110
|
+
}, tooltipProps => /*#__PURE__*/React.createElement(TriggerBridge, {
|
|
111
|
+
referenceElement: referenceElement,
|
|
112
|
+
tooltipProps: tooltipProps
|
|
113
|
+
}));
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Render-prop child for ADS `<Tooltip>`. The element it returns is a
|
|
118
|
+
* `display: none` placeholder that satisfies the render-prop API; the
|
|
119
|
+
* real trigger surface is the chip in the PM document, which receives
|
|
120
|
+
* both the ADS ref and the bridged event listeners via the side-effects
|
|
121
|
+
* declared on this component.
|
|
122
|
+
*/
|
|
123
|
+
const TriggerBridge = ({
|
|
124
|
+
referenceElement,
|
|
125
|
+
tooltipProps
|
|
126
|
+
}) => {
|
|
127
|
+
useBridgedTriggerListeners(referenceElement, tooltipProps);
|
|
128
|
+
return /*#__PURE__*/React.createElement("span", {
|
|
129
|
+
ref: () => assignRef(tooltipProps.ref, referenceElement),
|
|
130
|
+
"aria-hidden": "true",
|
|
131
|
+
className: ax([styles.hiddenTrigger])
|
|
132
|
+
});
|
|
133
|
+
};
|
|
134
|
+
export const disabledTooltipRenderer = ({
|
|
135
|
+
chipElement,
|
|
136
|
+
portalProviderAPI
|
|
137
|
+
}) => {
|
|
138
|
+
// eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- mirror existing renderer pattern
|
|
139
|
+
const key = uuid();
|
|
140
|
+
let currentTooltip;
|
|
141
|
+
const listeners = new Set();
|
|
142
|
+
const broadcast = () => {
|
|
143
|
+
listeners.forEach(listener => listener(currentTooltip));
|
|
144
|
+
};
|
|
145
|
+
const getInitialTooltip = () => currentTooltip;
|
|
146
|
+
const subscribe = listener => {
|
|
147
|
+
listeners.add(listener);
|
|
148
|
+
return () => {
|
|
149
|
+
listeners.delete(listener);
|
|
150
|
+
};
|
|
151
|
+
};
|
|
152
|
+
const renderElement = () => /*#__PURE__*/React.createElement(AnchoredTooltip, {
|
|
153
|
+
referenceElement: chipElement,
|
|
154
|
+
getInitialTooltip: getInitialTooltip,
|
|
155
|
+
subscribe: subscribe
|
|
156
|
+
});
|
|
157
|
+
portalProviderAPI.render(renderElement, chipElement, key);
|
|
158
|
+
return {
|
|
159
|
+
setTooltip(text) {
|
|
160
|
+
currentTooltip = text;
|
|
161
|
+
broadcast();
|
|
162
|
+
},
|
|
163
|
+
destroy() {
|
|
164
|
+
portalProviderAPI.remove(key);
|
|
165
|
+
listeners.clear();
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
};
|