@qoretechnologies/reqraft 0.10.53 → 0.10.54-pr.115.g9bc96ed
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/.claude/CLAUDE.md +25 -0
- package/.tasks/INDEX.md +1 -0
- package/.tasks/STORY_NETWORK_ISOLATION.md +98 -0
- package/README.md +1 -1
- package/design/FORM_ENGINE_EXPRESSIONS.md +110 -0
- package/design/FORM_ENGINE_FIELD_MIGRATION.md +56 -1
- package/design/RENDER_EXPRESSION_TRANSPORT.md +76 -10
- package/design/SMART_EDITOR_UX.md +21 -0
- package/dist/components/dpqlEditor/DpqlEditor.d.ts.map +1 -1
- package/dist/components/dpqlEditor/DpqlEditor.js +3 -3
- package/dist/components/dpqlEditor/DpqlEditor.js.map +1 -1
- package/dist/components/dpqlEditor/dpqlHelpers.d.ts +6 -0
- package/dist/components/dpqlEditor/dpqlHelpers.d.ts.map +1 -1
- package/dist/components/dpqlEditor/dpqlHelpers.js +21 -2
- package/dist/components/dpqlEditor/dpqlHelpers.js.map +1 -1
- package/dist/components/dpqlEditor/dpqlProbe.d.ts +37 -0
- package/dist/components/dpqlEditor/dpqlProbe.d.ts.map +1 -0
- package/dist/components/dpqlEditor/dpqlProbe.js +203 -0
- package/dist/components/dpqlEditor/dpqlProbe.js.map +1 -0
- package/dist/components/dpqlEditor/dpqlTags.d.ts +8 -0
- package/dist/components/dpqlEditor/dpqlTags.d.ts.map +1 -1
- package/dist/components/dpqlEditor/dpqlTags.js +5 -1
- package/dist/components/dpqlEditor/dpqlTags.js.map +1 -1
- package/dist/components/dpqlEditor/index.d.ts +4 -0
- package/dist/components/dpqlEditor/index.d.ts.map +1 -1
- package/dist/components/dpqlEditor/index.js +5 -1
- package/dist/components/dpqlEditor/index.js.map +1 -1
- package/dist/components/dpqlEditor/types.d.ts +42 -2
- package/dist/components/dpqlEditor/types.d.ts.map +1 -1
- package/dist/components/dpqlEditor/types.js +0 -4
- package/dist/components/dpqlEditor/types.js.map +1 -1
- package/dist/components/dpqlEditor/useDpqlProbe.d.ts +4 -0
- package/dist/components/dpqlEditor/useDpqlProbe.d.ts.map +1 -0
- package/dist/components/dpqlEditor/useDpqlProbe.js +29 -0
- package/dist/components/dpqlEditor/useDpqlProbe.js.map +1 -0
- package/dist/components/dpqlEditor/useDpqlSession.d.ts +5 -2
- package/dist/components/dpqlEditor/useDpqlSession.d.ts.map +1 -1
- package/dist/components/dpqlEditor/useDpqlSession.js +8 -2
- package/dist/components/dpqlEditor/useDpqlSession.js.map +1 -1
- package/dist/components/form/engine/CompactRow.d.ts.map +1 -1
- package/dist/components/form/engine/CompactRow.js +192 -45
- package/dist/components/form/engine/CompactRow.js.map +1 -1
- package/dist/components/form/engine/CompactToolbar.d.ts.map +1 -1
- package/dist/components/form/engine/CompactToolbar.js +5 -2
- package/dist/components/form/engine/CompactToolbar.js.map +1 -1
- package/dist/components/form/engine/FormEngine.d.ts +160 -12
- package/dist/components/form/engine/FormEngine.d.ts.map +1 -1
- package/dist/components/form/engine/FormEngine.js +376 -75
- package/dist/components/form/engine/FormEngine.js.map +1 -1
- package/dist/components/form/engine/FormFieldsSkeleton.d.ts +48 -0
- package/dist/components/form/engine/FormFieldsSkeleton.d.ts.map +1 -0
- package/dist/components/form/engine/FormFieldsSkeleton.js +38 -0
- package/dist/components/form/engine/FormFieldsSkeleton.js.map +1 -0
- package/dist/components/form/engine/OptionFieldMessages.d.ts +17 -2
- package/dist/components/form/engine/OptionFieldMessages.d.ts.map +1 -1
- package/dist/components/form/engine/OptionFieldMessages.js +61 -11
- package/dist/components/form/engine/OptionFieldMessages.js.map +1 -1
- package/dist/components/form/engine/_structuredData/SchemaDataView.d.ts.map +1 -1
- package/dist/components/form/engine/_structuredData/SchemaDataView.js +7 -1
- package/dist/components/form/engine/_structuredData/SchemaDataView.js.map +1 -1
- package/dist/components/form/engine/compactToolbarContext.d.ts +1 -0
- package/dist/components/form/engine/compactToolbarContext.d.ts.map +1 -1
- package/dist/components/form/engine/readFirst.d.ts +42 -1
- package/dist/components/form/engine/readFirst.d.ts.map +1 -1
- package/dist/components/form/engine/readFirst.js +74 -7
- package/dist/components/form/engine/readFirst.js.map +1 -1
- package/dist/components/form/engine/rendererTypes.d.ts +13 -0
- package/dist/components/form/engine/rendererTypes.d.ts.map +1 -1
- package/dist/components/form/engine/rendererTypes.js.map +1 -1
- package/dist/components/form/engine/rowMenuContext.d.ts +78 -0
- package/dist/components/form/engine/rowMenuContext.d.ts.map +1 -0
- package/dist/components/form/engine/rowMenuContext.js +103 -0
- package/dist/components/form/engine/rowMenuContext.js.map +1 -0
- package/dist/components/form/engine/typeChoices.d.ts +37 -0
- package/dist/components/form/engine/typeChoices.d.ts.map +1 -0
- package/dist/components/form/engine/typeChoices.js +25 -0
- package/dist/components/form/engine/typeChoices.js.map +1 -0
- package/dist/components/form/expressions/DpqlRendering.d.ts +26 -0
- package/dist/components/form/expressions/DpqlRendering.d.ts.map +1 -0
- package/dist/components/form/expressions/DpqlRendering.js +53 -0
- package/dist/components/form/expressions/DpqlRendering.js.map +1 -0
- package/dist/components/form/expressions/ExpressionField.d.ts +7 -1
- package/dist/components/form/expressions/ExpressionField.d.ts.map +1 -1
- package/dist/components/form/expressions/ExpressionField.js +202 -45
- package/dist/components/form/expressions/ExpressionField.js.map +1 -1
- package/dist/components/form/expressions/argumentPresence.d.ts +97 -0
- package/dist/components/form/expressions/argumentPresence.d.ts.map +1 -0
- package/dist/components/form/expressions/argumentPresence.js +203 -0
- package/dist/components/form/expressions/argumentPresence.js.map +1 -0
- package/dist/components/form/expressions/builder/argumentLabel.d.ts.map +1 -1
- package/dist/components/form/expressions/builder/argumentLabel.js +9 -4
- package/dist/components/form/expressions/builder/argumentLabel.js.map +1 -1
- package/dist/components/form/expressions/builder/index.d.ts +15 -2
- package/dist/components/form/expressions/builder/index.d.ts.map +1 -1
- package/dist/components/form/expressions/builder/index.js +20 -58
- package/dist/components/form/expressions/builder/index.js.map +1 -1
- package/dist/components/form/expressions/builder/renderTemplate.d.ts +4 -1
- package/dist/components/form/expressions/builder/renderTemplate.d.ts.map +1 -1
- package/dist/components/form/expressions/builder/renderTemplate.js +10 -67
- package/dist/components/form/expressions/builder/renderTemplate.js.map +1 -1
- package/dist/components/form/expressions/dpqlMockLanguage.d.ts +76 -0
- package/dist/components/form/expressions/dpqlMockLanguage.d.ts.map +1 -0
- package/dist/components/form/expressions/dpqlMockLanguage.js +525 -0
- package/dist/components/form/expressions/dpqlMockLanguage.js.map +1 -0
- package/dist/components/form/expressions/dpqlMockLsp.d.ts +31 -2
- package/dist/components/form/expressions/dpqlMockLsp.d.ts.map +1 -1
- package/dist/components/form/expressions/dpqlMockLsp.js +86 -80
- package/dist/components/form/expressions/dpqlMockLsp.js.map +1 -1
- package/dist/components/form/expressions/mockExpressions.d.ts.map +1 -1
- package/dist/components/form/expressions/mockExpressions.js +8 -4
- package/dist/components/form/expressions/mockExpressions.js.map +1 -1
- package/dist/components/form/expressions/renderExpressionToText.d.ts +1 -1
- package/dist/components/form/expressions/renderExpressionToText.d.ts.map +1 -1
- package/dist/components/form/expressions/renderExpressionToText.js +95 -19
- package/dist/components/form/expressions/renderExpressionToText.js.map +1 -1
- package/dist/components/form/expressions/types.d.ts +7 -0
- package/dist/components/form/expressions/types.d.ts.map +1 -1
- package/dist/components/form/expressions/useRenderExpression.d.ts +7 -16
- package/dist/components/form/expressions/useRenderExpression.d.ts.map +1 -1
- package/dist/components/form/expressions/useRenderExpression.js +50 -126
- package/dist/components/form/expressions/useRenderExpression.js.map +1 -1
- package/dist/components/form/fields/Field.d.ts.map +1 -1
- package/dist/components/form/fields/Field.js +3 -1
- package/dist/components/form/fields/Field.js.map +1 -1
- package/dist/components/form/fields/allowed-values/AllowedValues.d.ts +11 -1
- package/dist/components/form/fields/allowed-values/AllowedValues.d.ts.map +1 -1
- package/dist/components/form/fields/allowed-values/AllowedValues.js +14 -2
- package/dist/components/form/fields/allowed-values/AllowedValues.js.map +1 -1
- package/dist/components/form/fields/auto/AutoFormField.d.ts.map +1 -1
- package/dist/components/form/fields/auto/AutoFormField.js +32 -8
- package/dist/components/form/fields/auto/AutoFormField.js.map +1 -1
- package/dist/components/form/fields/date/Date.d.ts +1 -1
- package/dist/components/form/fields/date/Date.d.ts.map +1 -1
- package/dist/components/form/fields/date/Date.js +16 -2
- package/dist/components/form/fields/date/Date.js.map +1 -1
- package/dist/components/form/fields/rich-text/RichText.d.ts +21 -1
- package/dist/components/form/fields/rich-text/RichText.d.ts.map +1 -1
- package/dist/components/form/fields/rich-text/RichText.js +140 -8
- package/dist/components/form/fields/rich-text/RichText.js.map +1 -1
- package/dist/components/form/fields/template/ReadOnlyTemplateTag.d.ts +2 -1
- package/dist/components/form/fields/template/ReadOnlyTemplateTag.d.ts.map +1 -1
- package/dist/components/form/fields/template/ReadOnlyTemplateTag.js +3 -2
- package/dist/components/form/fields/template/ReadOnlyTemplateTag.js.map +1 -1
- package/dist/components/form/fields/template/TemplateField.d.ts +31 -1
- package/dist/components/form/fields/template/TemplateField.d.ts.map +1 -1
- package/dist/components/form/fields/template/TemplateField.js +528 -50
- package/dist/components/form/fields/template/TemplateField.js.map +1 -1
- package/dist/components/form/index.d.ts +1 -0
- package/dist/components/form/index.d.ts.map +1 -1
- package/dist/components/form/index.js +1 -0
- package/dist/components/form/index.js.map +1 -1
- package/dist/components/smartEditor/SmartEditor.d.ts.map +1 -1
- package/dist/components/smartEditor/SmartEditor.js +29 -8
- package/dist/components/smartEditor/SmartEditor.js.map +1 -1
- package/dist/components/smartEditor/__fixtures__/mockLspServer.d.ts +8 -0
- package/dist/components/smartEditor/__fixtures__/mockLspServer.d.ts.map +1 -1
- package/dist/components/smartEditor/__fixtures__/mockLspServer.js +53 -10
- package/dist/components/smartEditor/__fixtures__/mockLspServer.js.map +1 -1
- package/dist/components/smartEditor/useLspSession.d.ts +5 -1
- package/dist/components/smartEditor/useLspSession.d.ts.map +1 -1
- package/dist/components/smartEditor/useLspSession.js +16 -2
- package/dist/components/smartEditor/useLspSession.js.map +1 -1
- package/dist/helpers/dpqlDetection.d.ts +58 -0
- package/dist/helpers/dpqlDetection.d.ts.map +1 -0
- package/dist/helpers/dpqlDetection.js +164 -0
- package/dist/helpers/dpqlDetection.js.map +1 -0
- package/dist/helpers/optionUiTypes.d.ts +3 -3
- package/dist/helpers/options.d.ts +37 -0
- package/dist/helpers/options.d.ts.map +1 -1
- package/dist/helpers/options.js +78 -1
- package/dist/helpers/options.js.map +1 -1
- package/dist/helpers/templateItems.d.ts +47 -0
- package/dist/helpers/templateItems.d.ts.map +1 -0
- package/dist/helpers/templateItems.js +88 -0
- package/dist/helpers/templateItems.js.map +1 -0
- package/dist/helpers/templateText.d.ts +37 -0
- package/dist/helpers/templateText.d.ts.map +1 -0
- package/dist/helpers/templateText.js +64 -0
- package/dist/helpers/templateText.js.map +1 -0
- package/dist/helpers/templates.d.ts +19 -11
- package/dist/helpers/templates.d.ts.map +1 -1
- package/dist/helpers/templates.js +46 -29
- package/dist/helpers/templates.js.map +1 -1
- package/dist/helpers/validations.d.ts.map +1 -1
- package/dist/helpers/validations.js +56 -9
- package/dist/helpers/validations.js.map +1 -1
- package/dist/hooks/useArgSchema.d.ts +2 -1
- package/dist/hooks/useArgSchema.d.ts.map +1 -1
- package/dist/hooks/useFetch/useFetch.d.ts +3 -1
- package/dist/hooks/useFetch/useFetch.d.ts.map +1 -1
- package/dist/hooks/useFetch/useFetch.js +47 -9
- package/dist/hooks/useFetch/useFetch.js.map +1 -1
- package/dist/hooks/useTemplates.d.ts +20 -0
- package/dist/hooks/useTemplates.d.ts.map +1 -1
- package/dist/hooks/useTemplates.js +34 -2
- package/dist/hooks/useTemplates.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/stories/storyNetwork.d.ts +36 -0
- package/dist/stories/storyNetwork.d.ts.map +1 -0
- package/dist/stories/storyNetwork.js +82 -0
- package/dist/stories/storyNetwork.js.map +1 -0
- package/dist/utils/fetch.d.ts +151 -1
- package/dist/utils/fetch.d.ts.map +1 -1
- package/dist/utils/fetch.js +256 -44
- package/dist/utils/fetch.js.map +1 -1
- package/dist/utils/lspClient.d.ts +6 -0
- package/dist/utils/lspClient.d.ts.map +1 -1
- package/dist/utils/lspClient.js +62 -11
- package/dist/utils/lspClient.js.map +1 -1
- package/dist/utils/websocket.d.ts +6 -0
- package/dist/utils/websocket.d.ts.map +1 -1
- package/dist/utils/websocket.js +15 -7
- package/dist/utils/websocket.js.map +1 -1
- package/package.json +2 -2
- package/src/components/dpqlEditor/DpqlEditor.stories.tsx +3 -119
- package/src/components/dpqlEditor/DpqlEditor.tsx +5 -2
- package/src/components/dpqlEditor/dpqlHelpers.ts +20 -1
- package/src/components/dpqlEditor/dpqlProbe.ts +165 -0
- package/src/components/dpqlEditor/dpqlTags.ts +13 -0
- package/src/components/dpqlEditor/index.ts +4 -0
- package/src/components/dpqlEditor/types.ts +38 -2
- package/src/components/dpqlEditor/useDpqlProbe.ts +33 -0
- package/src/components/dpqlEditor/useDpqlSession.ts +20 -4
- package/src/components/form/engine/CompactRow.tsx +240 -51
- package/src/components/form/engine/CompactToolbar.tsx +10 -3
- package/src/components/form/engine/FormEngine.stories.tsx +423 -120
- package/src/components/form/engine/FormEngine.tsx +504 -87
- package/src/components/form/engine/FormFieldsSkeleton.tsx +76 -0
- package/src/components/form/engine/OptionFieldMessages.tsx +89 -11
- package/src/components/form/engine/_structuredData/SchemaDataView.tsx +11 -0
- package/src/components/form/engine/compactToolbarContext.ts +1 -1
- package/src/components/form/engine/readFirst.ts +86 -7
- package/src/components/form/engine/rendererTypes.ts +12 -0
- package/src/components/form/engine/rowMenuContext.ts +159 -0
- package/src/components/form/engine/typeChoices.ts +55 -0
- package/src/components/form/expressions/DpqlRendering.tsx +85 -0
- package/src/components/form/expressions/ExpressionField.stories.tsx +826 -48
- package/src/components/form/expressions/ExpressionField.tsx +265 -54
- package/src/components/form/expressions/argumentPresence.ts +200 -0
- package/src/components/form/expressions/builder/ExpressionBuilder.stories.tsx +20 -4
- package/src/components/form/expressions/builder/argumentLabel.tsx +10 -4
- package/src/components/form/expressions/builder/index.tsx +39 -77
- package/src/components/form/expressions/builder/renderTemplate.tsx +23 -56
- package/src/components/form/expressions/dpqlMockLanguage.ts +565 -0
- package/src/components/form/expressions/dpqlMockLsp.ts +109 -83
- package/src/components/form/expressions/mockExpressions.ts +8 -4
- package/src/components/form/expressions/renderExpressionToText.ts +112 -22
- package/src/components/form/expressions/types.ts +7 -0
- package/src/components/form/expressions/useRenderExpression.ts +43 -127
- package/src/components/form/fields/Field.tsx +3 -2
- package/src/components/form/fields/allowed-values/AllowedValues.tsx +13 -2
- package/src/components/form/fields/auto/AutoFormField.stories.tsx +27 -20
- package/src/components/form/fields/auto/AutoFormField.tsx +33 -9
- package/src/components/form/fields/date/Date.tsx +17 -1
- package/src/components/form/fields/rich-text/RichText.tsx +199 -22
- package/src/components/form/fields/template/ReadOnlyTemplateTag.tsx +4 -2
- package/src/components/form/fields/template/TemplateField.stories.tsx +31 -9
- package/src/components/form/fields/template/TemplateField.tsx +714 -122
- package/src/components/form/index.tsx +1 -0
- package/src/components/log/Log.stories.tsx +2 -1
- package/src/components/smartEditor/SmartEditor.tsx +41 -9
- package/src/components/smartEditor/__fixtures__/mockLspServer.ts +52 -3
- package/src/components/smartEditor/useLspSession.ts +21 -3
- package/src/helpers/dpqlDetection.ts +209 -0
- package/src/helpers/options.ts +70 -0
- package/src/helpers/templateItems.ts +81 -0
- package/src/helpers/templateText.ts +92 -0
- package/src/helpers/templates.ts +47 -37
- package/src/helpers/validations.ts +59 -9
- package/src/hooks/useFetch/useFetch.stories.tsx +6 -5
- package/src/hooks/useFetch/useFetch.tsx +53 -7
- package/src/hooks/useStorage/useStorage.stories.tsx +2 -1
- package/src/hooks/useTemplates.ts +41 -0
- package/src/hooks/useWebSocket/useWebsocket.stories.tsx +2 -1
- package/src/index.tsx +14 -1
- package/src/stores/currentUser/currentUser.stories.tsx +2 -1
- package/src/stories/storyNetwork.ts +92 -0
- package/src/utils/fetch.ts +311 -21
- package/src/utils/lspClient.ts +68 -11
- package/src/utils/websocket.ts +20 -9
|
@@ -4,10 +4,27 @@ import {
|
|
|
4
4
|
} from '@qoretechnologies/reqore/dist/components/RichTextEditor';
|
|
5
5
|
import { IReqoreFormTemplates } from '@qoretechnologies/reqore/dist/components/Textarea';
|
|
6
6
|
import { IReqoreTagProps } from '@qoretechnologies/reqore/dist/components/Tag';
|
|
7
|
+
import { IReqoreTooltip } from '@qoretechnologies/reqore/dist/types/global';
|
|
7
8
|
import { isEqual, size } from 'lodash';
|
|
8
|
-
import { memo, useCallback, useEffect, useMemo, useState } from 'react';
|
|
9
|
+
import { KeyboardEvent, memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
9
10
|
import { useDebounce } from 'react-use';
|
|
10
|
-
import {
|
|
11
|
+
import { flattenToSingleLine, hasLineBreak } from '../../../../helpers/singleLineString';
|
|
12
|
+
import {
|
|
13
|
+
renderTemplateItemDescriptions,
|
|
14
|
+
templateItemsToShow,
|
|
15
|
+
} from '../../../../helpers/templateItems';
|
|
16
|
+
import {
|
|
17
|
+
templateChipLabel,
|
|
18
|
+
templateNodesToText,
|
|
19
|
+
templateTextToNodes,
|
|
20
|
+
} from '../../../../helpers/templateText';
|
|
21
|
+
import {
|
|
22
|
+
describeTemplateReference,
|
|
23
|
+
getTemplateTagStyle,
|
|
24
|
+
templateTooltip,
|
|
25
|
+
TTemplateMeta,
|
|
26
|
+
} from '../../../../helpers/templates';
|
|
27
|
+
import { useMarkdownRenderer } from '../../../Description/markdownRendererContext';
|
|
11
28
|
|
|
12
29
|
export interface IRichTextFormFieldProps extends Omit<
|
|
13
30
|
IReqoreRichTextEditorProps,
|
|
@@ -17,18 +34,85 @@ export interface IRichTextFormFieldProps extends Omit<
|
|
|
17
34
|
onChange?: (value: string | IReqoreRichTextEditorProps['value']) => void;
|
|
18
35
|
allowTemplates?: boolean;
|
|
19
36
|
templates?: IReqoreFormTemplates;
|
|
37
|
+
/**
|
|
38
|
+
* What the value is. `richtext` (the default) stores the editor's document.
|
|
39
|
+
* `text` stores a plain string: each template reference in it is drawn as a
|
|
40
|
+
* chip named from `templates`, and what is emitted is the string again — for
|
|
41
|
+
* a string field whose value may hold references (`Dear $local:name`).
|
|
42
|
+
*/
|
|
43
|
+
valueFormat?: 'richtext' | 'text';
|
|
44
|
+
/** With `valueFormat: 'text'`: the value holds one line, so Enter adds none. */
|
|
45
|
+
singleLine?: boolean;
|
|
20
46
|
}
|
|
21
47
|
|
|
48
|
+
/**
|
|
49
|
+
* What each offered template value is FOR, keyed by the value itself.
|
|
50
|
+
*
|
|
51
|
+
* Built from the templates a field was already given rather than from the
|
|
52
|
+
* chip's metadata, which carries only `image` / `displayName` / style flags —
|
|
53
|
+
* putting a description there would mean threading one through every producer
|
|
54
|
+
* of a template list.
|
|
55
|
+
*
|
|
56
|
+
* Exported so the mapping is assertable without rendering a Slate editor.
|
|
57
|
+
*/
|
|
58
|
+
export const getChipTooltipDescriptions = (
|
|
59
|
+
templates?: IReqoreFormTemplates
|
|
60
|
+
): Record<string, string> => {
|
|
61
|
+
const out: Record<string, string> = {};
|
|
62
|
+
|
|
63
|
+
/* BOTH shapes, because this list arrives in either one. A picker's items are
|
|
64
|
+
normally grouped by category, but a LONE category is opened onto its values
|
|
65
|
+
where the templates are resolved (`templateItemsToShow`), so a field with
|
|
66
|
+
one category hands down a FLAT list of leaves. Walking only groups made
|
|
67
|
+
that the common case and silently lost every tooltip on it — one category
|
|
68
|
+
is the ordinary shape for a field, not the exception.
|
|
69
|
+
|
|
70
|
+
Recursive rather than two-level: a leaf is recognised by carrying a value
|
|
71
|
+
rather than by its depth, so a deeper catalogue works too. */
|
|
72
|
+
const collect = (items: any[] | undefined): void => {
|
|
73
|
+
items?.forEach((item: any) => {
|
|
74
|
+
const value = typeof item?.value === 'object' ? item?.value?.value : item?.value;
|
|
75
|
+
const description = item?.description ?? item?.short_desc;
|
|
76
|
+
if (typeof value === 'string' && typeof description === 'string' && description) {
|
|
77
|
+
out[value] = description;
|
|
78
|
+
}
|
|
79
|
+
collect(item?.items);
|
|
80
|
+
});
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
collect((templates as any)?.items);
|
|
84
|
+
|
|
85
|
+
return out;
|
|
86
|
+
};
|
|
87
|
+
|
|
22
88
|
export const RichTextFormField = memo(({
|
|
23
89
|
value,
|
|
24
90
|
onChange,
|
|
25
91
|
allowTemplates,
|
|
26
92
|
templates,
|
|
93
|
+
valueFormat = 'richtext',
|
|
94
|
+
singleLine,
|
|
27
95
|
...rest
|
|
28
96
|
}: IRichTextFormFieldProps) => {
|
|
29
|
-
const
|
|
97
|
+
const isText = valueFormat === 'text';
|
|
98
|
+
const [localValue, setLocalValue] = useState<any>(() =>
|
|
99
|
+
isText ? templateTextToNodes(String(value ?? ''), templates) : value
|
|
100
|
+
);
|
|
101
|
+
/* In text mode, the string the editor's document stands for. The value that
|
|
102
|
+
comes back from the parent is usually that same string, and rebuilding the
|
|
103
|
+
document from it would hand the editor a new tree on every keystroke —
|
|
104
|
+
which it answers by replacing its content and moving the cursor to the end. */
|
|
105
|
+
const lastTextRef = useRef(isText ? String(value ?? '') : '');
|
|
30
106
|
|
|
31
107
|
useEffect(() => {
|
|
108
|
+
if (isText) {
|
|
109
|
+
const text = String(value ?? '');
|
|
110
|
+
if (text !== lastTextRef.current) {
|
|
111
|
+
lastTextRef.current = text;
|
|
112
|
+
setLocalValue(templateTextToNodes(text, templates));
|
|
113
|
+
}
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
32
116
|
if (JSON.stringify(value) !== JSON.stringify(localValue)) {
|
|
33
117
|
setLocalValue(value);
|
|
34
118
|
}
|
|
@@ -36,6 +120,12 @@ export const RichTextFormField = memo(({
|
|
|
36
120
|
|
|
37
121
|
useDebounce(
|
|
38
122
|
() => {
|
|
123
|
+
if (isText) {
|
|
124
|
+
if (lastTextRef.current !== String(value ?? '')) {
|
|
125
|
+
onChange?.(lastTextRef.current);
|
|
126
|
+
}
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
39
129
|
if (!isEqual(localValue, value)) {
|
|
40
130
|
onChange?.(localValue);
|
|
41
131
|
}
|
|
@@ -50,6 +140,19 @@ export const RichTextFormField = memo(({
|
|
|
50
140
|
);
|
|
51
141
|
|
|
52
142
|
const handleChange = (val: any): void => {
|
|
143
|
+
if (isText) {
|
|
144
|
+
const text = templateNodesToText(val);
|
|
145
|
+
// A line break also arrives by paste and by drag-and-drop; Enter alone is
|
|
146
|
+
// stopped below. Flattened text is shown as the one line it now is.
|
|
147
|
+
if (singleLine && hasLineBreak(text)) {
|
|
148
|
+
lastTextRef.current = flattenToSingleLine(text);
|
|
149
|
+
setLocalValue(templateTextToNodes(lastTextRef.current, templates));
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
lastTextRef.current = text;
|
|
153
|
+
setLocalValue(val);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
53
156
|
if (JSON.stringify(val) === '[{"type":"paragraph","children":[{"text":""}]}]') {
|
|
54
157
|
setLocalValue(undefined);
|
|
55
158
|
return;
|
|
@@ -57,26 +160,91 @@ export const RichTextFormField = memo(({
|
|
|
57
160
|
setLocalValue(val);
|
|
58
161
|
};
|
|
59
162
|
|
|
60
|
-
|
|
61
|
-
|
|
163
|
+
// One renderer for both surfaces below — the chip's hover and the picker rows
|
|
164
|
+
// show the same strings, so they must be drawn the same way.
|
|
165
|
+
const renderMarkdown = useMarkdownRenderer();
|
|
62
166
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
167
|
+
const descriptionByValue = useMemo(() => getChipTooltipDescriptions(templates), [
|
|
168
|
+
JSON.stringify(templates),
|
|
169
|
+
]);
|
|
66
170
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
171
|
+
const handleGetTagProps = useCallback(
|
|
172
|
+
(tag: any): IReqoreTagProps => {
|
|
173
|
+
const tagValue = tag.value?.toString();
|
|
174
|
+
|
|
175
|
+
if (!tagValue) {
|
|
176
|
+
return {};
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/* A reference in a string is drawn exactly as the collapsed row draws the
|
|
180
|
+
same value (`ReadOnlyTemplateTag`): named from the catalogue, its
|
|
181
|
+
description on hover. Read at render, so a catalogue that arrives
|
|
182
|
+
after the value still names it. */
|
|
183
|
+
if (isText && tagValue.startsWith('$')) {
|
|
184
|
+
const { item } = describeTemplateReference(templates, tagValue);
|
|
185
|
+
const metadata = item?.metadata as TTemplateMeta | undefined;
|
|
186
|
+
return {
|
|
187
|
+
icon: 'ExchangeDollarLine',
|
|
188
|
+
leftIconProps: { image: metadata?.image },
|
|
189
|
+
label: templateChipLabel(templates, tagValue),
|
|
190
|
+
tooltip: templateTooltip(templates, tagValue),
|
|
191
|
+
...getTemplateTagStyle(metadata),
|
|
192
|
+
};
|
|
193
|
+
}
|
|
77
194
|
|
|
78
|
-
|
|
79
|
-
|
|
195
|
+
if (tagValue.startsWith('$')) {
|
|
196
|
+
return {
|
|
197
|
+
icon: 'ExchangeDollarLine',
|
|
198
|
+
leftIconProps: {
|
|
199
|
+
image: tag.metadata?.image,
|
|
200
|
+
},
|
|
201
|
+
labelKey: tag.metadata?.displayName,
|
|
202
|
+
/* Hovering a chip says what the value IS, not how it is spelled.
|
|
203
|
+
Reqore otherwise falls back to the tag's own value, so a chip
|
|
204
|
+
reading "result" reported `$.result` on hover — the reference the
|
|
205
|
+
author already chose, restating the label in engine syntax instead
|
|
206
|
+
of telling them anything. The path stays discoverable in the
|
|
207
|
+
field's help and in the picker row for an unlabelled value. */
|
|
208
|
+
/* Drawn, for the same reason the picker row is: this description is
|
|
209
|
+
the SAME string the row shows, so leaving it raw here would print
|
|
210
|
+
the punctuation the row no longer prints. A tooltip's `content`
|
|
211
|
+
takes a node, and without a host renderer it stays the plain
|
|
212
|
+
string it always was. */
|
|
213
|
+
/* Drawn, for the same reason the picker row is: this is the SAME
|
|
214
|
+
string the row shows, so leaving it raw here would print the
|
|
215
|
+
punctuation the row no longer prints. A drawn description travels
|
|
216
|
+
as the tooltip's `content` — the prop itself is `string |
|
|
217
|
+
IReqoreTooltip`, and only the object form takes a node. Without a
|
|
218
|
+
host renderer it stays the plain string it always was. */
|
|
219
|
+
tooltip:
|
|
220
|
+
descriptionByValue[tagValue] ?
|
|
221
|
+
renderMarkdown ?
|
|
222
|
+
{
|
|
223
|
+
content: renderMarkdown({
|
|
224
|
+
value: descriptionByValue[tagValue],
|
|
225
|
+
compact: true,
|
|
226
|
+
}) as IReqoreTooltip['content'],
|
|
227
|
+
}
|
|
228
|
+
: descriptionByValue[tagValue]
|
|
229
|
+
: undefined,
|
|
230
|
+
...getTemplateTagStyle(tag.metadata),
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return {};
|
|
235
|
+
},
|
|
236
|
+
[descriptionByValue, renderMarkdown, isText, templates]
|
|
237
|
+
);
|
|
238
|
+
|
|
239
|
+
const handleKeyDown = useCallback(
|
|
240
|
+
(event: KeyboardEvent<HTMLTextAreaElement>): void => {
|
|
241
|
+
if (isText && singleLine && event.key === 'Enter') {
|
|
242
|
+
event.preventDefault();
|
|
243
|
+
}
|
|
244
|
+
(rest as { onKeyDown?: (event: KeyboardEvent<HTMLTextAreaElement>) => void }).onKeyDown?.(event);
|
|
245
|
+
},
|
|
246
|
+
[isText, singleLine, (rest as { onKeyDown?: unknown }).onKeyDown]
|
|
247
|
+
);
|
|
80
248
|
|
|
81
249
|
const tags = useMemo<IReqoreRichTextEditorProps['tags']>((): IReqoreRichTextEditorProps['tags'] => {
|
|
82
250
|
const _tags: IReqoreRichTextEditorProps['tags'] = {};
|
|
@@ -87,12 +255,20 @@ export const RichTextFormField = memo(({
|
|
|
87
255
|
label: 'Templates',
|
|
88
256
|
flat: false,
|
|
89
257
|
description: 'Universal values that can be used in multiple places',
|
|
90
|
-
|
|
258
|
+
/* The in-editor list already nests everything under "Templates", so a
|
|
259
|
+
lone category makes the author drill through TWO headers to reach
|
|
260
|
+
the only values on offer. Hoist it. */
|
|
261
|
+
/* Drawn here, at the hand-off to Reqore. A description is prose written
|
|
262
|
+
in the same markdown as every other description this package shows,
|
|
263
|
+
and printing its punctuation at the reader was the last surface still
|
|
264
|
+
doing that. Never made further up: the list is a `JSON.stringify`
|
|
265
|
+
memo key in `TemplateField`. */
|
|
266
|
+
items: renderTemplateItemDescriptions(templateItemsToShow(templates?.items), renderMarkdown),
|
|
91
267
|
};
|
|
92
268
|
}
|
|
93
269
|
|
|
94
270
|
return _tags;
|
|
95
|
-
}, [allowTemplates, templates]);
|
|
271
|
+
}, [allowTemplates, templates, renderMarkdown]);
|
|
96
272
|
|
|
97
273
|
const formattedValue: IReqoreRichTextEditorProps['value'] =
|
|
98
274
|
typeof localValue !== 'object' ? [{ type: 'paragraph', children: [{ text: String(localValue ?? '') }] }]
|
|
@@ -128,6 +304,7 @@ export const RichTextFormField = memo(({
|
|
|
128
304
|
panelProps={{ fluid: true, style: { minWidth: '150px', ...rest.panelProps?.style } }}
|
|
129
305
|
{...rest}
|
|
130
306
|
readOnly={readOnly}
|
|
307
|
+
onKeyDown={handleKeyDown}
|
|
131
308
|
actions={
|
|
132
309
|
readOnly ?
|
|
133
310
|
{ undo: false, redo: false, styling: false }
|
|
@@ -5,6 +5,7 @@ import { memo } from 'react';
|
|
|
5
5
|
import {
|
|
6
6
|
getTemplateTagStyle,
|
|
7
7
|
describeTemplateReference,
|
|
8
|
+
templateTooltip,
|
|
8
9
|
TTemplateMeta,
|
|
9
10
|
} from '../../../../helpers/templates';
|
|
10
11
|
|
|
@@ -18,7 +19,8 @@ export interface IReadOnlyTemplateTagProps {
|
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* The read-only representation of a selected template — a picker-shaped chip:
|
|
21
|
-
* the `$`-dollar icon, the resolved display name (
|
|
22
|
+
* the `$`-dollar icon, the resolved display name (and what the value IS in the
|
|
23
|
+
* tooltip, not the reference that names it), the
|
|
22
24
|
* app image when present, coloured by qorus-ide's scheme (info / qorus purple /
|
|
23
25
|
* success — see `getTemplateTagStyle`). Shared by `TemplateField`'s disabled
|
|
24
26
|
* branch and the compact read-first row so a template reads identically wherever
|
|
@@ -34,7 +36,7 @@ export const ReadOnlyTemplateTag = memo(
|
|
|
34
36
|
icon='ExchangeDollarLine'
|
|
35
37
|
leftIconProps={{ image: metadata?.image }}
|
|
36
38
|
label={label}
|
|
37
|
-
tooltip={value}
|
|
39
|
+
tooltip={templateTooltip(templates, value)}
|
|
38
40
|
{...getTemplateTagStyle(metadata)}
|
|
39
41
|
/>
|
|
40
42
|
</ReqoreTagGroup>
|
|
@@ -264,10 +264,20 @@ export const AutoComponent: StoryObj<typeof meta> = {
|
|
|
264
264
|
docs: {
|
|
265
265
|
description: {
|
|
266
266
|
story:
|
|
267
|
-
'Renders TemplateField over an untyped (`auto`) field that accepts templates. While the field is empty it opens on
|
|
267
|
+
'Renders TemplateField over an untyped (`auto`) field that accepts templates. While the field is empty it opens on an editor to type into, which offers the templates — never on a data-type picker, so the author can write the value they mean without answering how it is stored.',
|
|
268
268
|
},
|
|
269
269
|
},
|
|
270
270
|
},
|
|
271
|
+
play: async ({ canvasElement }) => {
|
|
272
|
+
/* The editor itself, not a class: TemplateField puts `.template-selector`
|
|
273
|
+
on every control it draws, the data-type picker included, so asserting
|
|
274
|
+
the class passed while the story showed "Please select data type". */
|
|
275
|
+
await waitFor(() => expect(canvasElement.querySelector('[contenteditable="true"]')).toBeTruthy(), {
|
|
276
|
+
timeout: 5000,
|
|
277
|
+
});
|
|
278
|
+
expect(canvasElement.textContent).not.toContain('Please select data type');
|
|
279
|
+
expect(canvasElement.textContent).not.toContain('Select Template');
|
|
280
|
+
},
|
|
271
281
|
};
|
|
272
282
|
|
|
273
283
|
export const AllowedValuesWithTemplate: StoryObj<typeof meta> = {
|
|
@@ -674,7 +684,7 @@ export const TemplateCanBeSelected: StoryObj<typeof meta> = {
|
|
|
674
684
|
docs: {
|
|
675
685
|
description: {
|
|
676
686
|
story:
|
|
677
|
-
'Renders TemplateField for a string, opens the templates popover and clicks the Interface ID template — the field switches to the $local:id
|
|
687
|
+
'Renders TemplateField for a string, opens the templates popover and clicks the Interface ID template — the field switches to template mode, where the $local:id reference is a chip named Interface ID inside an editor that can still be typed into.',
|
|
678
688
|
},
|
|
679
689
|
},
|
|
680
690
|
},
|
|
@@ -684,9 +694,16 @@ export const TemplateCanBeSelected: StoryObj<typeof meta> = {
|
|
|
684
694
|
await ShowsTemplatesListForString.play({ canvasElement, ...rest });
|
|
685
695
|
await _testsClickButton({ label: 'Interface ID' });
|
|
686
696
|
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
await
|
|
697
|
+
// The chosen reference reads as the name it was chosen by, in an editor
|
|
698
|
+
// that can still be typed into — not as its spelling.
|
|
699
|
+
await waitFor(
|
|
700
|
+
() => {
|
|
701
|
+
const chip = canvasElement.querySelector('.template-selector [contenteditable="true"] .reqore-tag');
|
|
702
|
+
expect(chip?.textContent).toContain('Interface ID');
|
|
703
|
+
},
|
|
704
|
+
{ timeout: 5000 }
|
|
705
|
+
);
|
|
706
|
+
await expect(canvas.queryByDisplayValue('$local:id')).toBeNull();
|
|
690
707
|
},
|
|
691
708
|
};
|
|
692
709
|
|
|
@@ -991,14 +1008,19 @@ export const EmptyAnyOpensOnTemplates: StoryObj<typeof meta> = {
|
|
|
991
1008
|
docs: {
|
|
992
1009
|
description: {
|
|
993
1010
|
story:
|
|
994
|
-
'An untyped, empty field that accepts templates opens
|
|
1011
|
+
'An untyped, empty field that accepts templates opens on an editor to type into, which offers the templates — never on a data-type picker.',
|
|
995
1012
|
},
|
|
996
1013
|
},
|
|
997
1014
|
},
|
|
998
1015
|
play: async ({ canvasElement }) => {
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1016
|
+
/* The editor itself, not a class: TemplateField puts `.template-selector`
|
|
1017
|
+
on every control it draws, the data-type picker included, so asserting
|
|
1018
|
+
the class passed while the story showed "Please select data type". */
|
|
1019
|
+
await waitFor(() => expect(canvasElement.querySelector('[contenteditable="true"]')).toBeTruthy(), {
|
|
1020
|
+
timeout: 5000,
|
|
1021
|
+
});
|
|
1022
|
+
expect(canvasElement.textContent).not.toContain('Please select data type');
|
|
1023
|
+
expect(canvasElement.textContent).not.toContain('Select Template');
|
|
1002
1024
|
},
|
|
1003
1025
|
};
|
|
1004
1026
|
|