@qoretechnologies/reqraft 0.10.62-pr.142.g62c577f → 0.10.62

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (24) hide show
  1. package/dist/components/form/engine/CompactRow.js +1 -1
  2. package/dist/components/form/engine/CompactRow.js.map +1 -1
  3. package/dist/components/form/fields/rich-text/RichText.d.ts +22 -1
  4. package/dist/components/form/fields/rich-text/RichText.d.ts.map +1 -1
  5. package/dist/components/form/fields/rich-text/RichText.js +135 -50
  6. package/dist/components/form/fields/rich-text/RichText.js.map +1 -1
  7. package/dist/components/form/fields/template/ReadOnlyTemplateTag.d.ts +3 -1
  8. package/dist/components/form/fields/template/ReadOnlyTemplateTag.d.ts.map +1 -1
  9. package/dist/components/form/fields/template/ReadOnlyTemplateTag.js +2 -5
  10. package/dist/components/form/fields/template/ReadOnlyTemplateTag.js.map +1 -1
  11. package/dist/components/form/fields/template/TemplateField.js +1 -1
  12. package/dist/components/form/fields/template/TemplateField.js.map +1 -1
  13. package/dist/helpers/choiceChip.d.ts +98 -0
  14. package/dist/helpers/choiceChip.d.ts.map +1 -0
  15. package/dist/helpers/choiceChip.js +181 -0
  16. package/dist/helpers/choiceChip.js.map +1 -0
  17. package/package.json +1 -1
  18. package/src/components/form/engine/CompactRow.tsx +1 -1
  19. package/src/components/form/engine/FormEngine.stories.tsx +195 -0
  20. package/src/components/form/fields/rich-text/RichText.stories.tsx +178 -1
  21. package/src/components/form/fields/rich-text/RichText.tsx +180 -45
  22. package/src/components/form/fields/template/ReadOnlyTemplateTag.tsx +4 -5
  23. package/src/components/form/fields/template/TemplateField.tsx +1 -1
  24. package/src/helpers/choiceChip.ts +227 -0
@@ -0,0 +1,98 @@
1
+ import { IQorusAllowedValue } from '@qoretechnologies/ts-toolkit';
2
+ import { Editor, Path } from 'slate';
3
+ /**
4
+ * A value that IS one of the field's own choices, drawn as that choice.
5
+ *
6
+ * A rich-text field offered choices picks one by writing its value, so an
7
+ * author who chose the Slack channel "general" read `C07ERBFS0P6` in the
8
+ * editor. The value is right — it is what the server resolves — but it is not
9
+ * what was chosen by. These helpers draw such a value as one chip named from
10
+ * the choice, the way a template reference is drawn from the catalogue, while
11
+ * what is stored stays the plain value: the chip's own `value` is the choice's,
12
+ * so the text a document stands for is unchanged, and a document that is
13
+ * nothing but the chip is read back as the value it draws.
14
+ */
15
+ /** The marker a choice chip carries, so it is told apart from a template reference. */
16
+ export declare const CHOICE_CHIP_META = "allowedValue";
17
+ export interface IChoiceChipNode {
18
+ type: 'tag';
19
+ value: string;
20
+ label: string;
21
+ metadata: {
22
+ [CHOICE_CHIP_META]: true;
23
+ description?: string;
24
+ };
25
+ children: [{
26
+ text: '';
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;
31
+ /**
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.
41
+ */
42
+ export declare const choiceForValue: (value: unknown, choices?: IQorusAllowedValue[]) => IQorusAllowedValue | undefined;
43
+ /** The one-chip document that draws a choice by its name. */
44
+ export declare const choiceToNodes: (choice: IQorusAllowedValue) => {
45
+ type: 'paragraph';
46
+ children: ({
47
+ text: string;
48
+ } | IChoiceChipNode)[];
49
+ }[];
50
+ export declare const isChoiceChip: (node: unknown) => node is IChoiceChipNode;
51
+ /**
52
+ * The value a document is, when the document is one choice chip and nothing
53
+ * else; `undefined` when the author has written anything around it, in which
54
+ * case the document itself is the value.
55
+ */
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;
98
+ //# sourceMappingURL=choiceChip.d.ts.map
@@ -0,0 +1 @@
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"}
@@ -0,0 +1,181 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ Object.defineProperty(exports, "__esModule", { value: true });
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");
16
+ var allowedValues_1 = require("./allowedValues");
17
+ var options_1 = require("./options");
18
+ /**
19
+ * A value that IS one of the field's own choices, drawn as that choice.
20
+ *
21
+ * A rich-text field offered choices picks one by writing its value, so an
22
+ * author who chose the Slack channel "general" read `C07ERBFS0P6` in the
23
+ * editor. The value is right — it is what the server resolves — but it is not
24
+ * what was chosen by. These helpers draw such a value as one chip named from
25
+ * the choice, the way a template reference is drawn from the catalogue, while
26
+ * what is stored stays the plain value: the chip's own `value` is the choice's,
27
+ * so the text a document stands for is unchanged, and a document that is
28
+ * nothing but the chip is read back as the value it draws.
29
+ */
30
+ /** The marker a choice chip carries, so it is told apart from a template reference. */
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;
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
+ 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.
63
+ */
64
+ var choiceForValue = function (value, choices) {
65
+ var text = typeof value === 'string' ? value : (0, exports.plainTextOfNodes)(value);
66
+ if (!text || !(choices === null || choices === void 0 ? void 0 : choices.length)) {
67
+ return undefined;
68
+ }
69
+ return (0, allowedValues_1.findAllowedValueOption)(text, { allowed_values: choices });
70
+ };
71
+ exports.choiceForValue = choiceForValue;
72
+ /** The one-chip document that draws a choice by its name. */
73
+ var choiceToNodes = function (choice) {
74
+ var _a;
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;
78
+ return [
79
+ {
80
+ type: 'paragraph',
81
+ children: [
82
+ { text: '' },
83
+ {
84
+ type: 'tag',
85
+ value: value,
86
+ label: (_c = choice.display_name) !== null && _c !== void 0 ? _c : value,
87
+ metadata: __assign((_a = {}, _a[exports.CHOICE_CHIP_META] = true, _a), (description ? { description: description } : {})),
88
+ children: [{ text: '' }],
89
+ },
90
+ { text: '' },
91
+ ],
92
+ },
93
+ ];
94
+ };
95
+ exports.choiceToNodes = choiceToNodes;
96
+ var isChoiceChip = function (node) {
97
+ var _a;
98
+ return !!node &&
99
+ typeof node === 'object' &&
100
+ node.type === 'tag' &&
101
+ !!((_a = node.metadata) === null || _a === void 0 ? void 0 : _a[exports.CHOICE_CHIP_META]);
102
+ };
103
+ exports.isChoiceChip = isChoiceChip;
104
+ /**
105
+ * The value a document is, when the document is one choice chip and nothing
106
+ * else; `undefined` when the author has written anything around it, in which
107
+ * case the document itself is the value.
108
+ */
109
+ var choiceValueOfNodes = function (nodes) {
110
+ var _a, _b;
111
+ if (!Array.isArray(nodes) || nodes.length !== 1) {
112
+ return undefined;
113
+ }
114
+ var children = (_b = (_a = nodes[0]) === null || _a === void 0 ? void 0 : _a.children) !== null && _b !== void 0 ? _b : [];
115
+ var chips = children.filter(exports.isChoiceChip);
116
+ var text = children
117
+ .filter(function (node) { return !(0, exports.isChoiceChip)(node); })
118
+ .map(function (node) { return (typeof (node === null || node === void 0 ? void 0 : node.text) === 'string' ? node.text : '\u0000'); })
119
+ .join('');
120
+ return chips.length === 1 && text === '' ? chips[0].value : undefined;
121
+ };
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;
181
+ //# sourceMappingURL=choiceChip.js.map
@@ -0,0 +1 @@
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.142.g62c577f",
3
+ "version": "0.10.62",
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",
@@ -562,7 +562,7 @@ export const CompactRow = memo(
562
562
  !(field as { is_expression?: boolean }).is_expression &&
563
563
  (isValueTemplate(field.value) || !!findTemplate(ownTemplates ?? {}, field.value))
564
564
  ) {
565
- return <ReadOnlyTemplateTag value={field.value} templates={ownTemplates} />;
565
+ return <ReadOnlyTemplateTag value={field.value} templates={ownTemplates} size='small' />;
566
566
  }
567
567
 
568
568
  // A LIST whose elements are rich-text envelopes is a list of strings, so it
@@ -9723,3 +9723,198 @@ const stickyBoxesStory = (layout: 'own' | 'host' | 'padded-host'): Story => ({
9723
9723
  export const BoxHeaderSlidesUnderToolbarOwnScroll: Story = stickyBoxesStory('own');
9724
9724
  export const BoxHeaderSlidesUnderToolbarHostScroll: Story = stickyBoxesStory('host');
9725
9725
  export const BoxHeaderSlidesUnderToolbarPaddedHost: Story = stickyBoxesStory('padded-host');
9726
+
9727
+ /**
9728
+ * A rich-text option's choices are picked from "Saved & Suggested Values",
9729
+ * and picking one writes the choice's value: an author who chose the Slack
9730
+ * channel "general" read `C07ERBFS0P6` in the editor. The value is what the
9731
+ * server resolves, so it stays the value; the editor draws it by the name it
9732
+ * was picked by. These two stories are the guard: one opens on the stored
9733
+ * value, one performs the pick.
9734
+ */
9735
+ const RICH_TEXT_CHOICE_OPTIONS = {
9736
+ channel: {
9737
+ type: 'richtext',
9738
+ ui_type: 'richtext',
9739
+ display_name: 'Channel',
9740
+ short_desc: 'The channel to send the message to',
9741
+ required: true,
9742
+ allowed_values_creatable: true,
9743
+ allowed_values: [
9744
+ {
9745
+ display_name: 'general',
9746
+ short_desc: 'Company-wide announcements',
9747
+ value: { type: 'richtext', value: 'C07ERBFS0P6' },
9748
+ },
9749
+ {
9750
+ display_name: 'random',
9751
+ short_desc: 'Anything goes',
9752
+ value: { type: 'richtext', value: 'C07RANDOM01' },
9753
+ },
9754
+ ],
9755
+ },
9756
+ } as never;
9757
+
9758
+ const expectChannelChip = async (canvasElement: HTMLElement) => {
9759
+ await waitFor(
9760
+ () => {
9761
+ const row = canvasElement.querySelector('[data-field="channel"]') as HTMLElement | null;
9762
+ expect(row).toBeTruthy();
9763
+ expect(row?.querySelector('.reqore-tag')?.textContent).toContain('general');
9764
+ expect(row?.textContent).not.toContain('C07ERBFS0P6');
9765
+ },
9766
+ { timeout: 10000 }
9767
+ );
9768
+ };
9769
+
9770
+ export const RichTextChoiceIsShownByName: Story = {
9771
+ parameters: {
9772
+ docs: {
9773
+ description: {
9774
+ story:
9775
+ 'Renders a compact form whose rich-text Channel option holds the stored id of one of its choices, C07ERBFS0P6 — the editor shows one chip reading "general", and the id is not shown anywhere on the row.',
9776
+ },
9777
+ },
9778
+ },
9779
+ args: {
9780
+ compact: true,
9781
+ minColumnWidth: '360px',
9782
+ initialExpandedOptions: ['channel'],
9783
+ value: { channel: { type: 'richtext', value: 'C07ERBFS0P6' } },
9784
+ options: RICH_TEXT_CHOICE_OPTIONS,
9785
+ },
9786
+ play: async ({ canvasElement }) => {
9787
+ await expectChannelChip(canvasElement);
9788
+ },
9789
+ };
9790
+
9791
+ export const PickingARichTextChoiceShowsItsName: Story = {
9792
+ parameters: {
9793
+ docs: {
9794
+ description: {
9795
+ story:
9796
+ 'Renders a compact form with an empty rich-text Channel option. When "general" is picked from Saved & Suggested Values, the editor shows a chip reading "general" rather than the channel id it stores.',
9797
+ },
9798
+ },
9799
+ },
9800
+ args: {
9801
+ compact: true,
9802
+ minColumnWidth: '360px',
9803
+ initialExpandedOptions: ['channel'],
9804
+ value: {},
9805
+ options: RICH_TEXT_CHOICE_OPTIONS,
9806
+ },
9807
+ play: async ({ canvasElement }) => {
9808
+ await _testsClickText('Saved & Suggested Values');
9809
+ await waitFor(
9810
+ () => expect(within(document.body).getByText('general')).toBeInTheDocument(),
9811
+ { timeout: 10000 }
9812
+ );
9813
+ await fireEvent.click(within(document.body).getByText('general'));
9814
+
9815
+ await expectChannelChip(canvasElement);
9816
+ },
9817
+ };
9818
+
9819
+ export const ARichTextChoiceRetypedReturnsToItsChip: Story = {
9820
+ parameters: {
9821
+ // Interaction-only: the play assertions are the guard, and the end state
9822
+ // is already pictured by `RichTextChoiceIsShownByName`.
9823
+ qlip: { skip: true },
9824
+ docs: {
9825
+ description: {
9826
+ story:
9827
+ '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.',
9828
+ },
9829
+ },
9830
+ },
9831
+ args: {
9832
+ compact: true,
9833
+ minColumnWidth: '360px',
9834
+ initialExpandedOptions: ['channel'],
9835
+ value: { channel: { type: 'richtext', value: 'C07ERBFS0P6' } },
9836
+ options: RICH_TEXT_CHOICE_OPTIONS,
9837
+ },
9838
+ play: async ({ args, canvasElement }) => {
9839
+ await expectChannelChip(canvasElement);
9840
+ const row = canvasElement.querySelector('[data-field="channel"]') as HTMLElement;
9841
+ const editor = row.querySelector('[contenteditable="true"]') as HTMLElement;
9842
+
9843
+ await userEvent.click(within(row).getByText('general'));
9844
+ await waitFor(() => {
9845
+ expect(editor.querySelector('.reqore-tag')).toBeNull();
9846
+ expect(editor.contains(document.activeElement)).toBe(true);
9847
+ });
9848
+
9849
+ const channelValue = (text: string) =>
9850
+ expect.objectContaining({
9851
+ channel: expect.objectContaining({ value: [{ type: 'paragraph', children: [{ text }] }] }),
9852
+ });
9853
+
9854
+ // One key at a time, each emitted before the next: typed within the
9855
+ // field's debounce, the two would settle as the value the field started
9856
+ // with, and nothing would be emitted at all.
9857
+ await userEvent.keyboard('{Backspace}');
9858
+ await waitFor(() =>
9859
+ expect(args.onChange).toHaveBeenLastCalledWith('test', channelValue('C07ERBFS0P'), undefined)
9860
+ );
9861
+ await userEvent.keyboard('6');
9862
+ await waitFor(() =>
9863
+ expect(args.onChange).toHaveBeenLastCalledWith('test', channelValue('C07ERBFS0P6'), undefined)
9864
+ );
9865
+ await expect(editor.querySelector('.reqore-tag')).toBeNull();
9866
+
9867
+ await userEvent.tab();
9868
+ await expectChannelChip(canvasElement);
9869
+ // Leaving the row changed nothing: the chip stands for what was emitted.
9870
+ await expect(args.onChange).toHaveBeenLastCalledWith('test', channelValue('C07ERBFS0P6'), undefined);
9871
+ },
9872
+ };
9873
+
9874
+ export const ClickingARichTextChoiceEditsItsValue: Story = {
9875
+ parameters: {
9876
+ // Interaction-only: the play assertions are the guard, and the end state
9877
+ // is already pictured by the compact rich-text rows.
9878
+ qlip: { skip: true },
9879
+ docs: {
9880
+ description: {
9881
+ story:
9882
+ '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.',
9883
+ },
9884
+ },
9885
+ },
9886
+ args: {
9887
+ compact: true,
9888
+ minColumnWidth: '360px',
9889
+ initialExpandedOptions: ['channel'],
9890
+ value: { channel: { type: 'richtext', value: 'C07ERBFS0P6' } },
9891
+ options: RICH_TEXT_CHOICE_OPTIONS,
9892
+ },
9893
+ play: async ({ args, canvasElement }) => {
9894
+ await expectChannelChip(canvasElement);
9895
+ const row = canvasElement.querySelector('[data-field="channel"]') as HTMLElement;
9896
+ const editor = row.querySelector('[contenteditable="true"]') as HTMLElement;
9897
+
9898
+ // The chip's label: a tag binds its click to its content, not its frame.
9899
+ await userEvent.click(within(row).getByText('general'));
9900
+ await waitFor(() => {
9901
+ expect(editor.querySelector('.reqore-tag')).toBeNull();
9902
+ expect(editor.textContent).toBe('C07ERBFS0P6');
9903
+ expect(editor.contains(document.activeElement)).toBe(true);
9904
+ });
9905
+
9906
+ await userEvent.keyboard('{Backspace}7');
9907
+ await waitFor(() => expect(editor.textContent).toBe('C07ERBFS0P7'));
9908
+ await waitFor(() =>
9909
+ expect(args.onChange).toHaveBeenLastCalledWith(
9910
+ 'test',
9911
+ expect.objectContaining({
9912
+ channel: expect.objectContaining({
9913
+ value: [{ type: 'paragraph', children: [{ text: 'C07ERBFS0P7' }] }],
9914
+ }),
9915
+ }),
9916
+ undefined
9917
+ )
9918
+ );
9919
+ },
9920
+ };