@atlaskit/editor-common 122.3.3 → 122.4.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.
Files changed (44) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/cjs/ai-messages/ai-suggestions.js +5 -0
  3. package/dist/cjs/compiled-migration/withCompiledMigration.js +18 -20
  4. package/dist/cjs/extensibility/ExtensionNodeWrapper.js +13 -0
  5. package/dist/cjs/extensibility/GeneratedContentReveal.compiled.css +53 -0
  6. package/dist/cjs/extensibility/GeneratedContentReveal.js +146 -0
  7. package/dist/cjs/extensibility/extensionNodeView.js +6 -2
  8. package/dist/cjs/extensibility/nativeEmbedExtension.js +19 -0
  9. package/dist/cjs/extensibility/useNativeEmbedSettled.js +56 -0
  10. package/dist/cjs/monitoring/error.js +1 -1
  11. package/dist/cjs/react-node-view/getInlineNodeViewProducer.js +10 -12
  12. package/dist/cjs/ui/DropList/index.js +1 -1
  13. package/dist/es2019/ai-messages/ai-suggestions.js +5 -0
  14. package/dist/es2019/compiled-migration/withCompiledMigration.js +17 -17
  15. package/dist/es2019/extensibility/ExtensionNodeWrapper.js +12 -0
  16. package/dist/es2019/extensibility/GeneratedContentReveal.compiled.css +53 -0
  17. package/dist/es2019/extensibility/GeneratedContentReveal.js +121 -0
  18. package/dist/es2019/extensibility/extensionNodeView.js +6 -2
  19. package/dist/es2019/extensibility/nativeEmbedExtension.js +14 -0
  20. package/dist/es2019/extensibility/useNativeEmbedSettled.js +49 -0
  21. package/dist/es2019/monitoring/error.js +1 -1
  22. package/dist/es2019/react-node-view/getInlineNodeViewProducer.js +9 -14
  23. package/dist/es2019/ui/DropList/index.js +1 -1
  24. package/dist/esm/ai-messages/ai-suggestions.js +5 -0
  25. package/dist/esm/compiled-migration/withCompiledMigration.js +18 -16
  26. package/dist/esm/extensibility/ExtensionNodeWrapper.js +13 -0
  27. package/dist/esm/extensibility/GeneratedContentReveal.compiled.css +53 -0
  28. package/dist/esm/extensibility/GeneratedContentReveal.js +138 -0
  29. package/dist/esm/extensibility/extensionNodeView.js +6 -2
  30. package/dist/esm/extensibility/nativeEmbedExtension.js +14 -0
  31. package/dist/esm/extensibility/useNativeEmbedSettled.js +51 -0
  32. package/dist/esm/monitoring/error.js +1 -1
  33. package/dist/esm/react-node-view/getInlineNodeViewProducer.js +9 -14
  34. package/dist/esm/ui/DropList/index.js +1 -1
  35. package/dist/types/ai-messages/ai-suggestions.d.ts +5 -0
  36. package/dist/types/compiled-migration/withCompiledMigration.d.ts +8 -6
  37. package/dist/types/extensibility/ExtensionNodeWrapper.d.ts +7 -1
  38. package/dist/types/extensibility/GeneratedContentReveal.d.ts +13 -0
  39. package/dist/types/extensibility/extensionNodeView.d.ts +2 -0
  40. package/dist/types/extensibility/nativeEmbedExtension.d.ts +10 -0
  41. package/dist/types/extensibility/useNativeEmbedSettled.d.ts +12 -0
  42. package/dist/types/react-node-view/getInlineNodeViewProducer.d.ts +0 -4
  43. package/extensibility/native-embed/package.json +10 -0
  44. package/package.json +5 -5
@@ -10,6 +10,7 @@ import { css, jsx } from '@emotion/react';
10
10
  import classnames from 'classnames';
11
11
  import { ZERO_WIDTH_SPACE } from '../whitespace';
12
12
  import { ExtensionSSRReactContextsProvider } from './ExtensionSSRReactContextsProvider';
13
+ import { GeneratedContentReveal } from './GeneratedContentReveal';
13
14
  const styles = css({
14
15
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors -- Ignored via go/DSP-18766
15
16
  '&.inline-extension': {
@@ -20,6 +21,8 @@ const styles = css({
20
21
  position: 'relative'
21
22
  }
22
23
  });
24
+
25
+ // Mirrored by the reveal span in `GeneratedContentReveal`; keep the two in step.
23
26
  const hoverStyles = css({
24
27
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors, @atlaskit/ui-styling-standard/no-unsafe-selectors
25
28
  ':has(.extension-label:hover) .extension-container, :has(.extension-edit-toggle-container:hover) .extension-container': {
@@ -63,11 +66,20 @@ export const ExtensionNodeWrapper = ({
63
66
  children,
64
67
  nodeType,
65
68
  macroInteractionDesignFeatureFlags,
69
+ generatedContentMotion = false,
66
70
  intl
67
71
  }) => {
68
72
  const {
69
73
  showMacroInteractionDesignUpdates
70
74
  } = macroInteractionDesignFeatureFlags || {};
75
+
76
+ // Fixed for the node view's lifetime: switching would remount the subtree and reload the embed.
77
+ if (generatedContentMotion) {
78
+ return jsx(GeneratedContentReveal, {
79
+ intl: intl,
80
+ showMacroInteractionDesignUpdates: showMacroInteractionDesignUpdates
81
+ }, children);
82
+ }
71
83
  const wrapperClassNames = classnames({
72
84
  'inline-extension': nodeType === 'inlineExtension' && showMacroInteractionDesignUpdates,
73
85
  relative: showMacroInteractionDesignUpdates
@@ -0,0 +1,53 @@
1
+ ._10i01bym [data-native-embed-card-wrapper=true]{animation-name:var(--ds-keyframe-fade-in,FadeIn0to100)}
2
+ ._10t9kb7n:has(.extension-label:hover) .extension-edit-toggle-container{opacity:1}
3
+ ._114yglyw [data-testid$="--loading-overlay"]{display:none}
4
+ ._147ai9qs [data-native-embed-card-wrapper=true]{animation-duration:var(--ds-duration-medium,.2s)}
5
+ ._15k3glyw:has(.extension-edit-toggle-container:hover) .extension-label{box-shadow:none}
6
+ ._17sh1wug:has(.extension-edit-toggle-container:hover) .extension-label.always-hide-label{cursor:auto}
7
+ ._17w9indk iframe:not([data-native-embed-card-wrapper=true] iframe){animation-timing-function:var(--ds-easing-out-practical,cubic-bezier(.4,1,.6,1))}
8
+ ._18m915vq{overflow-y:hidden}
9
+ ._1a2e1j9a:has(.extension-edit-toggle-container:hover) .extension-label.with-bodied-macro-live-page-styles{background-color:var(--ds-background-input,#fff)}
10
+ ._1e0c1ule{display:block}
11
+ ._1fdfidpf .extension-label:hover.always-hide-label{opacity:0}
12
+ ._1ghxysee:has(.extension-container:hover) .extension-label{background-color:var(--ds-background-accent-gray-subtlest,#f0f1f2)}
13
+ ._1i8c1j9a:has(.extension-container:hover) .extension-label.with-bodied-macro-live-page-styles{background-color:var(--ds-background-input,#fff)}
14
+ ._1jbo15uc iframe:not([data-native-embed-card-wrapper=true] iframe){animation-delay:var(--ds-duration-xlong,.4s)}
15
+ ._1kr5kb7n:has(.extension-container:hover) .extension-edit-toggle-container{opacity:1}
16
+ ._1nuetlke:has(.extension-container:hover) .extension-label{cursor:pointer}
17
+ ._1p7l15uc [data-native-embed-card-wrapper=true]{animation-delay:var(--ds-duration-xlong,.4s)}
18
+ ._1pfgidpf:has(.extension-container:hover) .extension-label.always-hide-label{opacity:0}
19
+ ._1pglindk{animation-timing-function:var(--ds-easing-out-practical,cubic-bezier(.4,1,.6,1))}
20
+ ._1qac1nu9:has(.extension-container:hover) .extension-icon{display:inline}
21
+ ._1reo15vq{overflow-x:hidden}
22
+ ._1si41wug:has(.extension-container:hover) .extension-label.always-hide-label{cursor:auto}
23
+ ._1tr2ynbm:has(.extension-edit-toggle-container:hover) .extension-container{box-shadow:0 0 0 1px var(--ds-border-input,#8c8f97)}
24
+ ._1vs61nu9:has(.extension-label:hover) .extension-icon{display:inline}
25
+ ._26lx1tsb .extension-label:hover.with-bodied-macro-live-page-styles{box-shadow:0 0 0 1px var(--ds-border,#0b120e24)}
26
+ ._2z44kb7n:has(.extension-edit-toggle-container:hover) .extension-label{opacity:1}
27
+ ._54r11nu9:has(.extension-edit-toggle-container:hover) .extension-icon{display:inline}
28
+ ._5sag15uc{animation-duration:var(--ds-duration-xlong,.4s)}
29
+ ._9sz11bym iframe:not([data-native-embed-card-wrapper=true] iframe){animation-name:var(--ds-keyframe-fade-in,FadeIn0to100)}
30
+ ._bcikkb7n:has(.extension-container:hover) .extension-label{opacity:1}
31
+ ._c71lidpf{max-height:0}
32
+ ._d1oeglyw:has(.extension-container:hover) .extension-label{box-shadow:none}
33
+ ._decvtlke:has(.extension-edit-toggle-container:hover) .extension-label{cursor:pointer}
34
+ ._gp9p1hrf iframe:not([data-native-embed-card-wrapper=true] iframe){animation-fill-mode:both}
35
+ ._j7hq1k3l{animation-name:k1legk7d}
36
+ ._jl0d1tsb:has(.extension-edit-toggle-container:hover) .extension-label.with-bodied-macro-live-page-styles{box-shadow:0 0 0 1px var(--ds-border,#0b120e24)}
37
+ ._kqswh2mm{position:relative}
38
+ ._ks721tsb:has(.extension-container:hover) .extension-label.with-bodied-macro-live-page-styles{box-shadow:0 0 0 1px var(--ds-border,#0b120e24)}
39
+ ._lbjpindk [data-native-embed-card-wrapper=true]{animation-timing-function:var(--ds-easing-out-practical,cubic-bezier(.4,1,.6,1))}
40
+ ._lwlpi9qs iframe:not([data-native-embed-card-wrapper=true] iframe){animation-duration:var(--ds-duration-medium,.2s)}
41
+ ._mi5m1wug .extension-label:hover.always-hide-label{cursor:auto}
42
+ ._okd3ysee:has(.extension-edit-toggle-container:hover) .extension-label{background-color:var(--ds-background-accent-gray-subtlest,#f0f1f2)}
43
+ ._pjh31hrf [data-native-embed-card-wrapper=true]{animation-fill-mode:both}
44
+ ._x3ro1j9a .extension-label:hover.with-bodied-macro-live-page-styles{background-color:var(--ds-background-input,#fff)}
45
+ ._xajsynbm:has(.extension-label:hover) .extension-container{box-shadow:0 0 0 1px var(--ds-border-input,#8c8f97)}
46
+ ._y7o7idpf:has(.extension-edit-toggle-container:hover) .extension-label.always-hide-label{opacity:0}
47
+ ._10pdkb7n .extension-edit-toggle-container:hover{opacity:1}
48
+ ._1er3glyw .extension-label:hover{box-shadow:none}
49
+ ._1ql7tlke .extension-label:hover{cursor:pointer}
50
+ ._1tmrkb7n .extension-label:hover{opacity:1}
51
+ ._dmn9ysee .extension-label:hover{background-color:var(--ds-background-accent-gray-subtlest,#f0f1f2)}
52
+ @keyframes k1legk7d{0%{max-height:0}to{max-height:var(--extension-reveal-height)}}
53
+ @media (prefers-reduced-motion:reduce){._2hwzru3m{animation-duration:0s}._dxfxru3m [data-native-embed-card-wrapper=true]{animation-duration:0s}._log5ru3m iframe:not([data-native-embed-card-wrapper=true] iframe){animation-duration:0s}._1pz3ru3m [data-native-embed-card-wrapper=true]{animation-delay:0s}._9hrrru3m iframe:not([data-native-embed-card-wrapper=true] iframe){animation-delay:0s}}
@@ -0,0 +1,121 @@
1
+ /* GeneratedContentReveal.tsx generated by @compiled/babel-plugin v3.0.1 */
2
+ import "./GeneratedContentReveal.compiled.css";
3
+ import { ax, ix } from "@compiled/react/runtime";
4
+ import React, { useCallback, useEffect, useState } from 'react';
5
+ import { ExtensionSSRReactContextsProvider } from './ExtensionSSRReactContextsProvider';
6
+ import { useNativeEmbedSettled } from './useNativeEmbedSettled';
7
+
8
+ /*
9
+ * Animates a native embed into the document once it has loaded.
10
+ *
11
+ * 1. `collapsed` — clipped to zero height and `inert`. The embed loads behind it, full size but
12
+ * unseen, with its own loading overlay hidden.
13
+ * 2. `useNativeEmbedSettled` calls back once the embed has finished loading.
14
+ * 3. `revealing` — the measured height goes into `--extension-reveal-height` and the node animates
15
+ * open (400ms).
16
+ * 4. The embed fades in (200ms), delayed so it follows the opening instead of overlapping it.
17
+ * 5. `open` — on `animationend`, when the content first becomes visible, `inert` is dropped.
18
+ *
19
+ * Failure paths: never settles → `READY_TIMEOUT_MS` opens it and the embed's overlay reappears;
20
+ * fails with no frame → still settles and opens; no `animationend` → `REVEAL_TIMEOUT_MS`. Reduced
21
+ * motion runs the same steps with zero-length animations, so `animationend` still fires.
22
+ *
23
+ * Renders the wrapper span itself, in place of the default one in `ExtensionNodeWrapper`, so the
24
+ * reveal styles sit on the element editor-core reaches through `> span >` chains from the node view
25
+ * root. It therefore carries the default span's `relative` class and hover chrome as well.
26
+ */
27
+
28
+ /** Long, because a MAUI app has to boot and render first. Reaching it means the signal is broken. */
29
+ const READY_TIMEOUT_MS = 30_000;
30
+
31
+ /** For when no `animationend` arrives. Must exceed the reveal. */
32
+ const REVEAL_TIMEOUT_MS = 1000;
33
+
34
+ /** Set inline from the measured content height just before the animation runs. */
35
+ const REVEAL_HEIGHT_VARIABLE = '--extension-reveal-height';
36
+ const relativeStyles = null;
37
+
38
+ // Mirrors the default span's hover chrome in `ExtensionNodeWrapper`; keep the two in step.
39
+ const hoverStyles = null;
40
+
41
+ /**
42
+ * Animates `max-height`, so the rendered height is `min(content, max-height)` and overshooting is
43
+ * harmless — the measurement is taken before the embed has settled on its size. A measurement is
44
+ * needed because the embed writes a definite inline `height` onto `.extension-container`.
45
+ */
46
+ const openHeight = null;
47
+
48
+ // `display: block` because `overflow` and `max-height` do not apply to an inline span.
49
+ const clippedStyles = null;
50
+
51
+ /**
52
+ * Shut, and with the embed's own loading overlay hidden, so only one loading state shows. Only while
53
+ * closed: once open the embed shows its own progress again, which a node opened by the fail-safe
54
+ * timeout needs. Hiding the overlay here keeps `data-native-embed-loading` set, which is the signal
55
+ * the reveal waits on.
56
+ */
57
+ const collapsedStyles = null;
58
+ const revealingStyles = null;
59
+
60
+ // Two selectors because MAUI renders a bare iframe and others nest theirs in the card wrapper; the
61
+ // second excludes that nested case so the same content is not faded twice.
62
+ const embedContentEnteringStyles = null;
63
+
64
+ /** Mirrored onto `data-extension-reveal`. */
65
+
66
+ export const GeneratedContentReveal = ({
67
+ children,
68
+ intl,
69
+ showMacroInteractionDesignUpdates
70
+ }) => {
71
+ // Held in state so the effects below run once the span exists.
72
+ const [wrapperElement, setWrapperElement] = useState(null);
73
+ const [state, setState] = useState('collapsed');
74
+
75
+ // Only a collapsed node opens, so whichever of the readiness signal and the fail-safe timer
76
+ // comes second changes nothing. The measurement is repeated harmlessly in that case.
77
+ const startRevealing = useCallback(() => {
78
+ // The clipped wrapper's `scrollHeight` is the height its content wants.
79
+ wrapperElement === null || wrapperElement === void 0 ? void 0 : wrapperElement.style.setProperty(REVEAL_HEIGHT_VARIABLE, `${wrapperElement.scrollHeight}px`);
80
+ setState(current => current === 'collapsed' ? 'revealing' : current);
81
+ }, [wrapperElement]);
82
+
83
+ // Step 2 → 3.
84
+ useNativeEmbedSettled(wrapperElement, startRevealing);
85
+
86
+ // Set once the span exists; `startRevealing` only changes with it.
87
+ useEffect(() => {
88
+ const timer = setTimeout(startRevealing, READY_TIMEOUT_MS);
89
+ return () => clearTimeout(timer);
90
+ }, [startRevealing]);
91
+ useEffect(() => {
92
+ if (state !== 'revealing') {
93
+ return;
94
+ }
95
+ const timer = setTimeout(() => setState('open'), REVEAL_TIMEOUT_MS);
96
+ return () => clearTimeout(timer);
97
+ }, [state]);
98
+
99
+ // Clipped content, and content waiting out the fade's delay, are invisible but still focusable.
100
+ // Set as an attribute because `inert` is absent from the React 18 JSX types.
101
+ useEffect(() => {
102
+ wrapperElement === null || wrapperElement === void 0 ? void 0 : wrapperElement.toggleAttribute('inert', state !== 'open');
103
+ }, [state, wrapperElement]);
104
+ const onAnimationEnd = useCallback(event => {
105
+ // The extension's own content animates too, and those events bubble.
106
+ if (event.target === event.currentTarget) {
107
+ setState('open');
108
+ }
109
+ }, []);
110
+ return /*#__PURE__*/React.createElement(ExtensionSSRReactContextsProvider, {
111
+ intl: intl
112
+ }, /*#__PURE__*/React.createElement("span", {
113
+ "data-testid": "extension-node-wrapper",
114
+ "data-extension-reveal": state,
115
+ ref: setWrapperElement
116
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- the block controls and the SSR cleanup find the wrapper by `span.relative`
117
+ ,
118
+ className: ax(["_1tr2ynbm _xajsynbm _1tmrkb7n _bcikkb7n _2z44kb7n _dmn9ysee _1ghxysee _okd3ysee _1er3glyw _d1oeglyw _15k3glyw _1ql7tlke _1nuetlke _decvtlke _1fdfidpf _1pfgidpf _y7o7idpf _mi5m1wug _1si41wug _17sh1wug _x3ro1j9a _1i8c1j9a _1a2e1j9a _26lx1tsb _ks721tsb _jl0d1tsb _1qac1nu9 _54r11nu9 _1vs61nu9 _10pdkb7n _1kr5kb7n _10t9kb7n", showMacroInteractionDesignUpdates && "_kqswh2mm", state !== 'open' && "_1reo15vq _18m915vq _1e0c1ule", state === 'collapsed' && "_c71lidpf _114yglyw", state === 'revealing' && "", state === 'revealing' && "_j7hq1k3l _5sag15uc _1pglindk _2hwzru3m", state !== 'collapsed' && "_10i01bym _9sz11bym _147ai9qs _lwlpi9qs _lbjpindk _17w9indk _1p7l15uc _1jbo15uc _pjh31hrf _gp9p1hrf _dxfxru3m _log5ru3m _1pz3ru3m _9hrrru3m", showMacroInteractionDesignUpdates ? 'relative' : undefined]),
119
+ onAnimationEnd: onAnimationEnd
120
+ }, children));
121
+ };
@@ -6,6 +6,7 @@ import { isSSR } from '../core-utils';
6
6
  import ReactNodeView from '../react-node-view';
7
7
  import { Extension } from './Extension';
8
8
  import { ExtensionNodeWrapper } from './ExtensionNodeWrapper';
9
+ import { isNativeEmbedExtension } from './nativeEmbedExtension';
9
10
  /**
10
11
  * Allowlists of extension keys + layout
11
12
  * Currently, only toc with default layout allows to skip React render.
@@ -252,7 +253,7 @@ export class ExtensionNode extends ReactNodeView {
252
253
  };
253
254
  }
254
255
  render(props, forwardRef) {
255
- var _props$extensionNodeV;
256
+ var _props$extensionNodeV, _props$extensionNodeV2;
256
257
  // While sitting on SSR DOM, skip the React portal — see {@link didReuseSsrDom}.
257
258
  if (this.didReuseSsrDom) {
258
259
  return null;
@@ -261,6 +262,9 @@ export class ExtensionNode extends ReactNodeView {
261
262
  intl: props.intl,
262
263
  nodeType: this.node.type.name,
263
264
  macroInteractionDesignFeatureFlags: props.macroInteractionDesignFeatureFlags
265
+ // Only native embeds animate in; the reveal waits on the embed's own loading state.
266
+ ,
267
+ generatedContentMotion: !!((_props$extensionNodeV = props.extensionNodeViewOptions) !== null && _props$extensionNodeV !== void 0 && _props$extensionNodeV.allowAIGeneratedContentMotion) && isNativeEmbedExtension(this.node)
264
268
  }, /*#__PURE__*/React.createElement(Extension, {
265
269
  editorView: this.view,
266
270
  node: this.node,
@@ -277,7 +281,7 @@ export class ExtensionNode extends ReactNodeView {
277
281
  handleContentDOMRef: forwardRef,
278
282
  extensionHandlers: props.extensionHandlers,
279
283
  extensionLoadingHandlers: props.extensionLoadingHandlers,
280
- editorAppearance: (_props$extensionNodeV = props.extensionNodeViewOptions) === null || _props$extensionNodeV === void 0 ? void 0 : _props$extensionNodeV.appearance,
284
+ editorAppearance: (_props$extensionNodeV2 = props.extensionNodeViewOptions) === null || _props$extensionNodeV2 === void 0 ? void 0 : _props$extensionNodeV2.appearance,
281
285
  pluginInjectionApi: props.pluginInjectionApi,
282
286
  macroInteractionDesignFeatureFlags: props.macroInteractionDesignFeatureFlags,
283
287
  showLivePagesBodiedMacrosRendererView: props.showLivePagesBodiedMacrosRendererView,
@@ -0,0 +1,14 @@
1
+ import { NATIVE_EMBED_EXTENSION_KEY, NATIVE_EMBED_EXTENSION_TYPE } from '../extensions/manifest-helpers';
2
+
3
+ /**
4
+ * Whether a node is a native embed: the block `extension` that `editor-plugin-native-embeds` renders
5
+ * as an iframe. Bodied, multi-bodied and inline extensions do not qualify.
6
+ *
7
+ * The key can carry leading segments (`…:native-embed:database`), so it is matched with `includes`.
8
+ * `editor-plugin-native-embeds` and `editor-plugin-card` hold equivalent predicates; neither can be
9
+ * imported here, as both depend on this package.
10
+ */
11
+ export const isNativeEmbedExtension = node => {
12
+ var _node$attrs, _node$attrs2;
13
+ return node.type.name === 'extension' && ((_node$attrs = node.attrs) === null || _node$attrs === void 0 ? void 0 : _node$attrs.extensionType) === NATIVE_EMBED_EXTENSION_TYPE && typeof ((_node$attrs2 = node.attrs) === null || _node$attrs2 === void 0 ? void 0 : _node$attrs2.extensionKey) === 'string' && node.attrs.extensionKey.includes(NATIVE_EMBED_EXTENSION_KEY);
14
+ };
@@ -0,0 +1,49 @@
1
+ import { useEffect } from 'react';
2
+
3
+ /** Set to `"true"` by the embed frame while loading, then removed — never set to `"false"`. */
4
+ const NATIVE_EMBED_LOADING_ATTRIBUTE = 'data-native-embed-loading';
5
+
6
+ /**
7
+ * Calls `onSettled` once the native embed inside `container` has finished loading, successfully or
8
+ * not. The extension handler mounts the embed asynchronously, so the subtree is observed rather
9
+ * than a known element.
10
+ *
11
+ * Two signals, because neither alone catches every embed: the attribute having been seen and gone,
12
+ * which covers a failure that renders no frame; or a frame with no attribute, which covers an embed
13
+ * that never advertises loading. The frame is present either way, so the attribute comes first.
14
+ *
15
+ * `onSettled` must be stable, and runs at most once per container.
16
+ */
17
+ export const useNativeEmbedSettled = (container, onSettled) => {
18
+ useEffect(() => {
19
+ if (!container || typeof MutationObserver === 'undefined') {
20
+ return;
21
+ }
22
+ let hasBeenLoading = false;
23
+ let settled = false;
24
+ const read = () => {
25
+ if (settled) {
26
+ return;
27
+ }
28
+ if (container.querySelector(`[${NATIVE_EMBED_LOADING_ATTRIBUTE}="true"]`)) {
29
+ hasBeenLoading = true;
30
+ return;
31
+ }
32
+ if (hasBeenLoading || container.querySelector('iframe')) {
33
+ settled = true;
34
+ onSettled();
35
+ }
36
+ };
37
+ const observer = new MutationObserver(read);
38
+ observer.observe(container, {
39
+ attributes: true,
40
+ attributeFilter: [NATIVE_EMBED_LOADING_ATTRIBUTE],
41
+ childList: true,
42
+ subtree: true
43
+ });
44
+
45
+ // After `observe`, so a change landing in between is either read here or queued.
46
+ read();
47
+ return () => observer.disconnect();
48
+ }, [container, onSettled]);
49
+ };
@@ -13,7 +13,7 @@ const NETWORK_FAILURE_REGEX = /^network failure/i;
13
13
  const RESIZE_OBSERVER_LOOP_REGEX = /ResizeObserver loop completed with undelivered notifications/;
14
14
  const SENTRY_DSN = 'https://0b10c8e02fb44d8796c047b102c9bee8@o55978.ingest.sentry.io/4505129224110080';
15
15
  const packageName = 'editor-common'; // Sentry doesn't accept '/' in its releases https://docs.sentry.io/platforms/javascript/configuration/releases/
16
- const packageVersion = "122.3.2";
16
+ const packageVersion = "122.3.3";
17
17
  const sanitiseSentryEvents = (data, _hint) => {
18
18
  // Remove URL as it has UGC
19
19
  // Ignored via go/ees007
@@ -1,12 +1,5 @@
1
1
  import _extends from "@babel/runtime/helpers/extends";
2
- /**
3
- * @jsxRuntime classic
4
- * @jsx jsx
5
- */
6
2
  import React from 'react';
7
-
8
- // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
9
- import { jsx } from '@emotion/react';
10
3
  import { DOMSerializer } from '@atlaskit/editor-prosemirror/model';
11
4
  import { fg } from '@atlaskit/platform-feature-flags/fg';
12
5
  import { ACTION_SUBJECT, ACTION_SUBJECT_ID } from '../analytics';
@@ -342,15 +335,15 @@ function getPortalChildren({
342
335
  // refactor. A test suite to catch any instances of this is ideal however
343
336
  // the refactor required is currently out of scope for https://product-fabric.atlassian.net/browse/ED-14176
344
337
 
345
- return jsx(ErrorBoundary, {
338
+ return /*#__PURE__*/React.createElement(ErrorBoundary, {
346
339
  component: ACTION_SUBJECT.REACT_NODE_VIEW,
347
340
  componentId: (_currentNode$type$nam = currentNode === null || currentNode === void 0 ? void 0 : (_currentNode$type2 = currentNode.type) === null || _currentNode$type2 === void 0 ? void 0 : _currentNode$type2.name) !== null && _currentNode$type$nam !== void 0 ? _currentNode$type$nam : ACTION_SUBJECT_ID.UNKNOWN_NODE,
348
341
  dispatchAnalyticsEvent: dispatchAnalyticsEvent
349
- }, jsx("span", {
342
+ }, /*#__PURE__*/React.createElement("span", {
350
343
  className: `zeroWidthSpaceContainer`
351
- }, jsx("span", {
344
+ }, /*#__PURE__*/React.createElement("span", {
352
345
  className: `${inlineNodeViewClassname}AddZeroWidthSpace`
353
- }), ZERO_WIDTH_SPACE), jsx(Component, _extends({
346
+ }), ZERO_WIDTH_SPACE), /*#__PURE__*/React.createElement(Component, _extends({
354
347
  view: nodeViewParams.view
355
348
  // TODO: ED-13910 - Remove the boolean to fix the prosemirror view type
356
349
  // Ignored via go/ees005
@@ -360,15 +353,17 @@ function getPortalChildren({
360
353
  node: currentNode
361
354
  // eslint-disable-next-line react/jsx-props-no-spreading -- Spreading props to pass through dynamic component props
362
355
  }, extraComponentProps)), getBrowserInfo().android ?
356
+ /*#__PURE__*/
363
357
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
364
- jsx("span", {
358
+ React.createElement("span", {
365
359
  className: `zeroWidthSpaceContainer`,
366
360
  contentEditable: "false"
367
- }, jsx("span", {
361
+ }, /*#__PURE__*/React.createElement("span", {
368
362
  className: `${inlineNodeViewClassname}AddZeroWidthSpace`
369
363
  }), ZERO_WIDTH_SPACE) :
364
+ /*#__PURE__*/
370
365
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
371
- jsx("span", {
366
+ React.createElement("span", {
372
367
  className: `${inlineNodeViewClassname}AddZeroWidthSpace`
373
368
  }));
374
369
  };
@@ -14,7 +14,7 @@ import withAnalyticsEvents from '@atlaskit/analytics-next/withAnalyticsEvents';
14
14
  import { fg } from '@atlaskit/platform-feature-flags/fg';
15
15
  import Layer from '../Layer';
16
16
  const packageName = "@atlaskit/editor-common";
17
- const packageVersion = "122.3.2";
17
+ const packageVersion = "122.3.3";
18
18
  const halfFocusRing = 1;
19
19
  const dropOffset = '0, 8';
20
20
  const fadeIn = keyframes({
@@ -5,6 +5,11 @@ export var aiSuggestionsMessages = defineMessages({
5
5
  defaultMessage: 'Review',
6
6
  description: 'Label for the Suggest edits button in the editor toolbar'
7
7
  },
8
+ suggestEditsButtonTooltip: {
9
+ id: 'fabric.editor.ai.suggestions.suggestEditsButtonTooltip',
10
+ defaultMessage: 'Get AI suggestions to improve content',
11
+ description: 'Tooltip for the Review button in the editor toolbar'
12
+ },
8
13
  suggestEditsPromptPrefix: {
9
14
  id: 'fabric.editor.ai.suggestions.suggestEditsPromptPrefix.non-final',
10
15
  defaultMessage: 'Review my content with ',
@@ -1,12 +1,16 @@
1
- import _extends from "@babel/runtime/helpers/extends";
1
+ import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
+ 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; }
3
+ 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) { _defineProperty(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; }
2
4
  /**
3
- * @jsxRuntime classic
4
- * @jsx jsx
5
- *
6
- * IMPORTANT: This file MUST keep the emotion JSX pragma (@jsx jsx from @emotion/react).
5
+ * IMPORTANT: This file MUST keep using emotion's `jsx` factory (from @emotion/react).
7
6
  * This is intentional — it allows the HOC to apply emotion styles via the css prop
8
- * at the call site (where emotion's JSX runtime intercepts it), without requiring
9
- * the wrapped component to use the emotion pragma itself.
7
+ * without requiring the wrapped component to use the emotion pragma itself.
8
+ *
9
+ * Note: `jsx` is called directly rather than via the `@jsx jsx` pragma. The two are
10
+ * equivalent (the pragma just compiles JSX down to these calls), but the direct form
11
+ * avoids emotion's `EmotionJSX.LibraryManagedAttributes`, which since @emotion/react
12
+ * 11.13 is a distributive conditional type that TypeScript cannot resolve when the
13
+ * element's props are an uninstantiated generic parameter such as `P` below.
10
14
  *
11
15
  * This file is part of the Emotion → Compiled CSS-in-JS migration infrastructure.
12
16
  * It is temporary and should be removed once the migration is complete.
@@ -14,7 +18,7 @@ import _extends from "@babel/runtime/helpers/extends";
14
18
  * @see https://hello.atlassian.net/wiki/spaces/~712020e6f24689f2da470b80ba6873df7b44a2/pages/6788274038/Emotion+-+Compiled+Feature+Gating+Strategy
15
19
  */
16
20
 
17
- // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- intentional: this file must use emotion's JSX pragma to apply emotion styles via the css prop
21
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- intentional: this file must use emotion's element factory to apply emotion styles via the css prop
18
22
  import { jsx } from '@emotion/react';
19
23
  import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-experiment-enabled';
20
24
 
@@ -63,7 +67,7 @@ import { isExperimentEnabled } from '@atlaskit/platform-feature-experiments/is-e
63
67
  */
64
68
  export function withCompiledMigration(WrappedComponent, emotionStyles) {
65
69
  var _ref, _WrappedComponent$dis;
66
- // The cast is required because emotion's `css` prop is injected by the JSX pragma
70
+ // The cast is required because emotion's `css` prop is handled by the `jsx` factory
67
71
  // and is not part of the component's declared props type. We widen to P & { css? }
68
72
  // so TypeScript accepts the css prop in the emotion branch while preserving P.
69
73
  var Comp = WrappedComponent;
@@ -72,16 +76,14 @@ export function withCompiledMigration(WrappedComponent, emotionStyles) {
72
76
  if (compiledEnabled) {
73
77
  // Experiment ON — render directly. Compiled's statically-extracted CSS classes
74
78
  // are applied inside the component via its own css prop. No Emotion code runs.
75
- // eslint-disable-next-line react/jsx-props-no-spreading -- HOC must forward all props
76
79
  return jsx(Comp, props);
77
80
  }
78
81
 
79
- // Experiment OFF — render with Emotion css prop. Because this file has
80
- // the emotion JSX pragma, Emotion's JSX runtime intercepts the css prop
81
- // here, converts it to a className, and passes it through to the component.
82
- // No wrapper div needed.
83
- // eslint-disable-next-line react/jsx-props-no-spreading, @atlaskit/ui-styling-standard/use-compiled -- HOC must forward all props; intentional emotion usage for migration
84
- return jsx(Comp, _extends({}, props, {
82
+ // Experiment OFF — render with Emotion css prop. `jsx` is Emotion's element
83
+ // factory, so it intercepts the css prop here, converts it to a className, and
84
+ // passes it through to the component. No wrapper div needed.
85
+ // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- intentional emotion usage for migration
86
+ return jsx(Comp, _objectSpread(_objectSpread({}, props), {}, {
85
87
  css: emotionStyles
86
88
  }));
87
89
  }
@@ -10,6 +10,7 @@ import { css, jsx } from '@emotion/react';
10
10
  import classnames from 'classnames';
11
11
  import { ZERO_WIDTH_SPACE } from '../whitespace';
12
12
  import { ExtensionSSRReactContextsProvider } from './ExtensionSSRReactContextsProvider';
13
+ import { GeneratedContentReveal } from './GeneratedContentReveal';
13
14
  var styles = css({
14
15
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors -- Ignored via go/DSP-18766
15
16
  '&.inline-extension': {
@@ -20,6 +21,8 @@ var styles = css({
20
21
  position: 'relative'
21
22
  }
22
23
  });
24
+
25
+ // Mirrored by the reveal span in `GeneratedContentReveal`; keep the two in step.
23
26
  var hoverStyles = css({
24
27
  // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors, @atlaskit/ui-styling-standard/no-unsafe-selectors
25
28
  ':has(.extension-label:hover) .extension-container, :has(.extension-edit-toggle-container:hover) .extension-container': {
@@ -63,9 +66,19 @@ export var ExtensionNodeWrapper = function ExtensionNodeWrapper(_ref) {
63
66
  var children = _ref.children,
64
67
  nodeType = _ref.nodeType,
65
68
  macroInteractionDesignFeatureFlags = _ref.macroInteractionDesignFeatureFlags,
69
+ _ref$generatedContent = _ref.generatedContentMotion,
70
+ generatedContentMotion = _ref$generatedContent === void 0 ? false : _ref$generatedContent,
66
71
  intl = _ref.intl;
67
72
  var _ref2 = macroInteractionDesignFeatureFlags || {},
68
73
  showMacroInteractionDesignUpdates = _ref2.showMacroInteractionDesignUpdates;
74
+
75
+ // Fixed for the node view's lifetime: switching would remount the subtree and reload the embed.
76
+ if (generatedContentMotion) {
77
+ return jsx(GeneratedContentReveal, {
78
+ intl: intl,
79
+ showMacroInteractionDesignUpdates: showMacroInteractionDesignUpdates
80
+ }, children);
81
+ }
69
82
  var wrapperClassNames = classnames({
70
83
  'inline-extension': nodeType === 'inlineExtension' && showMacroInteractionDesignUpdates,
71
84
  relative: showMacroInteractionDesignUpdates
@@ -0,0 +1,53 @@
1
+ ._10i01bym [data-native-embed-card-wrapper=true]{animation-name:var(--ds-keyframe-fade-in,FadeIn0to100)}
2
+ ._10t9kb7n:has(.extension-label:hover) .extension-edit-toggle-container{opacity:1}
3
+ ._114yglyw [data-testid$="--loading-overlay"]{display:none}
4
+ ._147ai9qs [data-native-embed-card-wrapper=true]{animation-duration:var(--ds-duration-medium,.2s)}
5
+ ._15k3glyw:has(.extension-edit-toggle-container:hover) .extension-label{box-shadow:none}
6
+ ._17sh1wug:has(.extension-edit-toggle-container:hover) .extension-label.always-hide-label{cursor:auto}
7
+ ._17w9indk iframe:not([data-native-embed-card-wrapper=true] iframe){animation-timing-function:var(--ds-easing-out-practical,cubic-bezier(.4,1,.6,1))}
8
+ ._18m915vq{overflow-y:hidden}
9
+ ._1a2e1j9a:has(.extension-edit-toggle-container:hover) .extension-label.with-bodied-macro-live-page-styles{background-color:var(--ds-background-input,#fff)}
10
+ ._1e0c1ule{display:block}
11
+ ._1fdfidpf .extension-label:hover.always-hide-label{opacity:0}
12
+ ._1ghxysee:has(.extension-container:hover) .extension-label{background-color:var(--ds-background-accent-gray-subtlest,#f0f1f2)}
13
+ ._1i8c1j9a:has(.extension-container:hover) .extension-label.with-bodied-macro-live-page-styles{background-color:var(--ds-background-input,#fff)}
14
+ ._1jbo15uc iframe:not([data-native-embed-card-wrapper=true] iframe){animation-delay:var(--ds-duration-xlong,.4s)}
15
+ ._1kr5kb7n:has(.extension-container:hover) .extension-edit-toggle-container{opacity:1}
16
+ ._1nuetlke:has(.extension-container:hover) .extension-label{cursor:pointer}
17
+ ._1p7l15uc [data-native-embed-card-wrapper=true]{animation-delay:var(--ds-duration-xlong,.4s)}
18
+ ._1pfgidpf:has(.extension-container:hover) .extension-label.always-hide-label{opacity:0}
19
+ ._1pglindk{animation-timing-function:var(--ds-easing-out-practical,cubic-bezier(.4,1,.6,1))}
20
+ ._1qac1nu9:has(.extension-container:hover) .extension-icon{display:inline}
21
+ ._1reo15vq{overflow-x:hidden}
22
+ ._1si41wug:has(.extension-container:hover) .extension-label.always-hide-label{cursor:auto}
23
+ ._1tr2ynbm:has(.extension-edit-toggle-container:hover) .extension-container{box-shadow:0 0 0 1px var(--ds-border-input,#8c8f97)}
24
+ ._1vs61nu9:has(.extension-label:hover) .extension-icon{display:inline}
25
+ ._26lx1tsb .extension-label:hover.with-bodied-macro-live-page-styles{box-shadow:0 0 0 1px var(--ds-border,#0b120e24)}
26
+ ._2z44kb7n:has(.extension-edit-toggle-container:hover) .extension-label{opacity:1}
27
+ ._54r11nu9:has(.extension-edit-toggle-container:hover) .extension-icon{display:inline}
28
+ ._5sag15uc{animation-duration:var(--ds-duration-xlong,.4s)}
29
+ ._9sz11bym iframe:not([data-native-embed-card-wrapper=true] iframe){animation-name:var(--ds-keyframe-fade-in,FadeIn0to100)}
30
+ ._bcikkb7n:has(.extension-container:hover) .extension-label{opacity:1}
31
+ ._c71lidpf{max-height:0}
32
+ ._d1oeglyw:has(.extension-container:hover) .extension-label{box-shadow:none}
33
+ ._decvtlke:has(.extension-edit-toggle-container:hover) .extension-label{cursor:pointer}
34
+ ._gp9p1hrf iframe:not([data-native-embed-card-wrapper=true] iframe){animation-fill-mode:both}
35
+ ._j7hq1umn{animation-name:ke4lc1x}
36
+ ._jl0d1tsb:has(.extension-edit-toggle-container:hover) .extension-label.with-bodied-macro-live-page-styles{box-shadow:0 0 0 1px var(--ds-border,#0b120e24)}
37
+ ._kqswh2mm{position:relative}
38
+ ._ks721tsb:has(.extension-container:hover) .extension-label.with-bodied-macro-live-page-styles{box-shadow:0 0 0 1px var(--ds-border,#0b120e24)}
39
+ ._lbjpindk [data-native-embed-card-wrapper=true]{animation-timing-function:var(--ds-easing-out-practical,cubic-bezier(.4,1,.6,1))}
40
+ ._lwlpi9qs iframe:not([data-native-embed-card-wrapper=true] iframe){animation-duration:var(--ds-duration-medium,.2s)}
41
+ ._mi5m1wug .extension-label:hover.always-hide-label{cursor:auto}
42
+ ._okd3ysee:has(.extension-edit-toggle-container:hover) .extension-label{background-color:var(--ds-background-accent-gray-subtlest,#f0f1f2)}
43
+ ._pjh31hrf [data-native-embed-card-wrapper=true]{animation-fill-mode:both}
44
+ ._x3ro1j9a .extension-label:hover.with-bodied-macro-live-page-styles{background-color:var(--ds-background-input,#fff)}
45
+ ._xajsynbm:has(.extension-label:hover) .extension-container{box-shadow:0 0 0 1px var(--ds-border-input,#8c8f97)}
46
+ ._y7o7idpf:has(.extension-edit-toggle-container:hover) .extension-label.always-hide-label{opacity:0}
47
+ ._10pdkb7n .extension-edit-toggle-container:hover{opacity:1}
48
+ ._1er3glyw .extension-label:hover{box-shadow:none}
49
+ ._1ql7tlke .extension-label:hover{cursor:pointer}
50
+ ._1tmrkb7n .extension-label:hover{opacity:1}
51
+ ._dmn9ysee .extension-label:hover{background-color:var(--ds-background-accent-gray-subtlest,#f0f1f2)}
52
+ @keyframes ke4lc1x{0%{max-height:0}to{max-height:var(--_1wl3sa9)}}
53
+ @media (prefers-reduced-motion:reduce){._2hwzru3m{animation-duration:0s}._dxfxru3m [data-native-embed-card-wrapper=true]{animation-duration:0s}._log5ru3m iframe:not([data-native-embed-card-wrapper=true] iframe){animation-duration:0s}._1pz3ru3m [data-native-embed-card-wrapper=true]{animation-delay:0s}._9hrrru3m iframe:not([data-native-embed-card-wrapper=true] iframe){animation-delay:0s}}