@qoretechnologies/reqraft 0.10.62-pr.141.g7591ef9 → 0.10.62-pr.141.gd67d7d6

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.
@@ -2,6 +2,7 @@
2
2
  import { IReqoreRichTextEditorProps } from '@qoretechnologies/reqore/dist/components/RichTextEditor';
3
3
  import { IReqoreFormTemplates } from '@qoretechnologies/reqore/dist/components/Textarea';
4
4
  import { IQorusAllowedValue } from '@qoretechnologies/ts-toolkit';
5
+ import { IChoiceChipBehavior } from '../../../../helpers/choiceChip';
5
6
  export interface IRichTextFormFieldProps extends Omit<IReqoreRichTextEditorProps, 'onChange' | 'value' | 'tags' | 'actions'> {
6
7
  /**
7
8
  * A form field's OWN chips — not the editor's template catalogue, which this
@@ -31,13 +32,23 @@ export interface IRichTextFormFieldProps extends Omit<IReqoreRichTextEditorProps
31
32
  singleLine?: boolean;
32
33
  /**
33
34
  * The choices the field offers, when it offers any. A value that IS one of
34
- * them — the whole string, as picked from the field's suggestions — is drawn
35
- * as one chip named from the choice (`general` rather than `C07ERBFS0P6`),
36
- * and is still emitted as that value: the chip's own value is the choice's,
37
- * and a document that is nothing but the chip reads back as it. A field
38
- * spreads its schema here, so this is the schema's own key.
35
+ * them — the whole string, as picked from the field's suggestions, or a
36
+ * document of nothing but that string, as an edit of it stores — is drawn as
37
+ * one chip named from the choice (`general` rather than `C07ERBFS0P6`), and
38
+ * is still emitted as that value: the chip's own value is the choice's, and a
39
+ * document that is nothing but the chip reads back as it. A field spreads
40
+ * its schema here, so this is the schema's own key.
39
41
  */
40
42
  allowed_values?: IQorusAllowedValue[];
43
+ /**
44
+ * What a choice chip does when the author acts on it — Backspace right after
45
+ * it, a click on it. By default each opens the chip into its value as plain
46
+ * text, the cursor at the end, so one letter of what was chosen can be
47
+ * changed; see `IChoiceChipBehavior` for the alternatives. Text that is again
48
+ * exactly one of the choices becomes its chip when the author leaves the
49
+ * field — not while typing, where a choice can be the start of a longer value.
50
+ */
51
+ choiceChip?: IChoiceChipBehavior;
41
52
  /**
42
53
  * With `valueFormat: 'text'`: the token grammar the value's references are
43
54
  * WRITTEN in, when the host speaks one of its own.
@@ -62,5 +73,5 @@ export interface IRichTextFormFieldProps extends Omit<IReqoreRichTextEditorProps
62
73
  * Exported so the mapping is assertable without rendering a Slate editor.
63
74
  */
64
75
  export declare const getChipTooltipDescriptions: (templates?: IReqoreFormTemplates) => Record<string, string>;
65
- export declare const RichTextFormField: import("react").MemoExoticComponent<({ value, onChange, allowTemplates, templates, valueFormat, singleLine, templateToken, allowed_values, ...rest }: IRichTextFormFieldProps) => import("react/jsx-runtime").JSX.Element>;
76
+ export declare const RichTextFormField: import("react").MemoExoticComponent<({ value, onChange, allowTemplates, templates, valueFormat, singleLine, templateToken, allowed_values, choiceChip, ...rest }: IRichTextFormFieldProps) => import("react/jsx-runtime").JSX.Element>;
66
77
  //# sourceMappingURL=RichText.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"RichText.d.ts","sourceRoot":"","sources":["../../../../../src/components/form/fields/rich-text/RichText.tsx"],"names":[],"mappings":";AAAA,OAAO,EACL,0BAA0B,EAE3B,MAAM,yDAAyD,CAAC;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,mDAAmD,CAAC;AAGzF,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAwBlE,MAAM,WAAW,uBAAwB,SAAQ,IAAI,CACnD,0BAA0B,EAC1B,UAAU,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,CAC1C;IACC;;;;;;;;;;;OAWG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,GAAG,0BAA0B,CAAC,OAAO,CAAC,CAAC;IACrD,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,0BAA0B,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC;IACzE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,SAAS,CAAC,EAAE,oBAAoB,CAAC;IACjC;;;;;OAKG;IACH,WAAW,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC;IAClC,gFAAgF;IAChF,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;;;OAOG;IACH,cAAc,CAAC,EAAE,kBAAkB,EAAE,CAAC;IACtC;;;;;;;;;;OAUG;IACH,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACjC;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,0BAA0B,eACzB,oBAAoB,KAC/B,OAAO,MAAM,EAAE,MAAM,CA0BvB,CAAC;AAEF,eAAO,MAAM,iBAAiB,wJAU3B,uBAAuB,6CA6RxB,CAAC"}
1
+ {"version":3,"file":"RichText.d.ts","sourceRoot":"","sources":["../../../../../src/components/form/fields/rich-text/RichText.tsx"],"names":[],"mappings":";AAAA,OAAO,EACL,0BAA0B,EAG3B,MAAM,yDAAyD,CAAC;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,mDAAmD,CAAC;AAGzF,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAOlE,OAAO,EAOL,mBAAmB,EAGpB,MAAM,gCAAgC,CAAC;AAmBxC,MAAM,WAAW,uBAAwB,SAAQ,IAAI,CACnD,0BAA0B,EAC1B,UAAU,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,CAC1C;IACC;;;;;;;;;;;OAWG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,GAAG,0BAA0B,CAAC,OAAO,CAAC,CAAC;IACrD,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,0BAA0B,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC;IACzE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,SAAS,CAAC,EAAE,oBAAoB,CAAC;IACjC;;;;;OAKG;IACH,WAAW,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC;IAClC,gFAAgF;IAChF,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;;;;OAQG;IACH,cAAc,CAAC,EAAE,kBAAkB,EAAE,CAAC;IACtC;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,mBAAmB,CAAC;IACjC;;;;;;;;;;OAUG;IACH,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACjC;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,0BAA0B,eACzB,oBAAoB,KAC/B,OAAO,MAAM,EAAE,MAAM,CA0BvB,CAAC;AAEF,eAAO,MAAM,iBAAiB,oKAW3B,uBAAuB,6CA0XxB,CAAC"}
@@ -28,6 +28,7 @@ var RichTextEditor_1 = require("@qoretechnologies/reqore/dist/components/RichTex
28
28
  var lodash_1 = require("lodash");
29
29
  var react_1 = require("react");
30
30
  var react_use_1 = require("react-use");
31
+ var slate_react_1 = require("slate-react");
31
32
  var emittedValues_1 = require("../emittedValues");
32
33
  var choiceChip_1 = require("../../../../helpers/choiceChip");
33
34
  var singleLineString_1 = require("../../../../helpers/singleLineString");
@@ -73,8 +74,12 @@ var getChipTooltipDescriptions = function (templates) {
73
74
  exports.getChipTooltipDescriptions = getChipTooltipDescriptions;
74
75
  exports.RichTextFormField = (0, react_1.memo)(function (_a) {
75
76
  var _b, _c;
76
- var value = _a.value, onChange = _a.onChange, allowTemplates = _a.allowTemplates, templates = _a.templates, _d = _a.valueFormat, valueFormat = _d === void 0 ? 'richtext' : _d, singleLine = _a.singleLine, templateToken = _a.templateToken, allowed_values = _a.allowed_values, rest = __rest(_a, ["value", "onChange", "allowTemplates", "templates", "valueFormat", "singleLine", "templateToken", "allowed_values"]);
77
+ var value = _a.value, onChange = _a.onChange, allowTemplates = _a.allowTemplates, templates = _a.templates, _d = _a.valueFormat, valueFormat = _d === void 0 ? 'richtext' : _d, singleLine = _a.singleLine, templateToken = _a.templateToken, allowed_values = _a.allowed_values, choiceChip = _a.choiceChip, rest = __rest(_a, ["value", "onChange", "allowTemplates", "templates", "valueFormat", "singleLine", "templateToken", "allowed_values", "choiceChip"]);
77
78
  var isText = valueFormat === 'text';
79
+ /* The Slate editor behind Reqore's, for the two chip actions below: both
80
+ rewrite the document in place, which the editor's props cannot. */
81
+ var editorRef = (0, react_1.useRef)(null);
82
+ var chipBehavior = __assign(__assign({}, choiceChip_1.DEFAULT_CHOICE_CHIP_BEHAVIOR), choiceChip);
78
83
  /* The document the editor shows for a value: a choice by its chip, a text
79
84
  with its references as chips, a document as it is. */
80
85
  var toLocal = function (next) {
@@ -87,6 +92,18 @@ exports.RichTextFormField = (0, react_1.memo)(function (_a) {
87
92
  return choice ? (0, choiceChip_1.choiceToNodes)(choice) : next;
88
93
  };
89
94
  var _e = (0, react_1.useState)(function () { return toLocal(value); }), localValue = _e[0], setLocalValue = _e[1];
95
+ /* What a value stands for: the choice's value when the value is that choice
96
+ by any spelling — the plain string, the chip, a document of just the text —
97
+ else the value itself. Values are compared by this, so opening a chip, or
98
+ typing its id back, is not a change to the value. */
99
+ var standsFor = function (next) {
100
+ var chip = (0, choiceChip_1.choiceValueOfNodes)(next);
101
+ if (chip !== undefined) {
102
+ return chip;
103
+ }
104
+ var choice = (0, choiceChip_1.choiceForValue)(next, allowed_values);
105
+ return choice ? (0, choiceChip_1.choiceValue)(choice) : next;
106
+ };
90
107
  /* In text mode, the string the editor's document stands for. The value that
91
108
  comes back from the parent is usually that same string, and rebuilding the
92
109
  document from it would hand the editor a new tree on every keystroke —
@@ -97,7 +114,6 @@ exports.RichTextFormField = (0, react_1.memo)(function (_a) {
97
114
  them away. See `EmittedValues`. */
98
115
  var emitted = (0, emittedValues_1.useEmittedValues)(lodash_1.isEqual);
99
116
  (0, react_1.useEffect)(function () {
100
- var _a;
101
117
  if (emitted.isEcho(isText ? String(value !== null && value !== void 0 ? value : '') : value)) {
102
118
  return;
103
119
  }
@@ -109,9 +125,9 @@ exports.RichTextFormField = (0, react_1.memo)(function (_a) {
109
125
  }
110
126
  return;
111
127
  }
112
- // Compared as what the document stands for: a lone choice chip IS the
113
- // value it draws, so the value coming back is not a change to it.
114
- if (JSON.stringify(value) !== JSON.stringify((_a = (0, choiceChip_1.choiceValueOfNodes)(localValue)) !== null && _a !== void 0 ? _a : localValue)) {
128
+ // Compared as what each stands for: a lone choice chip IS the value it
129
+ // draws, so the value coming back is not a change to it.
130
+ if (!(0, lodash_1.isEqual)(standsFor(value), standsFor(localValue))) {
115
131
  setLocalValue(toLocal(value));
116
132
  }
117
133
  }, [JSON.stringify(value)]);
@@ -143,7 +159,7 @@ exports.RichTextFormField = (0, react_1.memo)(function (_a) {
143
159
  // A document that is nothing but one choice chip is emitted as the
144
160
  // choice's value — what was stored and what the server resolves.
145
161
  var next = (_a = (0, choiceChip_1.choiceValueOfNodes)(localValue)) !== null && _a !== void 0 ? _a : localValue;
146
- if (!(0, lodash_1.isEqual)(next, value)) {
162
+ if (!(0, lodash_1.isEqual)(standsFor(next), standsFor(value))) {
147
163
  emitted.record(next);
148
164
  onChange === null || onChange === void 0 ? void 0 : onChange(next);
149
165
  }
@@ -180,6 +196,39 @@ exports.RichTextFormField = (0, react_1.memo)(function (_a) {
180
196
  var descriptionByValue = (0, react_1.useMemo)(function () { return (0, exports.getChipTooltipDescriptions)(templates); }, [
181
197
  JSON.stringify(templates),
182
198
  ]);
199
+ /* Opens a choice chip into its value as text and puts the cursor there.
200
+ A click on the chip — a non-editable node — need not have given the
201
+ editor focus, so focus is asked of Slate, which places the DOM caret where
202
+ the selection is and focuses after; but only once the text the chip became
203
+ is rendered (the effect below), since Slate resolves the caret through the
204
+ rendered DOM. Asked any earlier it lost: a DOM `focus()` before the
205
+ transform let the browser put the caret at the editor's start and the
206
+ `selectionchange` it raised beat the render, so the next key typed landed
207
+ there; asked on the next frame, the frame came before React's commit
208
+ often enough. An editor that already has focus (Backspace came from it)
209
+ is returned at once, and its own render puts the caret where the
210
+ selection is. */
211
+ var focusOnceRendered = (0, react_1.useRef)(false);
212
+ var openChoiceChip = (0, react_1.useCallback)(function (path) {
213
+ var editor = editorRef.current;
214
+ if (editor && path && (0, choiceChip_1.unwrapChoiceChip)(editor, path)) {
215
+ focusOnceRendered.current = true;
216
+ }
217
+ }, []);
218
+ (0, react_1.useEffect)(function () {
219
+ var editor = editorRef.current;
220
+ if (!focusOnceRendered.current || !editor) {
221
+ return;
222
+ }
223
+ focusOnceRendered.current = false;
224
+ try {
225
+ slate_react_1.ReactEditor.toDOMNode(editor, editor);
226
+ slate_react_1.ReactEditor.focus(editor);
227
+ }
228
+ catch (_a) {
229
+ // Not mounted in a document — nothing to focus.
230
+ }
231
+ }, [localValue]);
183
232
  var handleGetTagProps = (0, react_1.useCallback)(function (tag) {
184
233
  var _a, _b, _c, _d, _e, _f;
185
234
  var tagValue = (_a = tag.value) === null || _a === void 0 ? void 0 : _a.toString();
@@ -189,11 +238,9 @@ exports.RichTextFormField = (0, react_1.memo)(function (_a) {
189
238
  /* One of the field's own choices, drawn by the name it was picked by;
190
239
  what it stands for on hover. */
191
240
  if ((_b = tag.metadata) === null || _b === void 0 ? void 0 : _b.allowedValue) {
192
- return {
193
- icon: 'ListCheck',
194
- label: (_c = tag.label) !== null && _c !== void 0 ? _c : tagValue,
195
- tooltip: (_d = tag.metadata) === null || _d === void 0 ? void 0 : _d.description,
196
- };
241
+ return __assign({ icon: 'ListCheck', label: (_c = tag.label) !== null && _c !== void 0 ? _c : tagValue, tooltip: (_d = tag.metadata) === null || _d === void 0 ? void 0 : _d.description }, (chipBehavior.click === 'unwrap' ?
242
+ { onClick: function () { return openChoiceChip(editorRef.current ? (0, choiceChip_1.pathOfNode)(editorRef.current, tag) : undefined); } }
243
+ : {}));
197
244
  }
198
245
  /* A reference in a string is drawn exactly as the collapsed row draws the
199
246
  same value (`ReadOnlyTemplateTag`): named from the catalogue, its
@@ -237,14 +284,42 @@ exports.RichTextFormField = (0, react_1.memo)(function (_a) {
237
284
  : undefined }, (0, templates_1.getTemplateTagStyle)(tag.metadata));
238
285
  }
239
286
  return {};
240
- }, [descriptionByValue, renderMarkdown, isText, templates]);
287
+ }, [descriptionByValue, renderMarkdown, isText, templates, chipBehavior.click, openChoiceChip]);
288
+ /* Leaving the field: text that is exactly one of the choices becomes its
289
+ chip again, as the picker would have drawn it. Only here, never while
290
+ typing — a choice can be the start of a longer value, and a chip drawn
291
+ under the cursor would swallow it. */
292
+ var handleBlur = (0, react_1.useCallback)(function (event) {
293
+ var _a, _b;
294
+ var shown = isText ? lastTextRef.current : localValue;
295
+ if ((0, choiceChip_1.choiceForValue)(shown, allowed_values)) {
296
+ setLocalValue(toLocal(shown));
297
+ }
298
+ (_b = (_a = rest).onBlur) === null || _b === void 0 ? void 0 : _b.call(_a, event);
299
+ }, [isText, localValue, choiceKey, rest.onBlur]);
241
300
  var handleKeyDown = (0, react_1.useCallback)(function (event) {
242
301
  var _a, _b;
243
302
  if (isText && singleLine && event.key === 'Enter') {
244
303
  event.preventDefault();
245
304
  }
305
+ /* Backspace right after a choice chip opens it rather than deleting it,
306
+ when so configured. Stopped here, at keydown, so the browser raises no
307
+ `beforeinput` for the editor to delete the chip by. */
308
+ if (event.key === 'Backspace' && chipBehavior.backspace === 'unwrap' && editorRef.current) {
309
+ var path = (0, choiceChip_1.choiceChipAtCursor)(editorRef.current);
310
+ if (path) {
311
+ event.preventDefault();
312
+ openChoiceChip(path);
313
+ }
314
+ }
246
315
  (_b = (_a = rest).onKeyDown) === null || _b === void 0 ? void 0 : _b.call(_a, event);
247
- }, [isText, singleLine, rest.onKeyDown]);
316
+ }, [
317
+ isText,
318
+ singleLine,
319
+ chipBehavior.backspace,
320
+ openChoiceChip,
321
+ rest.onKeyDown,
322
+ ]);
248
323
  var tags = (0, react_1.useMemo)(function () {
249
324
  var _tags = {};
250
325
  if ((0, lodash_1.size)(templates === null || templates === void 0 ? void 0 : templates.items) && allowTemplates) {
@@ -282,9 +357,9 @@ exports.RichTextFormField = (0, react_1.memo)(function (_a) {
282
357
  editor's `tags` is the template catalogue this component computes. */
283
358
  var editorProps = __assign({}, rest);
284
359
  delete editorProps.tags;
285
- return ((0, jsx_runtime_1.jsx)(RichTextEditor_1.ReqoreRichTextEditor, __assign({ value: formattedValue, onChange: handleChange }, editorProps, { tagsListProps: __assign({ useTargetWidth: true, minWidth: '300px', maxWidth: '600px', listCustomTheme: {
360
+ return ((0, jsx_runtime_1.jsx)(RichTextEditor_1.ReqoreRichTextEditor, __assign({ ref: editorRef, value: formattedValue, onChange: handleChange }, editorProps, { tagsListProps: __assign({ useTargetWidth: true, minWidth: '300px', maxWidth: '600px', listCustomTheme: {
286
361
  main: '#1b151f',
287
- } }, (rest.tagsListProps || {})), getTagProps: handleGetTagProps, tags: tags, panelProps: { fluid: true, style: __assign({ minWidth: '150px' }, (_c = rest.panelProps) === null || _c === void 0 ? void 0 : _c.style) }, readOnly: readOnly, onKeyDown: handleKeyDown,
362
+ } }, (rest.tagsListProps || {})), getTagProps: handleGetTagProps, tags: tags, panelProps: { fluid: true, style: __assign({ minWidth: '150px' }, (_c = rest.panelProps) === null || _c === void 0 ? void 0 : _c.style) }, readOnly: readOnly, onKeyDown: handleKeyDown, onBlur: handleBlur,
288
363
  /* A form field carries no document toolbar. Styling was already off, so
289
364
  the bar held only undo and redo — drawn by Reqore as a panel as wide as
290
365
  the tag list, which under a field reads as an empty 600px menu with two
@@ -1 +1 @@
1
- {"version":3,"file":"RichText.js","sourceRoot":"","sources":["../../../../../src/components/form/fields/rich-text/RichText.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"RichText.js","sourceRoot":"","sources":["../../../../../src/components/form/fields/rich-text/RichText.tsx"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { IQorusAllowedValue } from '@qoretechnologies/ts-toolkit';
2
+ import { Editor, Path } from 'slate';
2
3
  /**
3
4
  * A value that IS one of the field's own choices, drawn as that choice.
4
5
  *
@@ -25,10 +26,18 @@ export interface IChoiceChipNode {
25
26
  text: '';
26
27
  }];
27
28
  }
29
+ /** The choice's value as the plain string it is; it arrives in the form engine's `{type, value}` envelope. */
30
+ export declare const choiceValue: (choice: IQorusAllowedValue) => string;
28
31
  /**
29
- * The choice a value is, when the value is a whole plain string the field
30
- * offers. A document, or a string holding more than the choice, is the
31
- * author's own text and is never a choice.
32
+ * The text a document is, when it is one paragraph of plain text and nothing
33
+ * else; `undefined` for anything more — a chip, a mark, a second paragraph.
34
+ */
35
+ export declare const plainTextOfNodes: (nodes: unknown) => string | undefined;
36
+ /**
37
+ * The choice a value is: a whole plain string the field offers, or a document
38
+ * that is one paragraph of exactly that text — which is what an edit of the
39
+ * chip stores, so an id typed back is the choice it was. A string or document
40
+ * holding anything more is the author's own text and is never a choice.
32
41
  */
33
42
  export declare const choiceForValue: (value: unknown, choices?: IQorusAllowedValue[]) => IQorusAllowedValue | undefined;
34
43
  /** The one-chip document that draws a choice by its name. */
@@ -38,10 +47,52 @@ export declare const choiceToNodes: (choice: IQorusAllowedValue) => {
38
47
  text: string;
39
48
  } | IChoiceChipNode)[];
40
49
  }[];
50
+ export declare const isChoiceChip: (node: unknown) => node is IChoiceChipNode;
41
51
  /**
42
52
  * The value a document is, when the document is one choice chip and nothing
43
53
  * else; `undefined` when the author has written anything around it, in which
44
54
  * case the document itself is the value.
45
55
  */
46
56
  export declare const choiceValueOfNodes: (nodes: unknown) => string | undefined;
57
+ /**
58
+ * What a choice chip does when the author acts on it, by action.
59
+ *
60
+ * The chip is a void: it holds no text of its own, so a key or a click on it
61
+ * has nothing to land in, and an author who wants to change one letter of the
62
+ * value it draws (`C07ERBFS0P6` to `C07ERBFS0P7`) has no way in unless the
63
+ * chip opens. Each action is configurable, and the default is the one that
64
+ * opens it: a creatable choice is the author's to edit.
65
+ */
66
+ export interface IChoiceChipBehavior {
67
+ /**
68
+ * Backspace with the cursor right after the chip. `unwrap` (the default)
69
+ * turns the chip into its value as plain text, the cursor at the end of it,
70
+ * for the author to edit; `remove` deletes it whole, as the editor deletes
71
+ * any other chip.
72
+ */
73
+ backspace?: 'unwrap' | 'remove';
74
+ /**
75
+ * A click on the chip's body. `unwrap` (the default) turns the chip into its
76
+ * value as plain text, the cursor at the end of it; `cursor` only places the
77
+ * cursor after it, as a click on a template chip does.
78
+ */
79
+ click?: 'unwrap' | 'cursor';
80
+ }
81
+ export declare const DEFAULT_CHOICE_CHIP_BEHAVIOR: Required<IChoiceChipBehavior>;
82
+ /** Where the node is in the document, by identity; the editor renders the document's own nodes, so a chip handed to a click handler is one of them. */
83
+ export declare const pathOfNode: (editor: Editor, node: unknown) => Path | undefined;
84
+ /**
85
+ * The chip the cursor is on: right after it with nothing between, where
86
+ * Backspace would take it, or inside it, where the arrow keys can leave the
87
+ * cursor. Nothing when the selection spans text or sits anywhere else.
88
+ */
89
+ export declare const choiceChipAtCursor: (editor: Editor) => Path | undefined;
90
+ /**
91
+ * Opens the chip at `path` into its value as plain text, the cursor at the
92
+ * end of the text: what the author read is what they chose, now editable
93
+ * letter by letter. The document is text from here on, and is stored as the
94
+ * field stores anything typed; it is drawn as a chip again only when it is
95
+ * read back as exactly one of the choices.
96
+ */
97
+ export declare const unwrapChoiceChip: (editor: Editor, path: Path) => boolean;
47
98
  //# sourceMappingURL=choiceChip.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"choiceChip.d.ts","sourceRoot":"","sources":["../../src/helpers/choiceChip.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAyB,MAAM,8BAA8B,CAAC;AAIzF;;;;;;;;;;;GAWG;AAEH,uFAAuF;AACvF,eAAO,MAAM,gBAAgB,iBAAiB,CAAC;AAE/C,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,KAAK,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE;QAAE,CAAC,gBAAgB,CAAC,EAAE,IAAI,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7D,QAAQ,EAAE,CAAC;QAAE,IAAI,EAAE,EAAE,CAAA;KAAE,CAAC,CAAC;CAC1B;AAED;;;;GAIG;AACH,eAAO,MAAM,cAAc,UAClB,OAAO,YACJ,kBAAkB,EAAE,KAC7B,kBAAkB,GAAG,SAQvB,CAAC;AAEF,6DAA6D;AAC7D,eAAO,MAAM,aAAa,WAChB,kBAAkB,KACzB;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,EAAE,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,eAAe,CAAC,EAAE,CAAA;CAAE,EAqBzE,CAAC;AAQF;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,UAAW,OAAO,KAAG,MAAM,GAAG,SAa5D,CAAC"}
1
+ {"version":3,"file":"choiceChip.d.ts","sourceRoot":"","sources":["../../src/helpers/choiceChip.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAyB,MAAM,8BAA8B,CAAC;AACzF,OAAO,EAAE,MAAM,EAAQ,IAAI,EAAqB,MAAM,OAAO,CAAC;AAI9D;;;;;;;;;;;GAWG;AAEH,uFAAuF;AACvF,eAAO,MAAM,gBAAgB,iBAAiB,CAAC;AAE/C,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,KAAK,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE;QAAE,CAAC,gBAAgB,CAAC,EAAE,IAAI,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7D,QAAQ,EAAE,CAAC;QAAE,IAAI,EAAE,EAAE,CAAA;KAAE,CAAC,CAAC;CAC1B;AAED,8GAA8G;AAC9G,eAAO,MAAM,WAAW,WAAY,kBAAkB,KAAG,MACR,CAAC;AAElD;;;GAGG;AACH,eAAO,MAAM,gBAAgB,UAAW,OAAO,KAAG,MAAM,GAAG,SAqB1D,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,cAAc,UAClB,OAAO,YACJ,kBAAkB,EAAE,KAC7B,kBAAkB,GAAG,SAUvB,CAAC;AAEF,6DAA6D;AAC7D,eAAO,MAAM,aAAa,WAChB,kBAAkB,KACzB;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,EAAE,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,eAAe,CAAC,EAAE,CAAA;CAAE,EAoBzE,CAAC;AAEF,eAAO,MAAM,YAAY,SAAU,OAAO,4BAIuC,CAAC;AAElF;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,UAAW,OAAO,KAAG,MAAM,GAAG,SAa5D,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAChC;;;;OAIG;IACH,KAAK,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;CAC7B;AAED,eAAO,MAAM,4BAA4B,EAAE,QAAQ,CAAC,mBAAmB,CAGtE,CAAC;AAEF,uJAAuJ;AACvJ,eAAO,MAAM,UAAU,WAAY,MAAM,QAAQ,OAAO,KAAG,IAAI,GAAG,SAWjE,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,WAAY,MAAM,KAAG,IAAI,GAAG,SAqB1D,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,WAAY,MAAM,iBAAe,OAc7D,CAAC"}
@@ -11,7 +11,8 @@ var __assign = (this && this.__assign) || function () {
11
11
  return __assign.apply(this, arguments);
12
12
  };
13
13
  Object.defineProperty(exports, "__esModule", { value: true });
14
- exports.choiceValueOfNodes = exports.choiceToNodes = exports.choiceForValue = exports.CHOICE_CHIP_META = void 0;
14
+ exports.unwrapChoiceChip = exports.choiceChipAtCursor = exports.pathOfNode = exports.DEFAULT_CHOICE_CHIP_BEHAVIOR = exports.choiceValueOfNodes = exports.isChoiceChip = exports.choiceToNodes = exports.choiceForValue = exports.plainTextOfNodes = exports.choiceValue = exports.CHOICE_CHIP_META = void 0;
15
+ var slate_1 = require("slate");
15
16
  var allowedValues_1 = require("./allowedValues");
16
17
  var options_1 = require("./options");
17
18
  /**
@@ -28,25 +29,52 @@ var options_1 = require("./options");
28
29
  */
29
30
  /** The marker a choice chip carries, so it is told apart from a template reference. */
30
31
  exports.CHOICE_CHIP_META = 'allowedValue';
32
+ /** The choice's value as the plain string it is; it arrives in the form engine's `{type, value}` envelope. */
33
+ var choiceValue = function (choice) { var _a; return String((_a = (0, options_1.getListElementValue)(choice.value)) !== null && _a !== void 0 ? _a : ''); };
34
+ exports.choiceValue = choiceValue;
31
35
  /**
32
- * The choice a value is, when the value is a whole plain string the field
33
- * offers. A document, or a string holding more than the choice, is the
34
- * author's own text and is never a choice.
36
+ * The text a document is, when it is one paragraph of plain text and nothing
37
+ * else; `undefined` for anything more — a chip, a mark, a second paragraph.
38
+ */
39
+ var plainTextOfNodes = function (nodes) {
40
+ if (!Array.isArray(nodes) || nodes.length !== 1) {
41
+ return undefined;
42
+ }
43
+ var paragraph = nodes[0];
44
+ if ((paragraph === null || paragraph === void 0 ? void 0 : paragraph.type) !== 'paragraph' || !Array.isArray(paragraph.children)) {
45
+ return undefined;
46
+ }
47
+ var text = '';
48
+ for (var _i = 0, _a = paragraph.children; _i < _a.length; _i++) {
49
+ var child = _a[_i];
50
+ if (typeof (child === null || child === void 0 ? void 0 : child.text) !== 'string' || Object.keys(child).some(function (key) { return key !== 'text'; })) {
51
+ return undefined;
52
+ }
53
+ text += child.text;
54
+ }
55
+ return text;
56
+ };
57
+ exports.plainTextOfNodes = plainTextOfNodes;
58
+ /**
59
+ * The choice a value is: a whole plain string the field offers, or a document
60
+ * that is one paragraph of exactly that text — which is what an edit of the
61
+ * chip stores, so an id typed back is the choice it was. A string or document
62
+ * holding anything more is the author's own text and is never a choice.
35
63
  */
36
64
  var choiceForValue = function (value, choices) {
37
- if (typeof value !== 'string' || !value || !(choices === null || choices === void 0 ? void 0 : choices.length)) {
65
+ var text = typeof value === 'string' ? value : (0, exports.plainTextOfNodes)(value);
66
+ if (!text || !(choices === null || choices === void 0 ? void 0 : choices.length)) {
38
67
  return undefined;
39
68
  }
40
- return (0, allowedValues_1.findAllowedValueOption)(value, { allowed_values: choices });
69
+ return (0, allowedValues_1.findAllowedValueOption)(text, { allowed_values: choices });
41
70
  };
42
71
  exports.choiceForValue = choiceForValue;
43
72
  /** The one-chip document that draws a choice by its name. */
44
73
  var choiceToNodes = function (choice) {
45
74
  var _a;
46
- var _b, _c, _d;
47
- // The choice's value arrives in the form engine's `{type, value}` envelope.
48
- var value = String((_b = (0, options_1.getListElementValue)(choice.value)) !== null && _b !== void 0 ? _b : '');
49
- var description = (_c = choice.short_desc) !== null && _c !== void 0 ? _c : choice.desc;
75
+ var _b, _c;
76
+ var value = (0, exports.choiceValue)(choice);
77
+ var description = (_b = choice.short_desc) !== null && _b !== void 0 ? _b : choice.desc;
50
78
  return [
51
79
  {
52
80
  type: 'paragraph',
@@ -55,7 +83,7 @@ var choiceToNodes = function (choice) {
55
83
  {
56
84
  type: 'tag',
57
85
  value: value,
58
- label: (_d = choice.display_name) !== null && _d !== void 0 ? _d : value,
86
+ label: (_c = choice.display_name) !== null && _c !== void 0 ? _c : value,
59
87
  metadata: __assign((_a = {}, _a[exports.CHOICE_CHIP_META] = true, _a), (description ? { description: description } : {})),
60
88
  children: [{ text: '' }],
61
89
  },
@@ -72,6 +100,7 @@ var isChoiceChip = function (node) {
72
100
  node.type === 'tag' &&
73
101
  !!((_a = node.metadata) === null || _a === void 0 ? void 0 : _a[exports.CHOICE_CHIP_META]);
74
102
  };
103
+ exports.isChoiceChip = isChoiceChip;
75
104
  /**
76
105
  * The value a document is, when the document is one choice chip and nothing
77
106
  * else; `undefined` when the author has written anything around it, in which
@@ -83,12 +112,70 @@ var choiceValueOfNodes = function (nodes) {
83
112
  return undefined;
84
113
  }
85
114
  var children = (_b = (_a = nodes[0]) === null || _a === void 0 ? void 0 : _a.children) !== null && _b !== void 0 ? _b : [];
86
- var chips = children.filter(isChoiceChip);
115
+ var chips = children.filter(exports.isChoiceChip);
87
116
  var text = children
88
- .filter(function (node) { return !isChoiceChip(node); })
117
+ .filter(function (node) { return !(0, exports.isChoiceChip)(node); })
89
118
  .map(function (node) { return (typeof (node === null || node === void 0 ? void 0 : node.text) === 'string' ? node.text : '\u0000'); })
90
119
  .join('');
91
120
  return chips.length === 1 && text === '' ? chips[0].value : undefined;
92
121
  };
93
122
  exports.choiceValueOfNodes = choiceValueOfNodes;
123
+ exports.DEFAULT_CHOICE_CHIP_BEHAVIOR = {
124
+ backspace: 'unwrap',
125
+ click: 'unwrap',
126
+ };
127
+ /** Where the node is in the document, by identity; the editor renders the document's own nodes, so a chip handed to a click handler is one of them. */
128
+ var pathOfNode = function (editor, node) {
129
+ // Stepped by hand: the build target cannot iterate a generator (TS2802).
130
+ var nodes = slate_1.Node.nodes(editor);
131
+ for (var entry = nodes.next(); !entry.done; entry = nodes.next()) {
132
+ if (entry.value[0] === node) {
133
+ return entry.value[1];
134
+ }
135
+ }
136
+ return undefined;
137
+ };
138
+ exports.pathOfNode = pathOfNode;
139
+ /**
140
+ * The chip the cursor is on: right after it with nothing between, where
141
+ * Backspace would take it, or inside it, where the arrow keys can leave the
142
+ * cursor. Nothing when the selection spans text or sits anywhere else.
143
+ */
144
+ var choiceChipAtCursor = function (editor) {
145
+ var selection = editor.selection;
146
+ if (!selection || !slate_1.Range.isCollapsed(selection)) {
147
+ return undefined;
148
+ }
149
+ var _a = selection.anchor, path = _a.path, offset = _a.offset;
150
+ var inside = slate_1.Editor.above(editor, { at: path, match: exports.isChoiceChip, voids: true });
151
+ if (inside) {
152
+ return inside[1];
153
+ }
154
+ if (offset !== 0 || !slate_1.Path.hasPrevious(path)) {
155
+ return undefined;
156
+ }
157
+ var previous = slate_1.Path.previous(path);
158
+ return (0, exports.isChoiceChip)(slate_1.Node.get(editor, previous)) ? previous : undefined;
159
+ };
160
+ exports.choiceChipAtCursor = choiceChipAtCursor;
161
+ /**
162
+ * Opens the chip at `path` into its value as plain text, the cursor at the
163
+ * end of the text: what the author read is what they chose, now editable
164
+ * letter by letter. The document is text from here on, and is stored as the
165
+ * field stores anything typed; it is drawn as a chip again only when it is
166
+ * read back as exactly one of the choices.
167
+ */
168
+ var unwrapChoiceChip = function (editor, path) {
169
+ var chip = slate_1.Node.get(editor, path);
170
+ if (!(0, exports.isChoiceChip)(chip)) {
171
+ return false;
172
+ }
173
+ slate_1.Editor.withoutNormalizing(editor, function () {
174
+ slate_1.Transforms.removeNodes(editor, { at: path });
175
+ slate_1.Transforms.insertNodes(editor, [{ text: chip.value }], { at: path });
176
+ slate_1.Transforms.select(editor, slate_1.Editor.end(editor, path));
177
+ });
178
+ return true;
179
+ };
180
+ exports.unwrapChoiceChip = unwrapChoiceChip;
94
181
  //# sourceMappingURL=choiceChip.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"choiceChip.js","sourceRoot":"","sources":["../../src/helpers/choiceChip.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"choiceChip.js","sourceRoot":"","sources":["../../src/helpers/choiceChip.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qoretechnologies/reqraft",
3
- "version": "0.10.62-pr.141.g7591ef9",
3
+ "version": "0.10.62-pr.141.gd67d7d6",
4
4
  "description": "ReQraft is a collection of React components and hooks that are used across Qore Technologies' products made using the ReQore component library from Qore.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -9815,3 +9815,100 @@ export const PickingARichTextChoiceShowsItsName: Story = {
9815
9815
  await expectChannelChip(canvasElement);
9816
9816
  },
9817
9817
  };
9818
+
9819
+ export const ARichTextChoiceRetypedReturnsToItsChip: Story = {
9820
+ parameters: {
9821
+ docs: {
9822
+ description: {
9823
+ story:
9824
+ 'Renders a compact form whose rich-text Channel option shows its stored choice as the chip "general". A click opens the chip into C07ERBFS0P6 as text; Backspace makes the form emit C07ERBFS0P and a typed 6 makes it emit C07ERBFS0P6 again, each as a document and still shown as text while the author types; Tab out of the editor draws the chip "general" again and emits nothing further, since that document already stands for the choice.',
9825
+ },
9826
+ },
9827
+ },
9828
+ args: {
9829
+ compact: true,
9830
+ minColumnWidth: '360px',
9831
+ initialExpandedOptions: ['channel'],
9832
+ value: { channel: { type: 'richtext', value: 'C07ERBFS0P6' } },
9833
+ options: RICH_TEXT_CHOICE_OPTIONS,
9834
+ },
9835
+ play: async ({ args, canvasElement }) => {
9836
+ await expectChannelChip(canvasElement);
9837
+ const row = canvasElement.querySelector('[data-field="channel"]') as HTMLElement;
9838
+ const editor = row.querySelector('[contenteditable="true"]') as HTMLElement;
9839
+
9840
+ await userEvent.click(within(row).getByText('general'));
9841
+ await waitFor(() => {
9842
+ expect(editor.querySelector('.reqore-tag')).toBeNull();
9843
+ expect(editor.contains(document.activeElement)).toBe(true);
9844
+ });
9845
+
9846
+ const channelValue = (text: string) =>
9847
+ expect.objectContaining({
9848
+ channel: expect.objectContaining({ value: [{ type: 'paragraph', children: [{ text }] }] }),
9849
+ });
9850
+
9851
+ // One key at a time, each emitted before the next: typed within the
9852
+ // field's debounce, the two would settle as the value the field started
9853
+ // with, and nothing would be emitted at all.
9854
+ await userEvent.keyboard('{Backspace}');
9855
+ await waitFor(() =>
9856
+ expect(args.onChange).toHaveBeenLastCalledWith('test', channelValue('C07ERBFS0P'), undefined)
9857
+ );
9858
+ await userEvent.keyboard('6');
9859
+ await waitFor(() =>
9860
+ expect(args.onChange).toHaveBeenLastCalledWith('test', channelValue('C07ERBFS0P6'), undefined)
9861
+ );
9862
+ await expect(editor.querySelector('.reqore-tag')).toBeNull();
9863
+
9864
+ await userEvent.tab();
9865
+ await expectChannelChip(canvasElement);
9866
+ // Leaving the row changed nothing: the chip stands for what was emitted.
9867
+ await expect(args.onChange).toHaveBeenLastCalledWith('test', channelValue('C07ERBFS0P6'), undefined);
9868
+ },
9869
+ };
9870
+
9871
+ export const ClickingARichTextChoiceEditsItsValue: Story = {
9872
+ parameters: {
9873
+ docs: {
9874
+ description: {
9875
+ story:
9876
+ 'Renders a compact form whose rich-text Channel option shows its stored choice as the chip "general". A click on the chip opens it into its value as editable text: the row shows C07ERBFS0P6 and no chip, with the cursor at the end, so Backspace and a typed 7 make it C07ERBFS0P7 — the value the form then emits for the option.',
9877
+ },
9878
+ },
9879
+ },
9880
+ args: {
9881
+ compact: true,
9882
+ minColumnWidth: '360px',
9883
+ initialExpandedOptions: ['channel'],
9884
+ value: { channel: { type: 'richtext', value: 'C07ERBFS0P6' } },
9885
+ options: RICH_TEXT_CHOICE_OPTIONS,
9886
+ },
9887
+ play: async ({ args, canvasElement }) => {
9888
+ await expectChannelChip(canvasElement);
9889
+ const row = canvasElement.querySelector('[data-field="channel"]') as HTMLElement;
9890
+ const editor = row.querySelector('[contenteditable="true"]') as HTMLElement;
9891
+
9892
+ // The chip's label: a tag binds its click to its content, not its frame.
9893
+ await userEvent.click(within(row).getByText('general'));
9894
+ await waitFor(() => {
9895
+ expect(editor.querySelector('.reqore-tag')).toBeNull();
9896
+ expect(editor.textContent).toBe('C07ERBFS0P6');
9897
+ expect(editor.contains(document.activeElement)).toBe(true);
9898
+ });
9899
+
9900
+ await userEvent.keyboard('{Backspace}7');
9901
+ await waitFor(() => expect(editor.textContent).toBe('C07ERBFS0P7'));
9902
+ await waitFor(() =>
9903
+ expect(args.onChange).toHaveBeenLastCalledWith(
9904
+ 'test',
9905
+ expect.objectContaining({
9906
+ channel: expect.objectContaining({
9907
+ value: [{ type: 'paragraph', children: [{ text: 'C07ERBFS0P7' }] }],
9908
+ }),
9909
+ }),
9910
+ undefined
9911
+ )
9912
+ );
9913
+ },
9914
+ };
@@ -1,5 +1,5 @@
1
1
  import { StoryObj } from '@storybook/react-vite';
2
- import { expect, fn, within } from 'storybook/test';
2
+ import { expect, fn, userEvent, waitFor, within } from 'storybook/test';
3
3
  import { useState } from 'react';
4
4
 
5
5
  import { StoryMeta } from '../../../../types';
@@ -76,6 +76,144 @@ export const WithChoiceValue: Story = {
76
76
  },
77
77
  };
78
78
 
79
+ export const WithChoiceValueAsDocument: Story = {
80
+ args: {
81
+ ...WithChoiceValue.args,
82
+ value: [{ type: 'paragraph', children: [{ text: 'C07ERBFS0P6' }] }] as never,
83
+ },
84
+ parameters: {
85
+ docs: {
86
+ description: {
87
+ story:
88
+ 'Renders the RichText field holding a document that is nothing but the id of one of its choices — what an edit of the chip stores — drawn as the chip "general"; the id is not shown, and nothing is emitted for it, since the document already stands for the choice.',
89
+ },
90
+ },
91
+ },
92
+ async play({ args, canvasElement }) {
93
+ const canvas = within(canvasElement);
94
+ await expect(canvas.getByText('general')).toBeInTheDocument();
95
+ await expect(canvas.queryByText('C07ERBFS0P6')).not.toBeInTheDocument();
96
+ await new Promise((resolve) => setTimeout(resolve, 400));
97
+ await expect(args.onChange).not.toHaveBeenCalled();
98
+ },
99
+ };
100
+
101
+ export const RetypingTheChoiceReturnsItsChip: Story = {
102
+ args: WithChoiceValue.args,
103
+ parameters: {
104
+ docs: {
105
+ description: {
106
+ story:
107
+ 'Renders the RichText field holding a choice drawn as the chip "general". A click opens it into C07ERBFS0P6 as text; Backspace emits C07ERBFS0P, and a typed 6 emits C07ERBFS0P6 again, each as a document and still shown as text while the author types; leaving the field with Tab draws it as the chip "general" once more and emits nothing further, since that document already stands for the choice.',
108
+ },
109
+ },
110
+ },
111
+ async play({ args, canvasElement }) {
112
+ const canvas = within(canvasElement);
113
+ const editor = canvas.getByRole('textbox');
114
+
115
+ await userEvent.click(canvas.getByText('general'));
116
+ await waitFor(() => {
117
+ expect(editor.querySelector('.reqore-tag')).toBeNull();
118
+ expect(editor.contains(document.activeElement)).toBe(true);
119
+ });
120
+
121
+ // One key at a time, each emitted before the next: typed within the
122
+ // field's debounce, the two would settle as the value the field started
123
+ // with, and nothing would be emitted at all.
124
+ await userEvent.keyboard('{Backspace}');
125
+ await waitFor(() =>
126
+ expect(args.onChange).toHaveBeenLastCalledWith([
127
+ { type: 'paragraph', children: [{ text: 'C07ERBFS0P' }] },
128
+ ])
129
+ );
130
+ await userEvent.keyboard('6');
131
+ await waitFor(() =>
132
+ expect(args.onChange).toHaveBeenLastCalledWith([
133
+ { type: 'paragraph', children: [{ text: 'C07ERBFS0P6' }] },
134
+ ])
135
+ );
136
+ await expect(editor.querySelector('.reqore-tag')).toBeNull();
137
+
138
+ await userEvent.tab();
139
+ await waitFor(() => {
140
+ expect(editor.querySelector('.reqore-tag')?.textContent).toContain('general');
141
+ expect(editor.textContent).not.toContain('C07ERBFS0P6');
142
+ });
143
+ // Leaving the field changed nothing: the chip stands for what was emitted.
144
+ await expect(args.onChange).toHaveBeenLastCalledWith([
145
+ { type: 'paragraph', children: [{ text: 'C07ERBFS0P6' }] },
146
+ ]);
147
+ },
148
+ };
149
+
150
+ export const ClickOpensTheChoiceChip: Story = {
151
+ args: WithChoiceValue.args,
152
+ parameters: {
153
+ docs: {
154
+ description: {
155
+ story:
156
+ 'Renders the RichText field holding a choice drawn as the chip "general", with the default chip behaviour. A click on the chip opens it into its value as editable text: the editor shows C07ERBFS0P6 and no chip, the cursor at its end, so Backspace and a typed 7 make it C07ERBFS0P7, which is what the field emits.',
157
+ },
158
+ },
159
+ },
160
+ async play({ args, canvasElement }) {
161
+ const canvas = within(canvasElement);
162
+ const editor = canvas.getByRole('textbox');
163
+
164
+ await userEvent.click(canvas.getByText('general'));
165
+ await waitFor(() => {
166
+ expect(editor.querySelector('.reqore-tag')).toBeNull();
167
+ expect(editor.textContent).toBe('C07ERBFS0P6');
168
+ expect(editor.contains(document.activeElement)).toBe(true);
169
+ });
170
+
171
+ await userEvent.keyboard('{Backspace}7');
172
+ await waitFor(() => expect(editor.textContent).toBe('C07ERBFS0P7'));
173
+ await waitFor(() =>
174
+ expect(args.onChange).toHaveBeenLastCalledWith([
175
+ { type: 'paragraph', children: [{ text: 'C07ERBFS0P7' }] },
176
+ ])
177
+ );
178
+ },
179
+ };
180
+
181
+ export const BackspaceOpensTheChoiceChip: Story = {
182
+ args: {
183
+ ...WithChoiceValue.args,
184
+ choiceChip: { click: 'cursor' },
185
+ },
186
+ parameters: {
187
+ docs: {
188
+ description: {
189
+ story:
190
+ 'Renders the RichText field holding a choice drawn as the chip "general", configured so that a click on the chip only places the cursor after it. Backspace then opens the chip into its value as editable text: the editor shows C07ERBFS0P6 and no chip, the cursor at its end, so one more Backspace and a typed 7 make it C07ERBFS0P7, which is what the field emits.',
191
+ },
192
+ },
193
+ },
194
+ async play({ args, canvasElement }) {
195
+ const canvas = within(canvasElement);
196
+ const editor = canvas.getByRole('textbox');
197
+
198
+ await userEvent.click(canvas.getByText('general'));
199
+ await waitFor(() => expect(editor.contains(document.activeElement)).toBe(true));
200
+
201
+ await userEvent.keyboard('{Backspace}');
202
+ await waitFor(() => {
203
+ expect(editor.querySelector('.reqore-tag')).toBeNull();
204
+ expect(editor.textContent).toBe('C07ERBFS0P6');
205
+ });
206
+
207
+ await userEvent.keyboard('{Backspace}7');
208
+ await waitFor(() => expect(editor.textContent).toBe('C07ERBFS0P7'));
209
+ await waitFor(() =>
210
+ expect(args.onChange).toHaveBeenLastCalledWith([
211
+ { type: 'paragraph', children: [{ text: 'C07ERBFS0P7' }] },
212
+ ])
213
+ );
214
+ },
215
+ };
216
+
79
217
  export const Empty: Story = {
80
218
  parameters: {
81
219
  docs: {
@@ -1,16 +1,29 @@
1
1
  import {
2
2
  IReqoreRichTextEditorProps,
3
3
  ReqoreRichTextEditor,
4
+ TReqoreRichTextEditorRef,
4
5
  } from '@qoretechnologies/reqore/dist/components/RichTextEditor';
5
6
  import { IReqoreFormTemplates } from '@qoretechnologies/reqore/dist/components/Textarea';
6
7
  import { IReqoreTagProps } from '@qoretechnologies/reqore/dist/components/Tag';
7
8
  import { IReqoreTooltip } from '@qoretechnologies/reqore/dist/types/global';
8
9
  import { IQorusAllowedValue } from '@qoretechnologies/ts-toolkit';
9
10
  import { isEqual, size } from 'lodash';
10
- import { KeyboardEvent, memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
11
+ import { FocusEvent, KeyboardEvent, memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
11
12
  import { useDebounce } from 'react-use';
13
+ import { Path } from 'slate';
14
+ import { ReactEditor } from 'slate-react';
12
15
  import { useEmittedValues } from '../emittedValues';
13
- import { choiceForValue, choiceToNodes, choiceValueOfNodes } from '../../../../helpers/choiceChip';
16
+ import {
17
+ choiceChipAtCursor,
18
+ choiceForValue,
19
+ choiceToNodes,
20
+ choiceValue,
21
+ choiceValueOfNodes,
22
+ DEFAULT_CHOICE_CHIP_BEHAVIOR,
23
+ IChoiceChipBehavior,
24
+ pathOfNode,
25
+ unwrapChoiceChip,
26
+ } from '../../../../helpers/choiceChip';
14
27
  import { flattenToSingleLine, hasLineBreak } from '../../../../helpers/singleLineString';
15
28
  import {
16
29
  renderTemplateItemDescriptions,
@@ -61,13 +74,23 @@ export interface IRichTextFormFieldProps extends Omit<
61
74
  singleLine?: boolean;
62
75
  /**
63
76
  * The choices the field offers, when it offers any. A value that IS one of
64
- * them — the whole string, as picked from the field's suggestions — is drawn
65
- * as one chip named from the choice (`general` rather than `C07ERBFS0P6`),
66
- * and is still emitted as that value: the chip's own value is the choice's,
67
- * and a document that is nothing but the chip reads back as it. A field
68
- * spreads its schema here, so this is the schema's own key.
77
+ * them — the whole string, as picked from the field's suggestions, or a
78
+ * document of nothing but that string, as an edit of it stores — is drawn as
79
+ * one chip named from the choice (`general` rather than `C07ERBFS0P6`), and
80
+ * is still emitted as that value: the chip's own value is the choice's, and a
81
+ * document that is nothing but the chip reads back as it. A field spreads
82
+ * its schema here, so this is the schema's own key.
69
83
  */
70
84
  allowed_values?: IQorusAllowedValue[];
85
+ /**
86
+ * What a choice chip does when the author acts on it — Backspace right after
87
+ * it, a click on it. By default each opens the chip into its value as plain
88
+ * text, the cursor at the end, so one letter of what was chosen can be
89
+ * changed; see `IChoiceChipBehavior` for the alternatives. Text that is again
90
+ * exactly one of the choices becomes its chip when the author leaves the
91
+ * field — not while typing, where a choice can be the start of a longer value.
92
+ */
93
+ choiceChip?: IChoiceChipBehavior;
71
94
  /**
72
95
  * With `valueFormat: 'text'`: the token grammar the value's references are
73
96
  * WRITTEN in, when the host speaks one of its own.
@@ -131,9 +154,14 @@ export const RichTextFormField = memo(({
131
154
  singleLine,
132
155
  templateToken,
133
156
  allowed_values,
157
+ choiceChip,
134
158
  ...rest
135
159
  }: IRichTextFormFieldProps) => {
136
160
  const isText = valueFormat === 'text';
161
+ /* The Slate editor behind Reqore's, for the two chip actions below: both
162
+ rewrite the document in place, which the editor's props cannot. */
163
+ const editorRef = useRef<TReqoreRichTextEditorRef>(null);
164
+ const chipBehavior = { ...DEFAULT_CHOICE_CHIP_BEHAVIOR, ...choiceChip };
137
165
  /* The document the editor shows for a value: a choice by its chip, a text
138
166
  with its references as chips, a document as it is. */
139
167
  const toLocal = (next: unknown): any => {
@@ -146,6 +174,18 @@ export const RichTextFormField = memo(({
146
174
  return choice ? choiceToNodes(choice) : next;
147
175
  };
148
176
  const [localValue, setLocalValue] = useState<any>(() => toLocal(value));
177
+ /* What a value stands for: the choice's value when the value is that choice
178
+ by any spelling — the plain string, the chip, a document of just the text —
179
+ else the value itself. Values are compared by this, so opening a chip, or
180
+ typing its id back, is not a change to the value. */
181
+ const standsFor = (next: unknown): unknown => {
182
+ const chip = choiceValueOfNodes(next);
183
+ if (chip !== undefined) {
184
+ return chip;
185
+ }
186
+ const choice = choiceForValue(next, allowed_values);
187
+ return choice ? choiceValue(choice) : next;
188
+ };
149
189
  /* In text mode, the string the editor's document stands for. The value that
150
190
  comes back from the parent is usually that same string, and rebuilding the
151
191
  document from it would hand the editor a new tree on every keystroke —
@@ -168,9 +208,9 @@ export const RichTextFormField = memo(({
168
208
  }
169
209
  return;
170
210
  }
171
- // Compared as what the document stands for: a lone choice chip IS the
172
- // value it draws, so the value coming back is not a change to it.
173
- if (JSON.stringify(value) !== JSON.stringify(choiceValueOfNodes(localValue) ?? localValue)) {
211
+ // Compared as what each stands for: a lone choice chip IS the value it
212
+ // draws, so the value coming back is not a change to it.
213
+ if (!isEqual(standsFor(value), standsFor(localValue))) {
174
214
  setLocalValue(toLocal(value));
175
215
  }
176
216
  }, [JSON.stringify(value)]);
@@ -205,7 +245,7 @@ export const RichTextFormField = memo(({
205
245
  // A document that is nothing but one choice chip is emitted as the
206
246
  // choice's value — what was stored and what the server resolves.
207
247
  const next = choiceValueOfNodes(localValue) ?? localValue;
208
- if (!isEqual(next, value)) {
248
+ if (!isEqual(standsFor(next), standsFor(value))) {
209
249
  emitted.record(next);
210
250
  onChange?.(next);
211
251
  }
@@ -248,6 +288,43 @@ export const RichTextFormField = memo(({
248
288
  JSON.stringify(templates),
249
289
  ]);
250
290
 
291
+ /* Opens a choice chip into its value as text and puts the cursor there.
292
+ A click on the chip — a non-editable node — need not have given the
293
+ editor focus, so focus is asked of Slate, which places the DOM caret where
294
+ the selection is and focuses after; but only once the text the chip became
295
+ is rendered (the effect below), since Slate resolves the caret through the
296
+ rendered DOM. Asked any earlier it lost: a DOM `focus()` before the
297
+ transform let the browser put the caret at the editor's start and the
298
+ `selectionchange` it raised beat the render, so the next key typed landed
299
+ there; asked on the next frame, the frame came before React's commit
300
+ often enough. An editor that already has focus (Backspace came from it)
301
+ is returned at once, and its own render puts the caret where the
302
+ selection is. */
303
+ const focusOnceRendered = useRef(false);
304
+ const openChoiceChip = useCallback((path: Path | undefined): void => {
305
+ const editor = editorRef.current;
306
+
307
+ if (editor && path && unwrapChoiceChip(editor, path)) {
308
+ focusOnceRendered.current = true;
309
+ }
310
+ }, []);
311
+
312
+ useEffect(() => {
313
+ const editor = editorRef.current;
314
+
315
+ if (!focusOnceRendered.current || !editor) {
316
+ return;
317
+ }
318
+ focusOnceRendered.current = false;
319
+
320
+ try {
321
+ ReactEditor.toDOMNode(editor, editor);
322
+ ReactEditor.focus(editor);
323
+ } catch {
324
+ // Not mounted in a document — nothing to focus.
325
+ }
326
+ }, [localValue]);
327
+
251
328
  const handleGetTagProps = useCallback(
252
329
  (tag: any): IReqoreTagProps => {
253
330
  const tagValue = tag.value?.toString();
@@ -263,6 +340,11 @@ export const RichTextFormField = memo(({
263
340
  icon: 'ListCheck',
264
341
  label: tag.label ?? tagValue,
265
342
  tooltip: tag.metadata?.description,
343
+ /* The editor hands the document's own node here, so the chip is
344
+ found by identity; a chip already gone is a click on nothing. */
345
+ ...(chipBehavior.click === 'unwrap' ?
346
+ { onClick: () => openChoiceChip(editorRef.current ? pathOfNode(editorRef.current, tag) : undefined) }
347
+ : {}),
266
348
  };
267
349
  }
268
350
 
@@ -323,7 +405,23 @@ export const RichTextFormField = memo(({
323
405
 
324
406
  return {};
325
407
  },
326
- [descriptionByValue, renderMarkdown, isText, templates]
408
+ [descriptionByValue, renderMarkdown, isText, templates, chipBehavior.click, openChoiceChip]
409
+ );
410
+
411
+ /* Leaving the field: text that is exactly one of the choices becomes its
412
+ chip again, as the picker would have drawn it. Only here, never while
413
+ typing — a choice can be the start of a longer value, and a chip drawn
414
+ under the cursor would swallow it. */
415
+ const handleBlur = useCallback(
416
+ (event: FocusEvent<HTMLTextAreaElement>): void => {
417
+ const shown = isText ? lastTextRef.current : localValue;
418
+
419
+ if (choiceForValue(shown, allowed_values)) {
420
+ setLocalValue(toLocal(shown));
421
+ }
422
+ (rest as { onBlur?: (event: FocusEvent<HTMLTextAreaElement>) => void }).onBlur?.(event);
423
+ },
424
+ [isText, localValue, choiceKey, (rest as { onBlur?: unknown }).onBlur]
327
425
  );
328
426
 
329
427
  const handleKeyDown = useCallback(
@@ -331,9 +429,26 @@ export const RichTextFormField = memo(({
331
429
  if (isText && singleLine && event.key === 'Enter') {
332
430
  event.preventDefault();
333
431
  }
432
+ /* Backspace right after a choice chip opens it rather than deleting it,
433
+ when so configured. Stopped here, at keydown, so the browser raises no
434
+ `beforeinput` for the editor to delete the chip by. */
435
+ if (event.key === 'Backspace' && chipBehavior.backspace === 'unwrap' && editorRef.current) {
436
+ const path = choiceChipAtCursor(editorRef.current);
437
+
438
+ if (path) {
439
+ event.preventDefault();
440
+ openChoiceChip(path);
441
+ }
442
+ }
334
443
  (rest as { onKeyDown?: (event: KeyboardEvent<HTMLTextAreaElement>) => void }).onKeyDown?.(event);
335
444
  },
336
- [isText, singleLine, (rest as { onKeyDown?: unknown }).onKeyDown]
445
+ [
446
+ isText,
447
+ singleLine,
448
+ chipBehavior.backspace,
449
+ openChoiceChip,
450
+ (rest as { onKeyDown?: unknown }).onKeyDown,
451
+ ]
337
452
  );
338
453
 
339
454
  const tags = useMemo<IReqoreRichTextEditorProps['tags']>((): IReqoreRichTextEditorProps['tags'] => {
@@ -384,6 +499,7 @@ export const RichTextFormField = memo(({
384
499
 
385
500
  return (
386
501
  <ReqoreRichTextEditor
502
+ ref={editorRef}
387
503
  value={formattedValue}
388
504
  onChange={handleChange}
389
505
  /* `rest` is spread BEFORE everything this component computes. It used to
@@ -409,6 +525,7 @@ export const RichTextFormField = memo(({
409
525
  panelProps={{ fluid: true, style: { minWidth: '150px', ...rest.panelProps?.style } }}
410
526
  readOnly={readOnly}
411
527
  onKeyDown={handleKeyDown}
528
+ onBlur={handleBlur}
412
529
  /* A form field carries no document toolbar. Styling was already off, so
413
530
  the bar held only undo and redo — drawn by Reqore as a panel as wide as
414
531
  the tag list, which under a field reads as an empty 600px menu with two
@@ -1,5 +1,6 @@
1
1
  // Copyright 2026 Qore Technologies, s.r.o.
2
2
  import { IQorusAllowedValue, TQorusFormFieldSchema } from '@qoretechnologies/ts-toolkit';
3
+ import { Editor, Node, Path, Range, Transforms } from 'slate';
3
4
  import { findAllowedValueOption } from './allowedValues';
4
5
  import { getListElementValue } from './options';
5
6
 
@@ -27,20 +28,54 @@ export interface IChoiceChipNode {
27
28
  children: [{ text: '' }];
28
29
  }
29
30
 
31
+ /** The choice's value as the plain string it is; it arrives in the form engine's `{type, value}` envelope. */
32
+ export const choiceValue = (choice: IQorusAllowedValue): string =>
33
+ String(getListElementValue(choice.value) ?? '');
34
+
35
+ /**
36
+ * The text a document is, when it is one paragraph of plain text and nothing
37
+ * else; `undefined` for anything more — a chip, a mark, a second paragraph.
38
+ */
39
+ export const plainTextOfNodes = (nodes: unknown): string | undefined => {
40
+ if (!Array.isArray(nodes) || nodes.length !== 1) {
41
+ return undefined;
42
+ }
43
+
44
+ const paragraph = nodes[0] as { type?: unknown; children?: unknown[] } | undefined;
45
+
46
+ if (paragraph?.type !== 'paragraph' || !Array.isArray(paragraph.children)) {
47
+ return undefined;
48
+ }
49
+
50
+ let text = '';
51
+
52
+ for (const child of paragraph.children as { text?: unknown }[]) {
53
+ if (typeof child?.text !== 'string' || Object.keys(child).some((key) => key !== 'text')) {
54
+ return undefined;
55
+ }
56
+ text += child.text;
57
+ }
58
+
59
+ return text;
60
+ };
61
+
30
62
  /**
31
- * The choice a value is, when the value is a whole plain string the field
32
- * offers. A document, or a string holding more than the choice, is the
33
- * author's own text and is never a choice.
63
+ * The choice a value is: a whole plain string the field offers, or a document
64
+ * that is one paragraph of exactly that text — which is what an edit of the
65
+ * chip stores, so an id typed back is the choice it was. A string or document
66
+ * holding anything more is the author's own text and is never a choice.
34
67
  */
35
68
  export const choiceForValue = (
36
69
  value: unknown,
37
70
  choices?: IQorusAllowedValue[]
38
71
  ): IQorusAllowedValue | undefined => {
39
- if (typeof value !== 'string' || !value || !choices?.length) {
72
+ const text = typeof value === 'string' ? value : plainTextOfNodes(value);
73
+
74
+ if (!text || !choices?.length) {
40
75
  return undefined;
41
76
  }
42
77
 
43
- return findAllowedValueOption(value, { allowed_values: choices } as TQorusFormFieldSchema) as
78
+ return findAllowedValueOption(text, { allowed_values: choices } as TQorusFormFieldSchema) as
44
79
  | IQorusAllowedValue
45
80
  | undefined;
46
81
  };
@@ -49,8 +84,7 @@ export const choiceForValue = (
49
84
  export const choiceToNodes = (
50
85
  choice: IQorusAllowedValue
51
86
  ): { type: 'paragraph'; children: ({ text: string } | IChoiceChipNode)[] }[] => {
52
- // The choice's value arrives in the form engine's `{type, value}` envelope.
53
- const value = String(getListElementValue(choice.value) ?? '');
87
+ const value = choiceValue(choice);
54
88
  const description = (choice as { desc?: string; short_desc?: string }).short_desc ?? choice.desc;
55
89
 
56
90
  return [
@@ -71,7 +105,7 @@ export const choiceToNodes = (
71
105
  ];
72
106
  };
73
107
 
74
- const isChoiceChip = (node: unknown): node is IChoiceChipNode =>
108
+ export const isChoiceChip = (node: unknown): node is IChoiceChipNode =>
75
109
  !!node &&
76
110
  typeof node === 'object' &&
77
111
  (node as { type?: unknown }).type === 'tag' &&
@@ -96,3 +130,98 @@ export const choiceValueOfNodes = (nodes: unknown): string | undefined => {
96
130
 
97
131
  return chips.length === 1 && text === '' ? chips[0].value : undefined;
98
132
  };
133
+
134
+ /**
135
+ * What a choice chip does when the author acts on it, by action.
136
+ *
137
+ * The chip is a void: it holds no text of its own, so a key or a click on it
138
+ * has nothing to land in, and an author who wants to change one letter of the
139
+ * value it draws (`C07ERBFS0P6` to `C07ERBFS0P7`) has no way in unless the
140
+ * chip opens. Each action is configurable, and the default is the one that
141
+ * opens it: a creatable choice is the author's to edit.
142
+ */
143
+ export interface IChoiceChipBehavior {
144
+ /**
145
+ * Backspace with the cursor right after the chip. `unwrap` (the default)
146
+ * turns the chip into its value as plain text, the cursor at the end of it,
147
+ * for the author to edit; `remove` deletes it whole, as the editor deletes
148
+ * any other chip.
149
+ */
150
+ backspace?: 'unwrap' | 'remove';
151
+ /**
152
+ * A click on the chip's body. `unwrap` (the default) turns the chip into its
153
+ * value as plain text, the cursor at the end of it; `cursor` only places the
154
+ * cursor after it, as a click on a template chip does.
155
+ */
156
+ click?: 'unwrap' | 'cursor';
157
+ }
158
+
159
+ export const DEFAULT_CHOICE_CHIP_BEHAVIOR: Required<IChoiceChipBehavior> = {
160
+ backspace: 'unwrap',
161
+ click: 'unwrap',
162
+ };
163
+
164
+ /** Where the node is in the document, by identity; the editor renders the document's own nodes, so a chip handed to a click handler is one of them. */
165
+ export const pathOfNode = (editor: Editor, node: unknown): Path | undefined => {
166
+ // Stepped by hand: the build target cannot iterate a generator (TS2802).
167
+ const nodes = Node.nodes(editor);
168
+
169
+ for (let entry = nodes.next(); !entry.done; entry = nodes.next()) {
170
+ if (entry.value[0] === node) {
171
+ return entry.value[1];
172
+ }
173
+ }
174
+
175
+ return undefined;
176
+ };
177
+
178
+ /**
179
+ * The chip the cursor is on: right after it with nothing between, where
180
+ * Backspace would take it, or inside it, where the arrow keys can leave the
181
+ * cursor. Nothing when the selection spans text or sits anywhere else.
182
+ */
183
+ export const choiceChipAtCursor = (editor: Editor): Path | undefined => {
184
+ const { selection } = editor;
185
+
186
+ if (!selection || !Range.isCollapsed(selection)) {
187
+ return undefined;
188
+ }
189
+
190
+ const { path, offset } = selection.anchor;
191
+ const inside = Editor.above(editor, { at: path, match: isChoiceChip, voids: true });
192
+
193
+ if (inside) {
194
+ return inside[1];
195
+ }
196
+
197
+ if (offset !== 0 || !Path.hasPrevious(path)) {
198
+ return undefined;
199
+ }
200
+
201
+ const previous = Path.previous(path);
202
+
203
+ return isChoiceChip(Node.get(editor, previous)) ? previous : undefined;
204
+ };
205
+
206
+ /**
207
+ * Opens the chip at `path` into its value as plain text, the cursor at the
208
+ * end of the text: what the author read is what they chose, now editable
209
+ * letter by letter. The document is text from here on, and is stored as the
210
+ * field stores anything typed; it is drawn as a chip again only when it is
211
+ * read back as exactly one of the choices.
212
+ */
213
+ export const unwrapChoiceChip = (editor: Editor, path: Path): boolean => {
214
+ const chip = Node.get(editor, path);
215
+
216
+ if (!isChoiceChip(chip)) {
217
+ return false;
218
+ }
219
+
220
+ Editor.withoutNormalizing(editor, () => {
221
+ Transforms.removeNodes(editor, { at: path });
222
+ Transforms.insertNodes(editor, [{ text: chip.value }], { at: path });
223
+ Transforms.select(editor, Editor.end(editor, path));
224
+ });
225
+
226
+ return true;
227
+ };