@atlaskit/editor-plugin-placeholder 5.0.0 → 6.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # @atlaskit/editor-plugin-placeholder
2
2
 
3
+ ## 6.0.0
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies
8
+
9
+ ## 5.1.0
10
+
11
+ ### Minor Changes
12
+
13
+ - [`06349e515f94e`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/06349e515f94e) -
14
+ [ux] Add a delay to starting text cycling animation when user typed and deleted prompt text
15
+
3
16
  ## 5.0.0
4
17
 
5
18
  ### Patch Changes
@@ -5,7 +5,7 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.createPlaceholderDecoration = createPlaceholderDecoration;
7
7
  exports.createPlugin = createPlugin;
8
- exports.pluginKey = exports.placeholderTestId = exports.placeholderPlugin = void 0;
8
+ exports.pluginKey = exports.placeholderPlugin = void 0;
9
9
  var _messages = require("@atlaskit/editor-common/messages");
10
10
  var _safePlugin = require("@atlaskit/editor-common/safe-plugin");
11
11
  var _utils = require("@atlaskit/editor-common/utils");
@@ -18,16 +18,17 @@ var TYPEWRITER_TYPE_DELAY = 50; // Delay between typing each character
18
18
  var TYPEWRITER_PAUSE_BEFORE_ERASE = 2000; // Pause before starting to erase text
19
19
  var TYPEWRITER_ERASE_DELAY = 40; // Delay between erasing each character
20
20
  var TYPEWRITER_CYCLE_DELAY = 500; // Delay before starting next cycle
21
+ var TYPEWRITER_TYPED_AND_DELETED_DELAY = 1500; // Delay before starting animation after user typed and deleted
21
22
 
22
23
  var pluginKey = exports.pluginKey = new _state.PluginKey('placeholderPlugin');
24
+ var placeholderTestId = 'placeholder-test-id';
23
25
  function getPlaceholderState(editorState) {
24
26
  return pluginKey.getState(editorState);
25
27
  }
26
- var placeholderTestId = exports.placeholderTestId = 'placeholder-test-id';
27
28
  var nodeTypesWithLongPlaceholderText = ['expand', 'panel'];
28
29
  var nodeTypesWithShortPlaceholderText = ['tableCell', 'tableHeader'];
29
- var createTypewriterElement = function createTypewriterElement(placeholderPrompts, activeTypewriterTimeouts) {
30
- var typewriterElement = document.createElement('span');
30
+ var cycleThroughPlaceholderPrompts = function cycleThroughPlaceholderPrompts(placeholderPrompts, activeTypewriterTimeouts, placeholderNodeWithText) {
31
+ var initialDelayWhenUserTypedAndDeleted = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
31
32
  var currentPromptIndex = 0;
32
33
  var displayedText = '';
33
34
  var animationTimeouts = [];
@@ -48,7 +49,7 @@ var createTypewriterElement = function createTypewriterElement(placeholderPrompt
48
49
  var _typeNextCharacter = function typeNextCharacter() {
49
50
  if (characterIndex < currentPrompt.length) {
50
51
  displayedText = currentPrompt.substring(0, characterIndex + 1);
51
- typewriterElement.textContent = displayedText;
52
+ placeholderNodeWithText.textContent = displayedText;
52
53
  characterIndex++;
53
54
  scheduleTimeout(_typeNextCharacter, TYPEWRITER_TYPE_DELAY);
54
55
  } else {
@@ -58,11 +59,11 @@ var createTypewriterElement = function createTypewriterElement(placeholderPrompt
58
59
  var _eraseLastCharacter = function eraseLastCharacter() {
59
60
  if (displayedText.length > 1) {
60
61
  displayedText = displayedText.substring(0, displayedText.length - 1);
61
- typewriterElement.textContent = displayedText;
62
+ placeholderNodeWithText.textContent = displayedText;
62
63
  scheduleTimeout(_eraseLastCharacter, TYPEWRITER_ERASE_DELAY);
63
64
  } else {
64
65
  displayedText = ' ';
65
- typewriterElement.textContent = displayedText;
66
+ placeholderNodeWithText.textContent = displayedText;
66
67
  currentPromptIndex = (currentPromptIndex + 1) % placeholderPrompts.length;
67
68
  scheduleTimeout(_startAnimationCycle, TYPEWRITER_CYCLE_DELAY);
68
69
  }
@@ -70,14 +71,18 @@ var createTypewriterElement = function createTypewriterElement(placeholderPrompt
70
71
  _typeNextCharacter();
71
72
  };
72
73
  activeTypewriterTimeouts === null || activeTypewriterTimeouts === void 0 || activeTypewriterTimeouts.push(clearAllTimeouts);
73
- _startAnimationCycle();
74
- return typewriterElement;
74
+ if (initialDelayWhenUserTypedAndDeleted > 0) {
75
+ placeholderNodeWithText.textContent = ' ';
76
+ scheduleTimeout(_startAnimationCycle, initialDelayWhenUserTypedAndDeleted);
77
+ } else {
78
+ _startAnimationCycle();
79
+ }
75
80
  };
76
81
  function createPlaceholderDecoration(editorState, placeholderText, placeholderPrompts, activeTypewriterTimeouts) {
77
82
  var pos = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
83
+ var initialDelayWhenUserTypedAndDeleted = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 0;
78
84
  var placeholderDecoration = document.createElement('span');
79
85
  var placeholderNodeWithText = placeholderDecoration;
80
- var typewriterElement = null;
81
86
  placeholderDecoration.setAttribute('data-testid', placeholderTestId);
82
87
  placeholderDecoration.className = 'placeholder-decoration';
83
88
 
@@ -90,8 +95,7 @@ function createPlaceholderDecoration(editorState, placeholderText, placeholderPr
90
95
  placeholderNodeWithText = placeholderNode;
91
96
  }
92
97
  if (placeholderPrompts) {
93
- typewriterElement = createTypewriterElement(placeholderPrompts, activeTypewriterTimeouts);
94
- placeholderNodeWithText.appendChild(typewriterElement);
98
+ cycleThroughPlaceholderPrompts(placeholderPrompts, activeTypewriterTimeouts, placeholderNodeWithText, initialDelayWhenUserTypedAndDeleted);
95
99
  } else {
96
100
  placeholderNodeWithText.textContent = placeholderText || ' ';
97
101
  }
@@ -118,19 +122,23 @@ function createPlaceholderDecoration(editorState, placeholderText, placeholderPr
118
122
  key: "placeholder ".concat(placeholderText)
119
123
  })]);
120
124
  }
121
- function setPlaceHolderState(placeholderText, pos, placeholderPrompts) {
125
+ function setPlaceHolderState(placeholderText, pos, placeholderPrompts, typedAndDeleted, userHadTyped) {
122
126
  return {
123
127
  hasPlaceholder: true,
124
128
  placeholderText: placeholderText,
125
129
  placeholderPrompts: placeholderPrompts,
126
- pos: pos ? pos : 1
130
+ pos: pos ? pos : 1,
131
+ typedAndDeleted: typedAndDeleted,
132
+ userHadTyped: userHadTyped
127
133
  };
128
134
  }
129
- var emptyPlaceholder = function emptyPlaceholder(placeholderText, placeholderPrompts) {
135
+ var emptyPlaceholder = function emptyPlaceholder(placeholderText, placeholderPrompts, userHadTyped) {
130
136
  return {
131
137
  hasPlaceholder: false,
132
138
  placeholderText: placeholderText,
133
- placeholderPrompts: placeholderPrompts
139
+ placeholderPrompts: placeholderPrompts,
140
+ userHadTyped: userHadTyped,
141
+ typedAndDeleted: false
134
142
  };
135
143
  };
136
144
  function createPlaceHolderStateFrom(_ref) {
@@ -141,12 +149,14 @@ function createPlaceHolderStateFrom(_ref) {
141
149
  intl = _ref.intl,
142
150
  bracketPlaceholderText = _ref.bracketPlaceholderText,
143
151
  emptyLinePlaceholder = _ref.emptyLinePlaceholder,
144
- placeholderPrompts = _ref.placeholderPrompts;
152
+ placeholderPrompts = _ref.placeholderPrompts,
153
+ typedAndDeleted = _ref.typedAndDeleted,
154
+ userHadTyped = _ref.userHadTyped;
145
155
  if (isTypeAheadOpen !== null && isTypeAheadOpen !== void 0 && isTypeAheadOpen(editorState)) {
146
- return emptyPlaceholder(defaultPlaceholderText, placeholderPrompts);
156
+ return emptyPlaceholder(defaultPlaceholderText, placeholderPrompts, userHadTyped);
147
157
  }
148
158
  if ((defaultPlaceholderText || placeholderPrompts) && (0, _utils.isEmptyDocument)(editorState.doc)) {
149
- return setPlaceHolderState(defaultPlaceholderText, 1, placeholderPrompts);
159
+ return setPlaceHolderState(defaultPlaceholderText, 1, placeholderPrompts, typedAndDeleted, userHadTyped);
150
160
  }
151
161
  if (isEditorFocused && (0, _experiments.editorExperiment)('platform_editor_controls', 'variant1')) {
152
162
  var _parentNode$firstChil, _parentNode$firstChil2;
@@ -154,14 +164,14 @@ function createPlaceHolderStateFrom(_ref) {
154
164
  $from = _editorState$selectio.$from,
155
165
  $to = _editorState$selectio.$to;
156
166
  if ($from.pos !== $to.pos) {
157
- return emptyPlaceholder(defaultPlaceholderText, placeholderPrompts);
167
+ return emptyPlaceholder(defaultPlaceholderText, placeholderPrompts, userHadTyped);
158
168
  }
159
169
  var parentNode = $from.node($from.depth - 1);
160
170
  var parentType = parentNode === null || parentNode === void 0 ? void 0 : parentNode.type.name;
161
171
  if (emptyLinePlaceholder && parentType === 'doc') {
162
172
  var isEmptyLine = (0, _utils.isEmptyParagraph)($from.parent);
163
173
  if (isEmptyLine) {
164
- return setPlaceHolderState(emptyLinePlaceholder, $from.pos);
174
+ return setPlaceHolderState(emptyLinePlaceholder, $from.pos, placeholderPrompts, typedAndDeleted, userHadTyped);
165
175
  }
166
176
  }
167
177
  var isEmptyNode = (parentNode === null || parentNode === void 0 ? void 0 : parentNode.childCount) === 1 && ((_parentNode$firstChil = parentNode.firstChild) === null || _parentNode$firstChil === void 0 ? void 0 : _parentNode$firstChil.content.size) === 0 && ((_parentNode$firstChil2 = parentNode.firstChild) === null || _parentNode$firstChil2 === void 0 ? void 0 : _parentNode$firstChil2.type.name) === 'paragraph';
@@ -171,25 +181,45 @@ function createPlaceHolderStateFrom(_ref) {
171
181
  return node.type === editorState.schema.nodes.table;
172
182
  })(editorState.selection);
173
183
  if (!table) {
174
- return emptyPlaceholder(defaultPlaceholderText, placeholderPrompts);
184
+ return emptyPlaceholder(defaultPlaceholderText, placeholderPrompts, userHadTyped);
175
185
  }
176
186
  var isFirstCell = (table === null || table === void 0 || (_table$node$firstChil = table.node.firstChild) === null || _table$node$firstChil === void 0 ? void 0 : _table$node$firstChil.content.firstChild) === parentNode;
177
187
  if (isFirstCell) {
178
- return setPlaceHolderState(intl.formatMessage(_messages.placeholderTextMessages.shortEmptyNodePlaceholderText), $from.pos);
188
+ return setPlaceHolderState(intl.formatMessage(_messages.placeholderTextMessages.shortEmptyNodePlaceholderText), $from.pos, placeholderPrompts, typedAndDeleted, userHadTyped);
179
189
  }
180
190
  }
181
191
  if (nodeTypesWithLongPlaceholderText.includes(parentType) && isEmptyNode) {
182
- return setPlaceHolderState(intl.formatMessage(_messages.placeholderTextMessages.longEmptyNodePlaceholderText), $from.pos);
192
+ return setPlaceHolderState(intl.formatMessage(_messages.placeholderTextMessages.longEmptyNodePlaceholderText), $from.pos, placeholderPrompts, typedAndDeleted, userHadTyped);
183
193
  }
184
- return emptyPlaceholder(defaultPlaceholderText, placeholderPrompts);
194
+ return emptyPlaceholder(defaultPlaceholderText, placeholderPrompts, userHadTyped);
185
195
  }
186
196
  if (bracketPlaceholderText && (0, _utils.bracketTyped)(editorState) && isEditorFocused) {
187
197
  var _$from = editorState.selection.$from;
188
198
  // Space is to account for positioning of the bracket
189
199
  var bracketHint = ' ' + bracketPlaceholderText;
190
- return setPlaceHolderState(bracketHint, _$from.pos - 1, placeholderPrompts);
200
+ return setPlaceHolderState(bracketHint, _$from.pos - 1, placeholderPrompts, typedAndDeleted, userHadTyped);
191
201
  }
192
- return emptyPlaceholder(defaultPlaceholderText, placeholderPrompts);
202
+ return emptyPlaceholder(defaultPlaceholderText, placeholderPrompts, userHadTyped);
203
+ }
204
+ function calculateUserInteractionState(_ref2) {
205
+ var placeholderState = _ref2.placeholderState,
206
+ oldEditorState = _ref2.oldEditorState,
207
+ newEditorState = _ref2.newEditorState;
208
+ var wasEmpty = oldEditorState ? (0, _utils.isEmptyDocument)(oldEditorState.doc) : true;
209
+ var isEmpty = (0, _utils.isEmptyDocument)(newEditorState.doc);
210
+ var hasEverTyped = Boolean(placeholderState === null || placeholderState === void 0 ? void 0 : placeholderState.userHadTyped) ||
211
+ // Previously typed
212
+ !wasEmpty ||
213
+ // Had content before
214
+ wasEmpty && !isEmpty; // Just added content
215
+ var justDeletedAll = hasEverTyped && isEmpty && !wasEmpty;
216
+ var isInTypedAndDeletedState = justDeletedAll || Boolean(placeholderState === null || placeholderState === void 0 ? void 0 : placeholderState.typedAndDeleted) && isEmpty;
217
+ // Only reset user interaction tracking when editor is cleanly empty
218
+ var shouldResetInteraction = isEmpty && !isInTypedAndDeletedState;
219
+ return {
220
+ userHadTyped: shouldResetInteraction ? false : hasEverTyped,
221
+ typedAndDeleted: isInTypedAndDeletedState
222
+ };
193
223
  }
194
224
  function createPlugin(intl, defaultPlaceholderText, bracketPlaceholderText, emptyLinePlaceholder, placeholderPrompts, api) {
195
225
  if (!defaultPlaceholderText && !placeholderPrompts && !bracketPlaceholderText) {
@@ -216,30 +246,32 @@ function createPlugin(intl, defaultPlaceholderText, bracketPlaceholderText, empt
216
246
  bracketPlaceholderText: bracketPlaceholderText,
217
247
  emptyLinePlaceholder: emptyLinePlaceholder,
218
248
  placeholderPrompts: placeholderPrompts,
249
+ typedAndDeleted: false,
250
+ userHadTyped: false,
219
251
  intl: intl
220
252
  });
221
253
  },
222
254
  apply: function apply(tr, placeholderState, _oldEditorState, newEditorState) {
223
- var _api$focus2, _api$typeAhead2, _ref2, _meta$placeholderText, _ref3, _meta$placeholderProm, _api$typeAhead3, _placeholderState$pla, _placeholderState$pla2;
255
+ var _api$focus2, _api$typeAhead2, _ref3, _meta$placeholderText, _ref4, _meta$placeholderProm;
224
256
  var meta = tr.getMeta(pluginKey);
225
257
  var isEditorFocused = Boolean(api === null || api === void 0 || (_api$focus2 = api.focus) === null || _api$focus2 === void 0 || (_api$focus2 = _api$focus2.sharedState.currentState()) === null || _api$focus2 === void 0 ? void 0 : _api$focus2.hasFocus);
226
- var newPlaceholderState = (meta === null || meta === void 0 ? void 0 : meta.placeholderText) !== undefined || (meta === null || meta === void 0 ? void 0 : meta.placeholderPrompts) !== undefined ? createPlaceHolderStateFrom({
258
+ var _calculateUserInterac = calculateUserInteractionState({
259
+ placeholderState: placeholderState,
260
+ oldEditorState: _oldEditorState,
261
+ newEditorState: newEditorState
262
+ }),
263
+ userHadTyped = _calculateUserInterac.userHadTyped,
264
+ typedAndDeleted = _calculateUserInterac.typedAndDeleted;
265
+ var newPlaceholderState = createPlaceHolderStateFrom({
227
266
  isEditorFocused: isEditorFocused,
228
267
  editorState: newEditorState,
229
268
  isTypeAheadOpen: api === null || api === void 0 || (_api$typeAhead2 = api.typeAhead) === null || _api$typeAhead2 === void 0 ? void 0 : _api$typeAhead2.actions.isOpen,
230
- defaultPlaceholderText: (_ref2 = (_meta$placeholderText = meta.placeholderText) !== null && _meta$placeholderText !== void 0 ? _meta$placeholderText : placeholderState === null || placeholderState === void 0 ? void 0 : placeholderState.placeholderText) !== null && _ref2 !== void 0 ? _ref2 : defaultPlaceholderText,
269
+ defaultPlaceholderText: (_ref3 = (_meta$placeholderText = meta === null || meta === void 0 ? void 0 : meta.placeholderText) !== null && _meta$placeholderText !== void 0 ? _meta$placeholderText : placeholderState === null || placeholderState === void 0 ? void 0 : placeholderState.placeholderText) !== null && _ref3 !== void 0 ? _ref3 : defaultPlaceholderText,
231
270
  bracketPlaceholderText: bracketPlaceholderText,
232
271
  emptyLinePlaceholder: emptyLinePlaceholder,
233
- placeholderPrompts: (_ref3 = (_meta$placeholderProm = meta.placeholderPrompts) !== null && _meta$placeholderProm !== void 0 ? _meta$placeholderProm : placeholderState === null || placeholderState === void 0 ? void 0 : placeholderState.placeholderPrompts) !== null && _ref3 !== void 0 ? _ref3 : placeholderPrompts,
234
- intl: intl
235
- }) : createPlaceHolderStateFrom({
236
- isEditorFocused: isEditorFocused,
237
- editorState: newEditorState,
238
- isTypeAheadOpen: api === null || api === void 0 || (_api$typeAhead3 = api.typeAhead) === null || _api$typeAhead3 === void 0 ? void 0 : _api$typeAhead3.actions.isOpen,
239
- defaultPlaceholderText: (_placeholderState$pla = placeholderState === null || placeholderState === void 0 ? void 0 : placeholderState.placeholderText) !== null && _placeholderState$pla !== void 0 ? _placeholderState$pla : defaultPlaceholderText,
240
- bracketPlaceholderText: bracketPlaceholderText,
241
- emptyLinePlaceholder: emptyLinePlaceholder,
242
- placeholderPrompts: (_placeholderState$pla2 = placeholderState === null || placeholderState === void 0 ? void 0 : placeholderState.placeholderPrompts) !== null && _placeholderState$pla2 !== void 0 ? _placeholderState$pla2 : placeholderPrompts,
272
+ placeholderPrompts: (_ref4 = (_meta$placeholderProm = meta === null || meta === void 0 ? void 0 : meta.placeholderPrompts) !== null && _meta$placeholderProm !== void 0 ? _meta$placeholderProm : placeholderState === null || placeholderState === void 0 ? void 0 : placeholderState.placeholderPrompts) !== null && _ref4 !== void 0 ? _ref4 : placeholderPrompts,
273
+ typedAndDeleted: typedAndDeleted,
274
+ userHadTyped: userHadTyped,
243
275
  intl: intl
244
276
  });
245
277
 
@@ -256,7 +288,8 @@ function createPlugin(intl, defaultPlaceholderText, bracketPlaceholderText, empt
256
288
  var _getPlaceholderState = getPlaceholderState(editorState),
257
289
  hasPlaceholder = _getPlaceholderState.hasPlaceholder,
258
290
  placeholderText = _getPlaceholderState.placeholderText,
259
- pos = _getPlaceholderState.pos;
291
+ pos = _getPlaceholderState.pos,
292
+ typedAndDeleted = _getPlaceholderState.typedAndDeleted;
260
293
 
261
294
  // Decorations is still called after plugin is destroyed
262
295
  // So we need to make sure decorations is not called if plugin has been destroyed to prevent the placeholder animations' setTimeouts called infinitely
@@ -266,7 +299,8 @@ function createPlugin(intl, defaultPlaceholderText, bracketPlaceholderText, empt
266
299
  var compositionPluginState = api === null || api === void 0 || (_api$composition = api.composition) === null || _api$composition === void 0 ? void 0 : _api$composition.sharedState.currentState();
267
300
  var isShowingDiff = Boolean(api === null || api === void 0 || (_api$showDiff = api.showDiff) === null || _api$showDiff === void 0 || (_api$showDiff = _api$showDiff.sharedState.currentState()) === null || _api$showDiff === void 0 ? void 0 : _api$showDiff.isDisplayingChanges);
268
301
  if (hasPlaceholder && ((placeholderText !== null && placeholderText !== void 0 ? placeholderText : '') || placeholderPrompts) && pos !== undefined && !(compositionPluginState !== null && compositionPluginState !== void 0 && compositionPluginState.isComposing) && !isShowingDiff) {
269
- return createPlaceholderDecoration(editorState, placeholderText !== null && placeholderText !== void 0 ? placeholderText : '', placeholderPrompts, activeTypewriterTimeouts, pos);
302
+ var initialDelayWhenUserTypedAndDeleted = typedAndDeleted ? TYPEWRITER_TYPED_AND_DELETED_DELAY : 0;
303
+ return createPlaceholderDecoration(editorState, placeholderText !== null && placeholderText !== void 0 ? placeholderText : '', placeholderPrompts, activeTypewriterTimeouts, pos, initialDelayWhenUserTypedAndDeleted);
270
304
  }
271
305
  return;
272
306
  }
@@ -281,16 +315,16 @@ function createPlugin(intl, defaultPlaceholderText, bracketPlaceholderText, empt
281
315
  }
282
316
  });
283
317
  }
284
- var placeholderPlugin = exports.placeholderPlugin = function placeholderPlugin(_ref4) {
285
- var options = _ref4.config,
286
- api = _ref4.api;
318
+ var placeholderPlugin = exports.placeholderPlugin = function placeholderPlugin(_ref5) {
319
+ var options = _ref5.config,
320
+ api = _ref5.api;
287
321
  var currentPlaceholder = options === null || options === void 0 ? void 0 : options.placeholder;
288
322
  return {
289
323
  name: 'placeholder',
290
324
  commands: {
291
325
  setPlaceholder: function setPlaceholder(placeholderText) {
292
- return function (_ref5) {
293
- var tr = _ref5.tr;
326
+ return function (_ref6) {
327
+ var tr = _ref6.tr;
294
328
  if (currentPlaceholder !== placeholderText) {
295
329
  currentPlaceholder = placeholderText;
296
330
  return tr.setMeta(pluginKey, {
@@ -301,8 +335,8 @@ var placeholderPlugin = exports.placeholderPlugin = function placeholderPlugin(_
301
335
  };
302
336
  },
303
337
  setAnimatingPlaceholderPrompts: function setAnimatingPlaceholderPrompts(placeholderPrompts) {
304
- return function (_ref6) {
305
- var tr = _ref6.tr;
338
+ return function (_ref7) {
339
+ var tr = _ref7.tr;
306
340
  return tr.setMeta(pluginKey, {
307
341
  placeholderPrompts: placeholderPrompts
308
342
  });
@@ -312,8 +346,8 @@ var placeholderPlugin = exports.placeholderPlugin = function placeholderPlugin(_
312
346
  pmPlugins: function pmPlugins() {
313
347
  return [{
314
348
  name: 'placeholder',
315
- plugin: function plugin(_ref7) {
316
- var getIntl = _ref7.getIntl;
349
+ plugin: function plugin(_ref8) {
350
+ var getIntl = _ref8.getIntl;
317
351
  return createPlugin(getIntl(), options && options.placeholder, options && options.placeholderBracketHint, options && options.emptyLinePlaceholder, options && options.placeholderPrompts, api);
318
352
  }
319
353
  }];
@@ -10,16 +10,16 @@ const TYPEWRITER_TYPE_DELAY = 50; // Delay between typing each character
10
10
  const TYPEWRITER_PAUSE_BEFORE_ERASE = 2000; // Pause before starting to erase text
11
11
  const TYPEWRITER_ERASE_DELAY = 40; // Delay between erasing each character
12
12
  const TYPEWRITER_CYCLE_DELAY = 500; // Delay before starting next cycle
13
+ const TYPEWRITER_TYPED_AND_DELETED_DELAY = 1500; // Delay before starting animation after user typed and deleted
13
14
 
14
15
  export const pluginKey = new PluginKey('placeholderPlugin');
16
+ const placeholderTestId = 'placeholder-test-id';
15
17
  function getPlaceholderState(editorState) {
16
18
  return pluginKey.getState(editorState);
17
19
  }
18
- export const placeholderTestId = 'placeholder-test-id';
19
20
  const nodeTypesWithLongPlaceholderText = ['expand', 'panel'];
20
21
  const nodeTypesWithShortPlaceholderText = ['tableCell', 'tableHeader'];
21
- const createTypewriterElement = (placeholderPrompts, activeTypewriterTimeouts) => {
22
- const typewriterElement = document.createElement('span');
22
+ const cycleThroughPlaceholderPrompts = (placeholderPrompts, activeTypewriterTimeouts, placeholderNodeWithText, initialDelayWhenUserTypedAndDeleted = 0) => {
23
23
  let currentPromptIndex = 0;
24
24
  let displayedText = '';
25
25
  let animationTimeouts = [];
@@ -38,7 +38,7 @@ const createTypewriterElement = (placeholderPrompts, activeTypewriterTimeouts) =
38
38
  const typeNextCharacter = () => {
39
39
  if (characterIndex < currentPrompt.length) {
40
40
  displayedText = currentPrompt.substring(0, characterIndex + 1);
41
- typewriterElement.textContent = displayedText;
41
+ placeholderNodeWithText.textContent = displayedText;
42
42
  characterIndex++;
43
43
  scheduleTimeout(typeNextCharacter, TYPEWRITER_TYPE_DELAY);
44
44
  } else {
@@ -48,11 +48,11 @@ const createTypewriterElement = (placeholderPrompts, activeTypewriterTimeouts) =
48
48
  const eraseLastCharacter = () => {
49
49
  if (displayedText.length > 1) {
50
50
  displayedText = displayedText.substring(0, displayedText.length - 1);
51
- typewriterElement.textContent = displayedText;
51
+ placeholderNodeWithText.textContent = displayedText;
52
52
  scheduleTimeout(eraseLastCharacter, TYPEWRITER_ERASE_DELAY);
53
53
  } else {
54
54
  displayedText = ' ';
55
- typewriterElement.textContent = displayedText;
55
+ placeholderNodeWithText.textContent = displayedText;
56
56
  currentPromptIndex = (currentPromptIndex + 1) % placeholderPrompts.length;
57
57
  scheduleTimeout(startAnimationCycle, TYPEWRITER_CYCLE_DELAY);
58
58
  }
@@ -60,13 +60,16 @@ const createTypewriterElement = (placeholderPrompts, activeTypewriterTimeouts) =
60
60
  typeNextCharacter();
61
61
  };
62
62
  activeTypewriterTimeouts === null || activeTypewriterTimeouts === void 0 ? void 0 : activeTypewriterTimeouts.push(clearAllTimeouts);
63
- startAnimationCycle();
64
- return typewriterElement;
63
+ if (initialDelayWhenUserTypedAndDeleted > 0) {
64
+ placeholderNodeWithText.textContent = ' ';
65
+ scheduleTimeout(startAnimationCycle, initialDelayWhenUserTypedAndDeleted);
66
+ } else {
67
+ startAnimationCycle();
68
+ }
65
69
  };
66
- export function createPlaceholderDecoration(editorState, placeholderText, placeholderPrompts, activeTypewriterTimeouts, pos = 1) {
70
+ export function createPlaceholderDecoration(editorState, placeholderText, placeholderPrompts, activeTypewriterTimeouts, pos = 1, initialDelayWhenUserTypedAndDeleted = 0) {
67
71
  const placeholderDecoration = document.createElement('span');
68
72
  let placeholderNodeWithText = placeholderDecoration;
69
- let typewriterElement = null;
70
73
  placeholderDecoration.setAttribute('data-testid', placeholderTestId);
71
74
  placeholderDecoration.className = 'placeholder-decoration';
72
75
 
@@ -79,8 +82,7 @@ export function createPlaceholderDecoration(editorState, placeholderText, placeh
79
82
  placeholderNodeWithText = placeholderNode;
80
83
  }
81
84
  if (placeholderPrompts) {
82
- typewriterElement = createTypewriterElement(placeholderPrompts, activeTypewriterTimeouts);
83
- placeholderNodeWithText.appendChild(typewriterElement);
85
+ cycleThroughPlaceholderPrompts(placeholderPrompts, activeTypewriterTimeouts, placeholderNodeWithText, initialDelayWhenUserTypedAndDeleted);
84
86
  } else {
85
87
  placeholderNodeWithText.textContent = placeholderText || ' ';
86
88
  }
@@ -107,18 +109,22 @@ export function createPlaceholderDecoration(editorState, placeholderText, placeh
107
109
  key: `placeholder ${placeholderText}`
108
110
  })]);
109
111
  }
110
- function setPlaceHolderState(placeholderText, pos, placeholderPrompts) {
112
+ function setPlaceHolderState(placeholderText, pos, placeholderPrompts, typedAndDeleted, userHadTyped) {
111
113
  return {
112
114
  hasPlaceholder: true,
113
115
  placeholderText,
114
116
  placeholderPrompts,
115
- pos: pos ? pos : 1
117
+ pos: pos ? pos : 1,
118
+ typedAndDeleted,
119
+ userHadTyped
116
120
  };
117
121
  }
118
- const emptyPlaceholder = (placeholderText, placeholderPrompts) => ({
122
+ const emptyPlaceholder = (placeholderText, placeholderPrompts, userHadTyped) => ({
119
123
  hasPlaceholder: false,
120
124
  placeholderText,
121
- placeholderPrompts
125
+ placeholderPrompts,
126
+ userHadTyped,
127
+ typedAndDeleted: false
122
128
  });
123
129
  function createPlaceHolderStateFrom({
124
130
  isEditorFocused,
@@ -128,13 +134,15 @@ function createPlaceHolderStateFrom({
128
134
  intl,
129
135
  bracketPlaceholderText,
130
136
  emptyLinePlaceholder,
131
- placeholderPrompts
137
+ placeholderPrompts,
138
+ typedAndDeleted,
139
+ userHadTyped
132
140
  }) {
133
141
  if (isTypeAheadOpen !== null && isTypeAheadOpen !== void 0 && isTypeAheadOpen(editorState)) {
134
- return emptyPlaceholder(defaultPlaceholderText, placeholderPrompts);
142
+ return emptyPlaceholder(defaultPlaceholderText, placeholderPrompts, userHadTyped);
135
143
  }
136
144
  if ((defaultPlaceholderText || placeholderPrompts) && isEmptyDocument(editorState.doc)) {
137
- return setPlaceHolderState(defaultPlaceholderText, 1, placeholderPrompts);
145
+ return setPlaceHolderState(defaultPlaceholderText, 1, placeholderPrompts, typedAndDeleted, userHadTyped);
138
146
  }
139
147
  if (isEditorFocused && editorExperiment('platform_editor_controls', 'variant1')) {
140
148
  var _parentNode$firstChil, _parentNode$firstChil2;
@@ -143,14 +151,14 @@ function createPlaceHolderStateFrom({
143
151
  $to
144
152
  } = editorState.selection;
145
153
  if ($from.pos !== $to.pos) {
146
- return emptyPlaceholder(defaultPlaceholderText, placeholderPrompts);
154
+ return emptyPlaceholder(defaultPlaceholderText, placeholderPrompts, userHadTyped);
147
155
  }
148
156
  const parentNode = $from.node($from.depth - 1);
149
157
  const parentType = parentNode === null || parentNode === void 0 ? void 0 : parentNode.type.name;
150
158
  if (emptyLinePlaceholder && parentType === 'doc') {
151
159
  const isEmptyLine = isEmptyParagraph($from.parent);
152
160
  if (isEmptyLine) {
153
- return setPlaceHolderState(emptyLinePlaceholder, $from.pos);
161
+ return setPlaceHolderState(emptyLinePlaceholder, $from.pos, placeholderPrompts, typedAndDeleted, userHadTyped);
154
162
  }
155
163
  }
156
164
  const isEmptyNode = (parentNode === null || parentNode === void 0 ? void 0 : parentNode.childCount) === 1 && ((_parentNode$firstChil = parentNode.firstChild) === null || _parentNode$firstChil === void 0 ? void 0 : _parentNode$firstChil.content.size) === 0 && ((_parentNode$firstChil2 = parentNode.firstChild) === null || _parentNode$firstChil2 === void 0 ? void 0 : _parentNode$firstChil2.type.name) === 'paragraph';
@@ -158,17 +166,17 @@ function createPlaceHolderStateFrom({
158
166
  var _table$node$firstChil;
159
167
  const table = findParentNode(node => node.type === editorState.schema.nodes.table)(editorState.selection);
160
168
  if (!table) {
161
- return emptyPlaceholder(defaultPlaceholderText, placeholderPrompts);
169
+ return emptyPlaceholder(defaultPlaceholderText, placeholderPrompts, userHadTyped);
162
170
  }
163
171
  const isFirstCell = (table === null || table === void 0 ? void 0 : (_table$node$firstChil = table.node.firstChild) === null || _table$node$firstChil === void 0 ? void 0 : _table$node$firstChil.content.firstChild) === parentNode;
164
172
  if (isFirstCell) {
165
- return setPlaceHolderState(intl.formatMessage(messages.shortEmptyNodePlaceholderText), $from.pos);
173
+ return setPlaceHolderState(intl.formatMessage(messages.shortEmptyNodePlaceholderText), $from.pos, placeholderPrompts, typedAndDeleted, userHadTyped);
166
174
  }
167
175
  }
168
176
  if (nodeTypesWithLongPlaceholderText.includes(parentType) && isEmptyNode) {
169
- return setPlaceHolderState(intl.formatMessage(messages.longEmptyNodePlaceholderText), $from.pos);
177
+ return setPlaceHolderState(intl.formatMessage(messages.longEmptyNodePlaceholderText), $from.pos, placeholderPrompts, typedAndDeleted, userHadTyped);
170
178
  }
171
- return emptyPlaceholder(defaultPlaceholderText, placeholderPrompts);
179
+ return emptyPlaceholder(defaultPlaceholderText, placeholderPrompts, userHadTyped);
172
180
  }
173
181
  if (bracketPlaceholderText && bracketTyped(editorState) && isEditorFocused) {
174
182
  const {
@@ -176,9 +184,30 @@ function createPlaceHolderStateFrom({
176
184
  } = editorState.selection;
177
185
  // Space is to account for positioning of the bracket
178
186
  const bracketHint = ' ' + bracketPlaceholderText;
179
- return setPlaceHolderState(bracketHint, $from.pos - 1, placeholderPrompts);
187
+ return setPlaceHolderState(bracketHint, $from.pos - 1, placeholderPrompts, typedAndDeleted, userHadTyped);
180
188
  }
181
- return emptyPlaceholder(defaultPlaceholderText, placeholderPrompts);
189
+ return emptyPlaceholder(defaultPlaceholderText, placeholderPrompts, userHadTyped);
190
+ }
191
+ function calculateUserInteractionState({
192
+ placeholderState,
193
+ oldEditorState,
194
+ newEditorState
195
+ }) {
196
+ const wasEmpty = oldEditorState ? isEmptyDocument(oldEditorState.doc) : true;
197
+ const isEmpty = isEmptyDocument(newEditorState.doc);
198
+ const hasEverTyped = Boolean(placeholderState === null || placeholderState === void 0 ? void 0 : placeholderState.userHadTyped) ||
199
+ // Previously typed
200
+ !wasEmpty ||
201
+ // Had content before
202
+ wasEmpty && !isEmpty; // Just added content
203
+ const justDeletedAll = hasEverTyped && isEmpty && !wasEmpty;
204
+ const isInTypedAndDeletedState = justDeletedAll || Boolean(placeholderState === null || placeholderState === void 0 ? void 0 : placeholderState.typedAndDeleted) && isEmpty;
205
+ // Only reset user interaction tracking when editor is cleanly empty
206
+ const shouldResetInteraction = isEmpty && !isInTypedAndDeletedState;
207
+ return {
208
+ userHadTyped: shouldResetInteraction ? false : hasEverTyped,
209
+ typedAndDeleted: isInTypedAndDeletedState
210
+ };
182
211
  }
183
212
  export function createPlugin(intl, defaultPlaceholderText, bracketPlaceholderText, emptyLinePlaceholder, placeholderPrompts, api) {
184
213
  if (!defaultPlaceholderText && !placeholderPrompts && !bracketPlaceholderText) {
@@ -203,30 +232,33 @@ export function createPlugin(intl, defaultPlaceholderText, bracketPlaceholderTex
203
232
  bracketPlaceholderText,
204
233
  emptyLinePlaceholder,
205
234
  placeholderPrompts,
235
+ typedAndDeleted: false,
236
+ userHadTyped: false,
206
237
  intl
207
238
  });
208
239
  },
209
240
  apply: (tr, placeholderState, _oldEditorState, newEditorState) => {
210
- var _api$focus2, _api$focus2$sharedSta, _api$typeAhead2, _ref, _meta$placeholderText, _ref2, _meta$placeholderProm, _api$typeAhead3, _placeholderState$pla, _placeholderState$pla2;
241
+ var _api$focus2, _api$focus2$sharedSta, _api$typeAhead2, _ref, _meta$placeholderText, _ref2, _meta$placeholderProm;
211
242
  const meta = tr.getMeta(pluginKey);
212
243
  const isEditorFocused = Boolean(api === null || api === void 0 ? void 0 : (_api$focus2 = api.focus) === null || _api$focus2 === void 0 ? void 0 : (_api$focus2$sharedSta = _api$focus2.sharedState.currentState()) === null || _api$focus2$sharedSta === void 0 ? void 0 : _api$focus2$sharedSta.hasFocus);
213
- const newPlaceholderState = (meta === null || meta === void 0 ? void 0 : meta.placeholderText) !== undefined || (meta === null || meta === void 0 ? void 0 : meta.placeholderPrompts) !== undefined ? createPlaceHolderStateFrom({
244
+ const {
245
+ userHadTyped,
246
+ typedAndDeleted
247
+ } = calculateUserInteractionState({
248
+ placeholderState,
249
+ oldEditorState: _oldEditorState,
250
+ newEditorState
251
+ });
252
+ const newPlaceholderState = createPlaceHolderStateFrom({
214
253
  isEditorFocused,
215
254
  editorState: newEditorState,
216
255
  isTypeAheadOpen: api === null || api === void 0 ? void 0 : (_api$typeAhead2 = api.typeAhead) === null || _api$typeAhead2 === void 0 ? void 0 : _api$typeAhead2.actions.isOpen,
217
- defaultPlaceholderText: (_ref = (_meta$placeholderText = meta.placeholderText) !== null && _meta$placeholderText !== void 0 ? _meta$placeholderText : placeholderState === null || placeholderState === void 0 ? void 0 : placeholderState.placeholderText) !== null && _ref !== void 0 ? _ref : defaultPlaceholderText,
218
- bracketPlaceholderText,
219
- emptyLinePlaceholder,
220
- placeholderPrompts: (_ref2 = (_meta$placeholderProm = meta.placeholderPrompts) !== null && _meta$placeholderProm !== void 0 ? _meta$placeholderProm : placeholderState === null || placeholderState === void 0 ? void 0 : placeholderState.placeholderPrompts) !== null && _ref2 !== void 0 ? _ref2 : placeholderPrompts,
221
- intl
222
- }) : createPlaceHolderStateFrom({
223
- isEditorFocused,
224
- editorState: newEditorState,
225
- isTypeAheadOpen: api === null || api === void 0 ? void 0 : (_api$typeAhead3 = api.typeAhead) === null || _api$typeAhead3 === void 0 ? void 0 : _api$typeAhead3.actions.isOpen,
226
- defaultPlaceholderText: (_placeholderState$pla = placeholderState === null || placeholderState === void 0 ? void 0 : placeholderState.placeholderText) !== null && _placeholderState$pla !== void 0 ? _placeholderState$pla : defaultPlaceholderText,
256
+ defaultPlaceholderText: (_ref = (_meta$placeholderText = meta === null || meta === void 0 ? void 0 : meta.placeholderText) !== null && _meta$placeholderText !== void 0 ? _meta$placeholderText : placeholderState === null || placeholderState === void 0 ? void 0 : placeholderState.placeholderText) !== null && _ref !== void 0 ? _ref : defaultPlaceholderText,
227
257
  bracketPlaceholderText,
228
258
  emptyLinePlaceholder,
229
- placeholderPrompts: (_placeholderState$pla2 = placeholderState === null || placeholderState === void 0 ? void 0 : placeholderState.placeholderPrompts) !== null && _placeholderState$pla2 !== void 0 ? _placeholderState$pla2 : placeholderPrompts,
259
+ placeholderPrompts: (_ref2 = (_meta$placeholderProm = meta === null || meta === void 0 ? void 0 : meta.placeholderPrompts) !== null && _meta$placeholderProm !== void 0 ? _meta$placeholderProm : placeholderState === null || placeholderState === void 0 ? void 0 : placeholderState.placeholderPrompts) !== null && _ref2 !== void 0 ? _ref2 : placeholderPrompts,
260
+ typedAndDeleted,
261
+ userHadTyped,
230
262
  intl
231
263
  });
232
264
 
@@ -243,7 +275,8 @@ export function createPlugin(intl, defaultPlaceholderText, bracketPlaceholderTex
243
275
  const {
244
276
  hasPlaceholder,
245
277
  placeholderText,
246
- pos
278
+ pos,
279
+ typedAndDeleted
247
280
  } = getPlaceholderState(editorState);
248
281
 
249
282
  // Decorations is still called after plugin is destroyed
@@ -254,7 +287,8 @@ export function createPlugin(intl, defaultPlaceholderText, bracketPlaceholderTex
254
287
  const compositionPluginState = api === null || api === void 0 ? void 0 : (_api$composition = api.composition) === null || _api$composition === void 0 ? void 0 : _api$composition.sharedState.currentState();
255
288
  const isShowingDiff = Boolean(api === null || api === void 0 ? void 0 : (_api$showDiff = api.showDiff) === null || _api$showDiff === void 0 ? void 0 : (_api$showDiff$sharedS = _api$showDiff.sharedState.currentState()) === null || _api$showDiff$sharedS === void 0 ? void 0 : _api$showDiff$sharedS.isDisplayingChanges);
256
289
  if (hasPlaceholder && ((placeholderText !== null && placeholderText !== void 0 ? placeholderText : '') || placeholderPrompts) && pos !== undefined && !(compositionPluginState !== null && compositionPluginState !== void 0 && compositionPluginState.isComposing) && !isShowingDiff) {
257
- return createPlaceholderDecoration(editorState, placeholderText !== null && placeholderText !== void 0 ? placeholderText : '', placeholderPrompts, activeTypewriterTimeouts, pos);
290
+ const initialDelayWhenUserTypedAndDeleted = typedAndDeleted ? TYPEWRITER_TYPED_AND_DELETED_DELAY : 0;
291
+ return createPlaceholderDecoration(editorState, placeholderText !== null && placeholderText !== void 0 ? placeholderText : '', placeholderPrompts, activeTypewriterTimeouts, pos, initialDelayWhenUserTypedAndDeleted);
258
292
  }
259
293
  return;
260
294
  }
@@ -10,16 +10,17 @@ var TYPEWRITER_TYPE_DELAY = 50; // Delay between typing each character
10
10
  var TYPEWRITER_PAUSE_BEFORE_ERASE = 2000; // Pause before starting to erase text
11
11
  var TYPEWRITER_ERASE_DELAY = 40; // Delay between erasing each character
12
12
  var TYPEWRITER_CYCLE_DELAY = 500; // Delay before starting next cycle
13
+ var TYPEWRITER_TYPED_AND_DELETED_DELAY = 1500; // Delay before starting animation after user typed and deleted
13
14
 
14
15
  export var pluginKey = new PluginKey('placeholderPlugin');
16
+ var placeholderTestId = 'placeholder-test-id';
15
17
  function getPlaceholderState(editorState) {
16
18
  return pluginKey.getState(editorState);
17
19
  }
18
- export var placeholderTestId = 'placeholder-test-id';
19
20
  var nodeTypesWithLongPlaceholderText = ['expand', 'panel'];
20
21
  var nodeTypesWithShortPlaceholderText = ['tableCell', 'tableHeader'];
21
- var createTypewriterElement = function createTypewriterElement(placeholderPrompts, activeTypewriterTimeouts) {
22
- var typewriterElement = document.createElement('span');
22
+ var cycleThroughPlaceholderPrompts = function cycleThroughPlaceholderPrompts(placeholderPrompts, activeTypewriterTimeouts, placeholderNodeWithText) {
23
+ var initialDelayWhenUserTypedAndDeleted = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
23
24
  var currentPromptIndex = 0;
24
25
  var displayedText = '';
25
26
  var animationTimeouts = [];
@@ -40,7 +41,7 @@ var createTypewriterElement = function createTypewriterElement(placeholderPrompt
40
41
  var _typeNextCharacter = function typeNextCharacter() {
41
42
  if (characterIndex < currentPrompt.length) {
42
43
  displayedText = currentPrompt.substring(0, characterIndex + 1);
43
- typewriterElement.textContent = displayedText;
44
+ placeholderNodeWithText.textContent = displayedText;
44
45
  characterIndex++;
45
46
  scheduleTimeout(_typeNextCharacter, TYPEWRITER_TYPE_DELAY);
46
47
  } else {
@@ -50,11 +51,11 @@ var createTypewriterElement = function createTypewriterElement(placeholderPrompt
50
51
  var _eraseLastCharacter = function eraseLastCharacter() {
51
52
  if (displayedText.length > 1) {
52
53
  displayedText = displayedText.substring(0, displayedText.length - 1);
53
- typewriterElement.textContent = displayedText;
54
+ placeholderNodeWithText.textContent = displayedText;
54
55
  scheduleTimeout(_eraseLastCharacter, TYPEWRITER_ERASE_DELAY);
55
56
  } else {
56
57
  displayedText = ' ';
57
- typewriterElement.textContent = displayedText;
58
+ placeholderNodeWithText.textContent = displayedText;
58
59
  currentPromptIndex = (currentPromptIndex + 1) % placeholderPrompts.length;
59
60
  scheduleTimeout(_startAnimationCycle, TYPEWRITER_CYCLE_DELAY);
60
61
  }
@@ -62,14 +63,18 @@ var createTypewriterElement = function createTypewriterElement(placeholderPrompt
62
63
  _typeNextCharacter();
63
64
  };
64
65
  activeTypewriterTimeouts === null || activeTypewriterTimeouts === void 0 || activeTypewriterTimeouts.push(clearAllTimeouts);
65
- _startAnimationCycle();
66
- return typewriterElement;
66
+ if (initialDelayWhenUserTypedAndDeleted > 0) {
67
+ placeholderNodeWithText.textContent = ' ';
68
+ scheduleTimeout(_startAnimationCycle, initialDelayWhenUserTypedAndDeleted);
69
+ } else {
70
+ _startAnimationCycle();
71
+ }
67
72
  };
68
73
  export function createPlaceholderDecoration(editorState, placeholderText, placeholderPrompts, activeTypewriterTimeouts) {
69
74
  var pos = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
75
+ var initialDelayWhenUserTypedAndDeleted = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 0;
70
76
  var placeholderDecoration = document.createElement('span');
71
77
  var placeholderNodeWithText = placeholderDecoration;
72
- var typewriterElement = null;
73
78
  placeholderDecoration.setAttribute('data-testid', placeholderTestId);
74
79
  placeholderDecoration.className = 'placeholder-decoration';
75
80
 
@@ -82,8 +87,7 @@ export function createPlaceholderDecoration(editorState, placeholderText, placeh
82
87
  placeholderNodeWithText = placeholderNode;
83
88
  }
84
89
  if (placeholderPrompts) {
85
- typewriterElement = createTypewriterElement(placeholderPrompts, activeTypewriterTimeouts);
86
- placeholderNodeWithText.appendChild(typewriterElement);
90
+ cycleThroughPlaceholderPrompts(placeholderPrompts, activeTypewriterTimeouts, placeholderNodeWithText, initialDelayWhenUserTypedAndDeleted);
87
91
  } else {
88
92
  placeholderNodeWithText.textContent = placeholderText || ' ';
89
93
  }
@@ -110,19 +114,23 @@ export function createPlaceholderDecoration(editorState, placeholderText, placeh
110
114
  key: "placeholder ".concat(placeholderText)
111
115
  })]);
112
116
  }
113
- function setPlaceHolderState(placeholderText, pos, placeholderPrompts) {
117
+ function setPlaceHolderState(placeholderText, pos, placeholderPrompts, typedAndDeleted, userHadTyped) {
114
118
  return {
115
119
  hasPlaceholder: true,
116
120
  placeholderText: placeholderText,
117
121
  placeholderPrompts: placeholderPrompts,
118
- pos: pos ? pos : 1
122
+ pos: pos ? pos : 1,
123
+ typedAndDeleted: typedAndDeleted,
124
+ userHadTyped: userHadTyped
119
125
  };
120
126
  }
121
- var emptyPlaceholder = function emptyPlaceholder(placeholderText, placeholderPrompts) {
127
+ var emptyPlaceholder = function emptyPlaceholder(placeholderText, placeholderPrompts, userHadTyped) {
122
128
  return {
123
129
  hasPlaceholder: false,
124
130
  placeholderText: placeholderText,
125
- placeholderPrompts: placeholderPrompts
131
+ placeholderPrompts: placeholderPrompts,
132
+ userHadTyped: userHadTyped,
133
+ typedAndDeleted: false
126
134
  };
127
135
  };
128
136
  function createPlaceHolderStateFrom(_ref) {
@@ -133,12 +141,14 @@ function createPlaceHolderStateFrom(_ref) {
133
141
  intl = _ref.intl,
134
142
  bracketPlaceholderText = _ref.bracketPlaceholderText,
135
143
  emptyLinePlaceholder = _ref.emptyLinePlaceholder,
136
- placeholderPrompts = _ref.placeholderPrompts;
144
+ placeholderPrompts = _ref.placeholderPrompts,
145
+ typedAndDeleted = _ref.typedAndDeleted,
146
+ userHadTyped = _ref.userHadTyped;
137
147
  if (isTypeAheadOpen !== null && isTypeAheadOpen !== void 0 && isTypeAheadOpen(editorState)) {
138
- return emptyPlaceholder(defaultPlaceholderText, placeholderPrompts);
148
+ return emptyPlaceholder(defaultPlaceholderText, placeholderPrompts, userHadTyped);
139
149
  }
140
150
  if ((defaultPlaceholderText || placeholderPrompts) && isEmptyDocument(editorState.doc)) {
141
- return setPlaceHolderState(defaultPlaceholderText, 1, placeholderPrompts);
151
+ return setPlaceHolderState(defaultPlaceholderText, 1, placeholderPrompts, typedAndDeleted, userHadTyped);
142
152
  }
143
153
  if (isEditorFocused && editorExperiment('platform_editor_controls', 'variant1')) {
144
154
  var _parentNode$firstChil, _parentNode$firstChil2;
@@ -146,14 +156,14 @@ function createPlaceHolderStateFrom(_ref) {
146
156
  $from = _editorState$selectio.$from,
147
157
  $to = _editorState$selectio.$to;
148
158
  if ($from.pos !== $to.pos) {
149
- return emptyPlaceholder(defaultPlaceholderText, placeholderPrompts);
159
+ return emptyPlaceholder(defaultPlaceholderText, placeholderPrompts, userHadTyped);
150
160
  }
151
161
  var parentNode = $from.node($from.depth - 1);
152
162
  var parentType = parentNode === null || parentNode === void 0 ? void 0 : parentNode.type.name;
153
163
  if (emptyLinePlaceholder && parentType === 'doc') {
154
164
  var isEmptyLine = isEmptyParagraph($from.parent);
155
165
  if (isEmptyLine) {
156
- return setPlaceHolderState(emptyLinePlaceholder, $from.pos);
166
+ return setPlaceHolderState(emptyLinePlaceholder, $from.pos, placeholderPrompts, typedAndDeleted, userHadTyped);
157
167
  }
158
168
  }
159
169
  var isEmptyNode = (parentNode === null || parentNode === void 0 ? void 0 : parentNode.childCount) === 1 && ((_parentNode$firstChil = parentNode.firstChild) === null || _parentNode$firstChil === void 0 ? void 0 : _parentNode$firstChil.content.size) === 0 && ((_parentNode$firstChil2 = parentNode.firstChild) === null || _parentNode$firstChil2 === void 0 ? void 0 : _parentNode$firstChil2.type.name) === 'paragraph';
@@ -163,25 +173,45 @@ function createPlaceHolderStateFrom(_ref) {
163
173
  return node.type === editorState.schema.nodes.table;
164
174
  })(editorState.selection);
165
175
  if (!table) {
166
- return emptyPlaceholder(defaultPlaceholderText, placeholderPrompts);
176
+ return emptyPlaceholder(defaultPlaceholderText, placeholderPrompts, userHadTyped);
167
177
  }
168
178
  var isFirstCell = (table === null || table === void 0 || (_table$node$firstChil = table.node.firstChild) === null || _table$node$firstChil === void 0 ? void 0 : _table$node$firstChil.content.firstChild) === parentNode;
169
179
  if (isFirstCell) {
170
- return setPlaceHolderState(intl.formatMessage(messages.shortEmptyNodePlaceholderText), $from.pos);
180
+ return setPlaceHolderState(intl.formatMessage(messages.shortEmptyNodePlaceholderText), $from.pos, placeholderPrompts, typedAndDeleted, userHadTyped);
171
181
  }
172
182
  }
173
183
  if (nodeTypesWithLongPlaceholderText.includes(parentType) && isEmptyNode) {
174
- return setPlaceHolderState(intl.formatMessage(messages.longEmptyNodePlaceholderText), $from.pos);
184
+ return setPlaceHolderState(intl.formatMessage(messages.longEmptyNodePlaceholderText), $from.pos, placeholderPrompts, typedAndDeleted, userHadTyped);
175
185
  }
176
- return emptyPlaceholder(defaultPlaceholderText, placeholderPrompts);
186
+ return emptyPlaceholder(defaultPlaceholderText, placeholderPrompts, userHadTyped);
177
187
  }
178
188
  if (bracketPlaceholderText && bracketTyped(editorState) && isEditorFocused) {
179
189
  var _$from = editorState.selection.$from;
180
190
  // Space is to account for positioning of the bracket
181
191
  var bracketHint = ' ' + bracketPlaceholderText;
182
- return setPlaceHolderState(bracketHint, _$from.pos - 1, placeholderPrompts);
192
+ return setPlaceHolderState(bracketHint, _$from.pos - 1, placeholderPrompts, typedAndDeleted, userHadTyped);
183
193
  }
184
- return emptyPlaceholder(defaultPlaceholderText, placeholderPrompts);
194
+ return emptyPlaceholder(defaultPlaceholderText, placeholderPrompts, userHadTyped);
195
+ }
196
+ function calculateUserInteractionState(_ref2) {
197
+ var placeholderState = _ref2.placeholderState,
198
+ oldEditorState = _ref2.oldEditorState,
199
+ newEditorState = _ref2.newEditorState;
200
+ var wasEmpty = oldEditorState ? isEmptyDocument(oldEditorState.doc) : true;
201
+ var isEmpty = isEmptyDocument(newEditorState.doc);
202
+ var hasEverTyped = Boolean(placeholderState === null || placeholderState === void 0 ? void 0 : placeholderState.userHadTyped) ||
203
+ // Previously typed
204
+ !wasEmpty ||
205
+ // Had content before
206
+ wasEmpty && !isEmpty; // Just added content
207
+ var justDeletedAll = hasEverTyped && isEmpty && !wasEmpty;
208
+ var isInTypedAndDeletedState = justDeletedAll || Boolean(placeholderState === null || placeholderState === void 0 ? void 0 : placeholderState.typedAndDeleted) && isEmpty;
209
+ // Only reset user interaction tracking when editor is cleanly empty
210
+ var shouldResetInteraction = isEmpty && !isInTypedAndDeletedState;
211
+ return {
212
+ userHadTyped: shouldResetInteraction ? false : hasEverTyped,
213
+ typedAndDeleted: isInTypedAndDeletedState
214
+ };
185
215
  }
186
216
  export function createPlugin(intl, defaultPlaceholderText, bracketPlaceholderText, emptyLinePlaceholder, placeholderPrompts, api) {
187
217
  if (!defaultPlaceholderText && !placeholderPrompts && !bracketPlaceholderText) {
@@ -208,30 +238,32 @@ export function createPlugin(intl, defaultPlaceholderText, bracketPlaceholderTex
208
238
  bracketPlaceholderText: bracketPlaceholderText,
209
239
  emptyLinePlaceholder: emptyLinePlaceholder,
210
240
  placeholderPrompts: placeholderPrompts,
241
+ typedAndDeleted: false,
242
+ userHadTyped: false,
211
243
  intl: intl
212
244
  });
213
245
  },
214
246
  apply: function apply(tr, placeholderState, _oldEditorState, newEditorState) {
215
- var _api$focus2, _api$typeAhead2, _ref2, _meta$placeholderText, _ref3, _meta$placeholderProm, _api$typeAhead3, _placeholderState$pla, _placeholderState$pla2;
247
+ var _api$focus2, _api$typeAhead2, _ref3, _meta$placeholderText, _ref4, _meta$placeholderProm;
216
248
  var meta = tr.getMeta(pluginKey);
217
249
  var isEditorFocused = Boolean(api === null || api === void 0 || (_api$focus2 = api.focus) === null || _api$focus2 === void 0 || (_api$focus2 = _api$focus2.sharedState.currentState()) === null || _api$focus2 === void 0 ? void 0 : _api$focus2.hasFocus);
218
- var newPlaceholderState = (meta === null || meta === void 0 ? void 0 : meta.placeholderText) !== undefined || (meta === null || meta === void 0 ? void 0 : meta.placeholderPrompts) !== undefined ? createPlaceHolderStateFrom({
250
+ var _calculateUserInterac = calculateUserInteractionState({
251
+ placeholderState: placeholderState,
252
+ oldEditorState: _oldEditorState,
253
+ newEditorState: newEditorState
254
+ }),
255
+ userHadTyped = _calculateUserInterac.userHadTyped,
256
+ typedAndDeleted = _calculateUserInterac.typedAndDeleted;
257
+ var newPlaceholderState = createPlaceHolderStateFrom({
219
258
  isEditorFocused: isEditorFocused,
220
259
  editorState: newEditorState,
221
260
  isTypeAheadOpen: api === null || api === void 0 || (_api$typeAhead2 = api.typeAhead) === null || _api$typeAhead2 === void 0 ? void 0 : _api$typeAhead2.actions.isOpen,
222
- defaultPlaceholderText: (_ref2 = (_meta$placeholderText = meta.placeholderText) !== null && _meta$placeholderText !== void 0 ? _meta$placeholderText : placeholderState === null || placeholderState === void 0 ? void 0 : placeholderState.placeholderText) !== null && _ref2 !== void 0 ? _ref2 : defaultPlaceholderText,
261
+ defaultPlaceholderText: (_ref3 = (_meta$placeholderText = meta === null || meta === void 0 ? void 0 : meta.placeholderText) !== null && _meta$placeholderText !== void 0 ? _meta$placeholderText : placeholderState === null || placeholderState === void 0 ? void 0 : placeholderState.placeholderText) !== null && _ref3 !== void 0 ? _ref3 : defaultPlaceholderText,
223
262
  bracketPlaceholderText: bracketPlaceholderText,
224
263
  emptyLinePlaceholder: emptyLinePlaceholder,
225
- placeholderPrompts: (_ref3 = (_meta$placeholderProm = meta.placeholderPrompts) !== null && _meta$placeholderProm !== void 0 ? _meta$placeholderProm : placeholderState === null || placeholderState === void 0 ? void 0 : placeholderState.placeholderPrompts) !== null && _ref3 !== void 0 ? _ref3 : placeholderPrompts,
226
- intl: intl
227
- }) : createPlaceHolderStateFrom({
228
- isEditorFocused: isEditorFocused,
229
- editorState: newEditorState,
230
- isTypeAheadOpen: api === null || api === void 0 || (_api$typeAhead3 = api.typeAhead) === null || _api$typeAhead3 === void 0 ? void 0 : _api$typeAhead3.actions.isOpen,
231
- defaultPlaceholderText: (_placeholderState$pla = placeholderState === null || placeholderState === void 0 ? void 0 : placeholderState.placeholderText) !== null && _placeholderState$pla !== void 0 ? _placeholderState$pla : defaultPlaceholderText,
232
- bracketPlaceholderText: bracketPlaceholderText,
233
- emptyLinePlaceholder: emptyLinePlaceholder,
234
- placeholderPrompts: (_placeholderState$pla2 = placeholderState === null || placeholderState === void 0 ? void 0 : placeholderState.placeholderPrompts) !== null && _placeholderState$pla2 !== void 0 ? _placeholderState$pla2 : placeholderPrompts,
264
+ placeholderPrompts: (_ref4 = (_meta$placeholderProm = meta === null || meta === void 0 ? void 0 : meta.placeholderPrompts) !== null && _meta$placeholderProm !== void 0 ? _meta$placeholderProm : placeholderState === null || placeholderState === void 0 ? void 0 : placeholderState.placeholderPrompts) !== null && _ref4 !== void 0 ? _ref4 : placeholderPrompts,
265
+ typedAndDeleted: typedAndDeleted,
266
+ userHadTyped: userHadTyped,
235
267
  intl: intl
236
268
  });
237
269
 
@@ -248,7 +280,8 @@ export function createPlugin(intl, defaultPlaceholderText, bracketPlaceholderTex
248
280
  var _getPlaceholderState = getPlaceholderState(editorState),
249
281
  hasPlaceholder = _getPlaceholderState.hasPlaceholder,
250
282
  placeholderText = _getPlaceholderState.placeholderText,
251
- pos = _getPlaceholderState.pos;
283
+ pos = _getPlaceholderState.pos,
284
+ typedAndDeleted = _getPlaceholderState.typedAndDeleted;
252
285
 
253
286
  // Decorations is still called after plugin is destroyed
254
287
  // So we need to make sure decorations is not called if plugin has been destroyed to prevent the placeholder animations' setTimeouts called infinitely
@@ -258,7 +291,8 @@ export function createPlugin(intl, defaultPlaceholderText, bracketPlaceholderTex
258
291
  var compositionPluginState = api === null || api === void 0 || (_api$composition = api.composition) === null || _api$composition === void 0 ? void 0 : _api$composition.sharedState.currentState();
259
292
  var isShowingDiff = Boolean(api === null || api === void 0 || (_api$showDiff = api.showDiff) === null || _api$showDiff === void 0 || (_api$showDiff = _api$showDiff.sharedState.currentState()) === null || _api$showDiff === void 0 ? void 0 : _api$showDiff.isDisplayingChanges);
260
293
  if (hasPlaceholder && ((placeholderText !== null && placeholderText !== void 0 ? placeholderText : '') || placeholderPrompts) && pos !== undefined && !(compositionPluginState !== null && compositionPluginState !== void 0 && compositionPluginState.isComposing) && !isShowingDiff) {
261
- return createPlaceholderDecoration(editorState, placeholderText !== null && placeholderText !== void 0 ? placeholderText : '', placeholderPrompts, activeTypewriterTimeouts, pos);
294
+ var initialDelayWhenUserTypedAndDeleted = typedAndDeleted ? TYPEWRITER_TYPED_AND_DELETED_DELAY : 0;
295
+ return createPlaceholderDecoration(editorState, placeholderText !== null && placeholderText !== void 0 ? placeholderText : '', placeholderPrompts, activeTypewriterTimeouts, pos, initialDelayWhenUserTypedAndDeleted);
262
296
  }
263
297
  return;
264
298
  }
@@ -273,16 +307,16 @@ export function createPlugin(intl, defaultPlaceholderText, bracketPlaceholderTex
273
307
  }
274
308
  });
275
309
  }
276
- export var placeholderPlugin = function placeholderPlugin(_ref4) {
277
- var options = _ref4.config,
278
- api = _ref4.api;
310
+ export var placeholderPlugin = function placeholderPlugin(_ref5) {
311
+ var options = _ref5.config,
312
+ api = _ref5.api;
279
313
  var currentPlaceholder = options === null || options === void 0 ? void 0 : options.placeholder;
280
314
  return {
281
315
  name: 'placeholder',
282
316
  commands: {
283
317
  setPlaceholder: function setPlaceholder(placeholderText) {
284
- return function (_ref5) {
285
- var tr = _ref5.tr;
318
+ return function (_ref6) {
319
+ var tr = _ref6.tr;
286
320
  if (currentPlaceholder !== placeholderText) {
287
321
  currentPlaceholder = placeholderText;
288
322
  return tr.setMeta(pluginKey, {
@@ -293,8 +327,8 @@ export var placeholderPlugin = function placeholderPlugin(_ref4) {
293
327
  };
294
328
  },
295
329
  setAnimatingPlaceholderPrompts: function setAnimatingPlaceholderPrompts(placeholderPrompts) {
296
- return function (_ref6) {
297
- var tr = _ref6.tr;
330
+ return function (_ref7) {
331
+ var tr = _ref7.tr;
298
332
  return tr.setMeta(pluginKey, {
299
333
  placeholderPrompts: placeholderPrompts
300
334
  });
@@ -304,8 +338,8 @@ export var placeholderPlugin = function placeholderPlugin(_ref4) {
304
338
  pmPlugins: function pmPlugins() {
305
339
  return [{
306
340
  name: 'placeholder',
307
- plugin: function plugin(_ref7) {
308
- var getIntl = _ref7.getIntl;
341
+ plugin: function plugin(_ref8) {
342
+ var getIntl = _ref8.getIntl;
309
343
  return createPlugin(getIntl(), options && options.placeholder, options && options.placeholderBracketHint, options && options.emptyLinePlaceholder, options && options.placeholderPrompts, api);
310
344
  }
311
345
  }];
@@ -6,7 +6,6 @@ import { PluginKey } from '@atlaskit/editor-prosemirror/state';
6
6
  import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
7
7
  import type { PlaceholderPlugin } from './placeholderPluginType';
8
8
  export declare const pluginKey: PluginKey<any>;
9
- export declare const placeholderTestId = "placeholder-test-id";
10
- export declare function createPlaceholderDecoration(editorState: EditorState, placeholderText: string, placeholderPrompts?: string[], activeTypewriterTimeouts?: (() => void)[], pos?: number): DecorationSet;
9
+ export declare function createPlaceholderDecoration(editorState: EditorState, placeholderText: string, placeholderPrompts?: string[], activeTypewriterTimeouts?: (() => void)[], pos?: number, initialDelayWhenUserTypedAndDeleted?: number): DecorationSet;
11
10
  export declare function createPlugin(intl: IntlShape, defaultPlaceholderText?: string, bracketPlaceholderText?: string, emptyLinePlaceholder?: string, placeholderPrompts?: string[], api?: ExtractInjectionAPI<PlaceholderPlugin>): SafePlugin | undefined;
12
11
  export declare const placeholderPlugin: PlaceholderPlugin;
@@ -6,7 +6,6 @@ import { PluginKey } from '@atlaskit/editor-prosemirror/state';
6
6
  import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
7
7
  import type { PlaceholderPlugin } from './placeholderPluginType';
8
8
  export declare const pluginKey: PluginKey<any>;
9
- export declare const placeholderTestId = "placeholder-test-id";
10
- export declare function createPlaceholderDecoration(editorState: EditorState, placeholderText: string, placeholderPrompts?: string[], activeTypewriterTimeouts?: (() => void)[], pos?: number): DecorationSet;
9
+ export declare function createPlaceholderDecoration(editorState: EditorState, placeholderText: string, placeholderPrompts?: string[], activeTypewriterTimeouts?: (() => void)[], pos?: number, initialDelayWhenUserTypedAndDeleted?: number): DecorationSet;
11
10
  export declare function createPlugin(intl: IntlShape, defaultPlaceholderText?: string, bracketPlaceholderText?: string, emptyLinePlaceholder?: string, placeholderPrompts?: string[], api?: ExtractInjectionAPI<PlaceholderPlugin>): SafePlugin | undefined;
12
11
  export declare const placeholderPlugin: PlaceholderPlugin;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/editor-plugin-placeholder",
3
- "version": "5.0.0",
3
+ "version": "6.0.0",
4
4
  "description": "Placeholder plugin for @atlaskit/editor-core.",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -27,17 +27,17 @@
27
27
  "sideEffects": false,
28
28
  "atlaskit:src": "src/index.ts",
29
29
  "dependencies": {
30
- "@atlaskit/editor-plugin-composition": "^4.0.0",
31
- "@atlaskit/editor-plugin-focus": "^4.0.0",
32
- "@atlaskit/editor-plugin-show-diff": "^2.0.0",
33
- "@atlaskit/editor-plugin-type-ahead": "^5.0.0",
30
+ "@atlaskit/editor-plugin-composition": "^5.0.0",
31
+ "@atlaskit/editor-plugin-focus": "^5.0.0",
32
+ "@atlaskit/editor-plugin-show-diff": "^3.0.0",
33
+ "@atlaskit/editor-plugin-type-ahead": "^6.0.0",
34
34
  "@atlaskit/editor-prosemirror": "7.0.0",
35
35
  "@atlaskit/platform-feature-flags": "^1.1.0",
36
- "@atlaskit/tmp-editor-statsig": "^12.9.0",
36
+ "@atlaskit/tmp-editor-statsig": "^12.31.0",
37
37
  "@babel/runtime": "^7.0.0"
38
38
  },
39
39
  "peerDependencies": {
40
- "@atlaskit/editor-common": "^109.0.0",
40
+ "@atlaskit/editor-common": "^110.0.0",
41
41
  "react": "^18.2.0",
42
42
  "react-dom": "^18.2.0",
43
43
  "react-intl-next": "npm:react-intl@^5.18.1"