@case-framework/survey-editor-ui 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/README.md +85 -0
  2. package/dist/src/components/c-ui/dot-background.d.ts +2 -2
  3. package/dist/src/components/rich-text/content-policy.d.ts +10 -1
  4. package/dist/src/components/rich-text/nodes/survey-rich-text-heading-node.d.ts +4 -1
  5. package/dist/src/components/rich-text-editor/plugins/block-shortcut-plugin.d.ts +4 -2
  6. package/dist/src/components/rich-text-editor/plugins/docked-toolbar-plugin.d.ts +3 -1
  7. package/dist/src/components/rich-text-editor/plugins/heading-policy-plugin.d.ts +13 -0
  8. package/dist/src/components/rich-text-editor/plugins/link-shortcut-plugin.d.ts +3 -0
  9. package/dist/src/components/rich-text-editor/plugins/slash-command-menu-plugin.d.ts +3 -1
  10. package/dist/src/components/rich-text-editor/plugins/sync-editor-value-plugin.d.ts +5 -2
  11. package/dist/src/components/rich-text-editor/rich-text-editor-provider.d.ts +18 -0
  12. package/dist/src/components/rich-text-editor/rich-text-editor-utils.d.ts +22 -5
  13. package/dist/src/components/rich-text-editor/rich-text-editor.d.ts +4 -1
  14. package/dist/src/index.d.ts +2 -0
  15. package/dist/src/lib/utils.d.ts +1 -2
  16. package/dist/src/modules/default-item-registry/items/choice/editor/option-create.d.ts +1 -1
  17. package/dist/src/modules/default-item-registry/items/choice/editor/option-editor-card.d.ts +2 -2
  18. package/dist/src/modules/default-item-registry/items/choice/editor/response-options-list.d.ts +1 -1
  19. package/dist/src/modules/default-item-registry/items/form/editor/config-editor.d.ts +1 -1
  20. package/dist/src/modules/default-item-registry/items/form/editor/editor-metadata.d.ts +10 -0
  21. package/dist/src/modules/default-item-registry/items/form/editor/field-edit-dialog.d.ts +1 -1
  22. package/dist/src/modules/default-item-registry/items/form/editor/field-group-layout-dialog.d.ts +1 -1
  23. package/dist/src/modules/default-item-registry/items/form/editor/field-item-preview.d.ts +1 -1
  24. package/dist/src/modules/default-item-registry/items/form/editor/field-key-dialog.d.ts +1 -1
  25. package/dist/src/modules/default-item-registry/items/form/editor/field-sort-dialog.d.ts +1 -1
  26. package/dist/src/modules/default-item-registry/items/form/editor/field-type-shared.d.ts +8 -8
  27. package/dist/src/modules/default-item-registry/items/form/editor/response-field-groups-list.d.ts +1 -1
  28. package/dist/src/modules/default-item-registry/items/form/editor/simple-field-editor.d.ts +1 -1
  29. package/dist/src/modules/survey-editor/assistant/apply.d.ts +1 -11
  30. package/dist/src/modules/survey-editor/assistant/index.d.ts +1 -1
  31. package/dist/src/modules/survey-editor/assistant/snapshot.d.ts +1 -2
  32. package/dist/src/modules/survey-editor/hooks/focus-when-available.d.ts +8 -0
  33. package/dist/src/modules/survey-editor/hooks/item-clipboard-shortcut.d.ts +16 -0
  34. package/dist/src/modules/survey-editor/routes/editor/_components/expression-diagnostics-status-model.d.ts +10 -0
  35. package/dist/src/modules/survey-editor/routes/editor/_components/workspace-presets.d.ts +7 -7
  36. package/dist/src/modules/survey-editor/routes/editor/item-editor/_components/item-drag-drop.d.ts +2 -1
  37. package/dist/src/modules/survey-editor/routes/editor/item-editor/_components/outline-selection.d.ts +6 -0
  38. package/dist/src/modules/survey-editor/store/editor-store.d.ts +1 -2
  39. package/dist/src/modules/survey-editor/survey-editor-config.d.ts +2 -2
  40. package/dist/src/modules/survey-editor/survey-editor.d.ts +2 -1
  41. package/dist/survey-editor-ui.cjs.js +64 -64
  42. package/dist/survey-editor-ui.cjs.js.map +1 -1
  43. package/dist/survey-editor-ui.css +1 -1
  44. package/dist/survey-editor-ui.es.js +31730 -33230
  45. package/dist/survey-editor-ui.es.js.map +1 -1
  46. package/package.json +24 -19
  47. package/dist/src/modules/default-item-registry/items/choice/display-order.d.ts +0 -1
  48. package/dist/src/modules/default-item-registry/items/choice/model.d.ts +0 -28
  49. package/dist/src/modules/default-item-registry/items/form/model.d.ts +0 -163
package/README.md CHANGED
@@ -12,6 +12,11 @@ For repository development and custom item registration, see
12
12
  Save or Back. The host owns persistence, routing, and its header; the editor
13
13
  owns survey mutations and undo/redo history.
14
14
 
15
+ The main editor export includes the assistant launcher UI. Host applications
16
+ must provide versions of `ai` and `@ai-sdk/react` compatible with the peer
17
+ ranges in `package.json`. The assistant's Mastra peers remain optional because
18
+ they are only needed by server integrations.
19
+
15
20
  Use `controllerRef` for host-triggered commands and `onHostStateChange` to keep
16
21
  host controls in sync with the editor:
17
22
 
@@ -163,3 +168,83 @@ system.
163
168
  shared UI stylesheet and theme configuration belong to the consuming
164
169
  workspace rather than being independently repeated by every component
165
170
  package.
171
+
172
+ ## Standalone rich text editing
173
+
174
+ `RichTextEditor` and `RichTextBlockEditor` work without `SurveyEditor` or a survey
175
+ configuration provider. They automatically supply default English translations,
176
+ tooltips, and confirmation dialogs. Wrap one or more editors in the exported
177
+ `RichTextEditorProvider` to configure their UI language or translation overrides:
178
+
179
+ ```tsx
180
+ import {
181
+ RichTextBlockEditor,
182
+ RichTextEditorProvider,
183
+ type RichTextEditorProps,
184
+ } from "@case-framework/survey-editor-ui";
185
+ import { useState } from "react";
186
+
187
+ function NoticeEditor() {
188
+ const [value, setValue] = useState<RichTextEditorProps["value"]>();
189
+ return (
190
+ <div className="survey-editor">
191
+ <RichTextEditorProvider language="nl">
192
+ <RichTextBlockEditor
193
+ aria-label="Notice content"
194
+ value={value}
195
+ onChange={(change) => setValue(change.value)}
196
+ toolbarMode="docked"
197
+ dockedToolbarVisibility="always"
198
+ styleControls={[
199
+ { kind: "weight", value: "strong" },
200
+ { kind: "italic", value: "italic" },
201
+ { kind: "underline", value: "underline" },
202
+ ]}
203
+ contentPolicy={{
204
+ allowLinks: false,
205
+ allowTemplateVariables: false,
206
+ allowedBlockTypes: { image: false, separator: false, infoBox: false },
207
+ }}
208
+ />
209
+ </RichTextEditorProvider>
210
+ </div>
211
+ );
212
+ }
213
+ ```
214
+
215
+ Use this in a client component in Next.js. Apply the host styling setup above;
216
+ the provider does not import CSS or install an application toaster.
217
+
218
+ `language` selects bundled English/Dutch UI messages, with English fallback.
219
+ `localizations` merges overrides using the existing editor message keys (for
220
+ example `defaultEditors.imagePopover`). An optional `translate(key, values)`
221
+ callback takes precedence when the host owns translation. Toolbar, block-menu, and link-editor labels use the `richTextEditor` message namespace.
222
+ Within a survey, rich text automatically inherits the survey's translator,
223
+ including custom catalogs. A nested provider can override it for a specific editor.
224
+
225
+ Formatting, toolbar modes, read-only behavior (`editable`), templates, links,
226
+ and block restrictions remain per-editor props. Asset resolution, registration,
227
+ and deletion are optional callbacks; no survey store is required. Content remains
228
+ the same serialized Lexical JSON (`change.value`), so existing documents and
229
+ renderers remain compatible. Content policies configure editing behavior; hosts
230
+ must still validate persisted documents against their own accepted content rules.
231
+
232
+ ### Document heading levels
233
+
234
+ `RichTextContentPolicy.allowedHeadingLevels` configures the heading choices in the
235
+ block toolbar, slash menu, and `#` shortcuts. It defaults to `[1, 2]`; existing
236
+ disallowed levels normalize to the nearest permitted shallower level (or the minimum
237
+ permitted level). An empty list converts headings to paragraphs while retaining content
238
+ and formatting. This applies to pasted content, loaded JSON, and serialized content. For notices, use `[1, 2, 3, 4, 5]` with
239
+ `headingLevelOffset={1}` on both `RichTextBlockEditor` and `RichTextContentView`.
240
+ Document level 1 then renders as HTML `h2`, through level 5 as `h6`. Choices that
241
+ would exceed HTML `h6` are omitted. The offset changes rendering, not saved JSON.
242
+ The standalone editor defaults to offset 0; survey fields use offset 1 to match
243
+ the survey player. Keep an editor's offset stable while editing; changing it
244
+ recreates the Lexical editor.
245
+
246
+ In editable mode, correcting a supplied value to satisfy the heading policy calls
247
+ `onChange` once with the normalized editor value, even before the user types.
248
+ Controlled hosts should accept that value so saving matches the visible document.
249
+ Ordinary synchronization of an already-valid value and read-only normalization do
250
+ not emit this callback.
@@ -45,8 +45,8 @@ declare const dotBackgroundSpacingVariants: {
45
45
  type DotBackgroundVariant = keyof typeof dotBackgroundColorVariants;
46
46
  type DotBackgroundSpacingVariant = keyof typeof dotBackgroundSpacingVariants;
47
47
  declare const dotBackgroundVariants: (props?: ({
48
- variant?: "default" | "secondary" | "accent" | "custom" | "card" | "muted" | null | undefined;
49
- spacing?: "default" | "custom" | "dense" | "loose" | "relaxed" | null | undefined;
48
+ variant?: "default" | "secondary" | "accent" | "muted" | "card" | "custom" | null | undefined;
49
+ spacing?: "default" | "dense" | "loose" | "custom" | "relaxed" | null | undefined;
50
50
  } & import('class-variance-authority/types').ClassProp) | undefined) => string;
51
51
  type DotBackgroundStyle = React.CSSProperties & {
52
52
  "--dot-background-color"?: string;
@@ -1,4 +1,4 @@
1
- import { Content, RichTextStyle } from '@case-framework/survey-core';
1
+ import { Content, RichTextHeadingBlock, RichTextStyle } from '@case-framework/survey-core';
2
2
  export type RichTextEditorVariant = "compact" | "block";
3
3
  export type RichTextSupportedBlockType = "paragraph" | "bulletList" | "image" | "separator" | "heading" | "infoBox";
4
4
  export type RichTextStyleAttribute = keyof RichTextStyle;
@@ -6,6 +6,12 @@ export interface RichTextContentPolicy {
6
6
  variant?: RichTextEditorVariant;
7
7
  allowedBlockTypes?: Partial<Record<RichTextSupportedBlockType, boolean>>;
8
8
  allowedStyleAttributes?: Partial<Record<RichTextStyleAttribute, boolean>>;
9
+ /**
10
+ * Allowed document heading levels; defaults to [1, 2]. An empty list disables headings.
11
+ * Headings must also be enabled by allowedBlockTypes.heading; false takes precedence.
12
+ * Disallowed levels normalize to the nearest permitted shallower level (or the minimum).
13
+ */
14
+ allowedHeadingLevels?: readonly RichTextHeadingBlock["level"][];
9
15
  allowLinks?: boolean;
10
16
  allowTemplateVariables?: boolean;
11
17
  allowLineBreaks?: boolean;
@@ -17,3 +23,6 @@ export declare const DEFAULT_BLOCK_CONTENT_POLICY: RichTextContentPolicy;
17
23
  export declare function mergeRichTextContentPolicy(base: RichTextContentPolicy, override?: RichTextContentPolicy): RichTextContentPolicy;
18
24
  export declare function sanitizeContentForPolicy(content: Content | undefined, policy?: RichTextContentPolicy): Content | undefined;
19
25
  export declare function isBlockContentPolicyVariant(policy?: RichTextContentPolicy): boolean;
26
+ export declare function getAllowedHeadingLevels(policy?: RichTextContentPolicy): RichTextHeadingBlock["level"][];
27
+ /** Null means headings are disabled; preserve content as a paragraph. */
28
+ export declare function resolveHeadingLevelForPolicy(level: RichTextHeadingBlock["level"], policy?: RichTextContentPolicy): RichTextHeadingBlock["level"] | null;
@@ -11,6 +11,7 @@ export declare class SurveyRichTextHeadingNode extends ParagraphNode {
11
11
  static clone(node: SurveyRichTextHeadingNode): SurveyRichTextHeadingNode;
12
12
  constructor(level?: RichTextHeadingBlock["level"], key?: string);
13
13
  getHeadingLevel(): RichTextHeadingBlock["level"];
14
+ setHeadingLevel(level: RichTextHeadingBlock["level"]): this;
14
15
  createDOM(config: EditorConfig): HTMLElement;
15
16
  updateDOM(prevNode: SurveyRichTextHeadingNode): boolean;
16
17
  static importDOM(): DOMConversionMap | null;
@@ -19,7 +20,9 @@ export declare class SurveyRichTextHeadingNode extends ParagraphNode {
19
20
  };
20
21
  static importJSON(serializedNode: SerializedSurveyRichTextHeadingNode): SurveyRichTextHeadingNode;
21
22
  exportJSON(): SerializedSurveyRichTextHeadingNode;
22
- /** Backspace at block start: replace heading with a paragraph (same children and block styles). */
23
+ /** Replace this heading with a paragraph, preserving children, selection, and block styles. */
24
+ convertToParagraph(): ParagraphNode;
25
+ /** Lexical's backspace-at-block-start handler. */
23
26
  collapseAtStart(): boolean;
24
27
  insertNewAfter(rangeSelection: RangeSelection, restoreSelection?: boolean): ParagraphNode;
25
28
  }
@@ -1,7 +1,9 @@
1
+ import { RichTextHeadingBlock } from '@case-framework/survey-core';
1
2
  export interface BlockShortcutPluginProps {
2
3
  bulletListsEnabled: boolean;
3
4
  headingsEnabled: boolean;
5
+ allowedHeadingLevels: readonly RichTextHeadingBlock["level"][];
4
6
  }
5
7
  /** Converts an exact marker-only root paragraph while the space key is being handled. */
6
- export declare function $convertBlockShortcut(bulletListsEnabled: boolean, headingsEnabled: boolean): boolean;
7
- export declare function BlockShortcutPlugin({ bulletListsEnabled, headingsEnabled, }: BlockShortcutPluginProps): null;
8
+ export declare function $convertBlockShortcut(bulletListsEnabled: boolean, headingsEnabled: boolean, allowedHeadingLevels?: readonly RichTextHeadingBlock["level"][]): boolean;
9
+ export declare function BlockShortcutPlugin({ bulletListsEnabled, headingsEnabled, allowedHeadingLevels, }: BlockShortcutPluginProps): null;
@@ -1,7 +1,8 @@
1
+ import { RichTextHeadingBlock } from '@case-framework/survey-core';
1
2
  import { RefObject } from 'react';
2
3
  import { RichTextStyleControl, RichTextTemplateVariable } from '../rich-text-editor-utils';
3
4
  /** A stable, in-flow toolbar for longer block editors. */
4
- export declare function DockedToolbarPlugin({ editable, visibility, position, editorOwnerId, sticky, linksEnabled, blockAlignmentEnabled, surfaceRef, toolbarClassName, styleControls, templateVariables, bulletListsEnabled, headingsEnabled, infoBoxesEnabled, imagesEnabled, separatorsEnabled, }: {
5
+ export declare function DockedToolbarPlugin({ editable, visibility, position, editorOwnerId, sticky, linksEnabled, blockAlignmentEnabled, surfaceRef, toolbarClassName, styleControls, templateVariables, bulletListsEnabled, headingsEnabled, allowedHeadingLevels, infoBoxesEnabled, imagesEnabled, separatorsEnabled, }: {
5
6
  editable: boolean;
6
7
  visibility: "active" | "always";
7
8
  position: "flow" | "above";
@@ -15,6 +16,7 @@ export declare function DockedToolbarPlugin({ editable, visibility, position, ed
15
16
  templateVariables: RichTextTemplateVariable[];
16
17
  bulletListsEnabled: boolean;
17
18
  headingsEnabled: boolean;
19
+ allowedHeadingLevels: readonly RichTextHeadingBlock["level"][];
18
20
  infoBoxesEnabled: boolean;
19
21
  imagesEnabled: boolean;
20
22
  separatorsEnabled: boolean;
@@ -0,0 +1,13 @@
1
+ import { LexicalEditor, SerializedEditorState } from 'lexical';
2
+ import { RichTextContentPolicy } from '../../rich-text/content-policy';
3
+ /** Normalize within the original Lexical transaction so paste and undo stay atomic. */
4
+ export declare function registerHeadingPolicy(editor: LexicalEditor, policy: RichTextContentPolicy): () => void;
5
+ /**
6
+ * Normalize incoming JSON before controlled-value comparison and synchronization.
7
+ * This keeps the sync target consistent with the heading transform's result,
8
+ * preventing repeated reapplication of a disallowed value supplied by the host.
9
+ */
10
+ export declare function normalizeHeadingValue(value: SerializedEditorState, policy: RichTextContentPolicy): SerializedEditorState;
11
+ export declare function HeadingPolicyPlugin({ policy }: {
12
+ policy: RichTextContentPolicy;
13
+ }): null;
@@ -0,0 +1,3 @@
1
+ export declare function $convertLinkShortcut(insertSpace?: boolean): boolean;
2
+ export declare function $pasteLinkShortcut(text: string): boolean;
3
+ export declare function LinkShortcutPlugin(): null;
@@ -1,10 +1,12 @@
1
+ import { RichTextHeadingBlock } from '@case-framework/survey-core';
1
2
  import { RefObject } from 'react';
2
3
  import { RichTextStyleControl, RichTextTemplateVariable } from '../rich-text-editor-utils';
3
- export declare function SlashCommandMenuPlugin({ editable, linksEnabled, bulletListsEnabled, headingsEnabled, infoBoxesEnabled, imagesEnabled, separatorsEnabled, editorOwnerId, surfaceRef, styleControls, templateVariables, commandMenuClassName, }: {
4
+ export declare function SlashCommandMenuPlugin({ editable, linksEnabled, bulletListsEnabled, headingsEnabled, allowedHeadingLevels, infoBoxesEnabled, imagesEnabled, separatorsEnabled, editorOwnerId, surfaceRef, styleControls, templateVariables, commandMenuClassName, }: {
4
5
  editable: boolean;
5
6
  linksEnabled: boolean;
6
7
  bulletListsEnabled?: boolean;
7
8
  headingsEnabled?: boolean;
9
+ allowedHeadingLevels: readonly RichTextHeadingBlock["level"][];
8
10
  infoBoxesEnabled?: boolean;
9
11
  imagesEnabled?: boolean;
10
12
  separatorsEnabled?: boolean;
@@ -1,4 +1,7 @@
1
- import { SerializedEditorState } from 'lexical';
2
- export declare function SyncEditorValuePlugin({ value }: {
1
+ import { EditorState, SerializedEditorState } from 'lexical';
2
+ export declare function SyncEditorValuePlugin({ value, normalizationSource, onNormalize, }: {
3
3
  value?: SerializedEditorState | null;
4
+ /** The supplied value before a policy correction; absent for ordinary synchronization. */
5
+ normalizationSource?: SerializedEditorState;
6
+ onNormalize?: (state: EditorState) => void;
4
7
  }): null;
@@ -0,0 +1,18 @@
1
+ import { ReactNode } from 'react';
2
+ import { LocalizationCatalog, LocalizationTranslate } from '@case-framework/ui-localization';
3
+ export interface RichTextEditorProviderProps {
4
+ children: ReactNode;
5
+ /** UI language, independent of the document language. Defaults to English. */
6
+ language?: string;
7
+ /** Overrides merged with the toolkit's bundled English and Dutch messages. */
8
+ localizations?: LocalizationCatalog;
9
+ /** Optional host translator; takes precedence over language and localizations. */
10
+ translate?: LocalizationTranslate;
11
+ }
12
+ /** Supplies rich text UI services without survey state, workspace, or assistant dependencies. */
13
+ export declare function RichTextEditorProvider({ children, language, localizations, translate, }: RichTextEditorProviderProps): import("react").JSX.Element;
14
+ /** Reuse a host provider, or supply defaults for an editor rendered on its own. */
15
+ export declare function RichTextEditorBoundary({ children }: {
16
+ children: ReactNode;
17
+ }): string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | import('react').ReactPortal | import('react').ReactElement<unknown, string | import('react').JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | import("react").JSX.Element | null | undefined;
18
+ export declare function useRichTextTranslation(namespace?: string): LocalizationTranslate;
@@ -1,3 +1,4 @@
1
+ import { LocalizationTranslate } from '@case-framework/ui-localization';
1
2
  import { RichTextInfoBoxTone } from '../../../components/rich-text/nodes/rich-text-info-box-node';
2
3
  import { SurveyRichTextHeadingNode } from '../../../components/rich-text/nodes/survey-rich-text-heading-node';
3
4
  import { EditorConfig, ElementFormatType, LexicalCommand, LexicalEditor, LexicalNode, NodeKey, ParagraphNode, RangeSelection, SerializedEditorState, SerializedTextNode, Spread, TextFormatType, TextNode } from 'lexical';
@@ -45,7 +46,7 @@ export type SlashCommandGroupId = "formatting" | "blocks" | "insert";
45
46
  /**
46
47
  * Block styles exposed by the rich-text toolbar.
47
48
  */
48
- export type RichTextBlockStyle = "bullet-list" | "heading-1" | "heading-2" | "paragraph";
49
+ export type RichTextBlockStyle = "bullet-list" | `heading-${RichTextHeadingBlock["level"]}` | "paragraph";
49
50
  export type RichTextBlockSelectionStyle = RichTextBlockStyle | "mixed";
50
51
  export declare const SLASH_COMMAND_GROUP_ORDER: Record<SlashCommandGroupId, number>;
51
52
  export type SlashCommandItem = {
@@ -109,13 +110,27 @@ export type SlashCommandItem = {
109
110
  };
110
111
  export declare function getTemplateVariableText(templateKey: string): string;
111
112
  export declare function getStyleControlKey(control: RichTextStyleControl): string;
112
- export declare function resolveStyleControl(control: RichTextStyleControl): {
113
- label: string;
114
- title: string;
113
+ export declare function getStyleControlStyle(control: RichTextStyleControl): {
115
114
  property: string;
116
115
  value: string;
117
116
  };
118
- export declare function getSlashCommandItems(styleControls: RichTextStyleControl[], templateVariables: RichTextTemplateVariable[], linksEnabled?: boolean, bulletListsEnabled?: boolean, headingsEnabled?: boolean, infoBoxesEnabled?: boolean, imagesEnabled?: boolean, separatorsEnabled?: boolean): SlashCommandItem[];
117
+ export declare function getStyleControlLabels(control: RichTextStyleControl, t: LocalizationTranslate): {
118
+ label: string;
119
+ title: string;
120
+ };
121
+ interface SlashCommandItemsOptions {
122
+ t: LocalizationTranslate;
123
+ styleControls: RichTextStyleControl[];
124
+ templateVariables: RichTextTemplateVariable[];
125
+ linksEnabled?: boolean;
126
+ bulletListsEnabled?: boolean;
127
+ headingsEnabled?: boolean;
128
+ allowedHeadingLevels?: readonly RichTextHeadingBlock["level"][];
129
+ infoBoxesEnabled?: boolean;
130
+ imagesEnabled?: boolean;
131
+ separatorsEnabled?: boolean;
132
+ }
133
+ export declare function getSlashCommandItems({ t, styleControls, templateVariables, linksEnabled, bulletListsEnabled, headingsEnabled, allowedHeadingLevels, infoBoxesEnabled, imagesEnabled, separatorsEnabled, }: SlashCommandItemsOptions): SlashCommandItem[];
119
134
  export declare function $insertSurveyRichTextHeading(level: RichTextHeadingBlock["level"]): boolean;
120
135
  export declare function $insertSurveyRichTextParagraph(): boolean;
121
136
  /** Returns a shared style, "mixed" for supported mixed blocks, or null if unsupported. */
@@ -225,3 +240,5 @@ export declare class RichTextLinkNode extends TextNode {
225
240
  export declare function $createTemplateVariableNode(templateKey: string): TemplateVariableNode;
226
241
  export declare function $createRichTextLinkNode(text: string, url: string): RichTextLinkNode;
227
242
  export declare function $isRichTextLinkNode(node: unknown): node is RichTextLinkNode;
243
+ /** Preserve legacy survey labels for the default [1, 2] policy; otherwise number levels explicitly. */
244
+ export declare function getHeadingLabel(level: RichTextHeadingBlock["level"], allowedLevels: readonly RichTextHeadingBlock["level"][], t: LocalizationTranslate): string;
@@ -37,6 +37,8 @@ export interface RichTextEditorProps {
37
37
  templateVariables?: RichTextTemplateVariable[];
38
38
  editorVariant?: "compact" | "block";
39
39
  contentPolicy?: RichTextContentPolicy;
40
+ /** HTML heading offset; document levels remain unchanged. Defaults to 0. */
41
+ headingLevelOffset?: 0 | 1 | 2 | 3 | 4 | 5;
40
42
  resolveImageAssetUrl?: (assetId: string) => string | undefined;
41
43
  imageAssets?: RichTextImageAssetOption[];
42
44
  /** When set, the image popover can add a new embedded survey image asset and return its id. */
@@ -45,10 +47,11 @@ export interface RichTextEditorProps {
45
47
  imageAssetDeletion?: RichTextImageAssetDeletionHandlers;
46
48
  linksEnabled?: boolean;
47
49
  "aria-label"?: string;
50
+ /** Reports user edits and policy corrections to supplied values. Read-only value synchronization does not report corrections. */
48
51
  onChange?: (change: RichTextEditorChange) => void;
49
52
  onFocus?: () => void;
50
53
  onBlur?: () => void;
51
54
  onKeyDown?: KeyboardEventHandler<HTMLDivElement>;
52
55
  onKeyDownCapture?: KeyboardEventHandler<HTMLDivElement>;
53
56
  }
54
- export declare function RichTextEditor({ id, value, placeholder, autoFocus, autoFocusSelection, editable, wrapperClassName, surfaceClassName, contentClassName, endOfContentEditingArea, placeholderClassName, toolbarClassName, toolbarMode, dockedToolbarVisibility, dockedToolbarPosition, dockedToolbarSticky, commandMenuClassName, styleControls, templateVariables, editorVariant, contentPolicy, resolveImageAssetUrl, imageAssets, registerImageAsset, imageAssetDeletion, linksEnabled, "aria-label": ariaLabel, onChange, onFocus, onBlur, onKeyDown, onKeyDownCapture, }: RichTextEditorProps): import("react").JSX.Element;
57
+ export declare function RichTextEditor(props: RichTextEditorProps): import("react").JSX.Element;
@@ -12,3 +12,5 @@ export type { CreateComposedEditorRegistryOptions, CreateRegistryEntriesOptions,
12
12
  export type { SurveyEditorProps, SurveyEditorController, SurveyEditorHostState, SurveyEditorStateChange, SurveyEditorWorkspace, SurveyEditorWorkspacePanelOptions, SurveyEditorAssistantController, SurveyAssistantSnapshotOptions, CreateSnapshotSurveyEditorAIProviderOptions, UseSurveyEditorAssistantIntegrationOptions, SurveyEditorAITaskCacheOptions, SurveyEditorAITaskExecution, SurveyEditorAITaskExecutor, SurveyEditorLocation, EditorItemDefinition, EditorItemDefinitionRegistry, ItemInitialDataContext, ComposedEditorItemRegistry, EntriesToComposedEditorRegistryOptions, EntriesToParticipantRegistryOptions, ItemEditorComponentProps, ItemIconComponent, ItemPreviewComponentProps, ItemPreviewMode, ItemRegistryEntry, ItemRendererComponentProps, ItemSearchAdapter, RegistryValidationIssue, RegistryValidationMode, RegistryValidationOptions, RegistryValidationResult, SurveyPlayerItemRegistry, SurveyEditorAIProvider, SurveyAIRequestOptions, RichTextEditorChange, RichTextEditorProps, RichTextBlockEditorChange, RichTextBlockEditorProps, RichTextContentPolicy, RichTextLinkPayload, RichTextStyleControl, RichTextTemplateVariable, RichTextContentViewProps, RichTextEditorVariant, RichTextStyleAttribute, RichTextSupportedBlockType, SerializedRichTextLinkNode, SerializedTemplateVariableNode, SurveyImageAssetManagerProps, ParsedSurveySession, ParsedSurveySessionFormat, } from './modules/survey-editor';
13
13
  export type { SurveyEditorDateLocales } from './modules/survey-editor/localization/date-fns';
14
14
  export type { FilepickerDropzoneLabels, FilepickerDropzoneProps, } from './components/c-ui/filepicker-dropzone';
15
+ export { RichTextEditorProvider } from './components/rich-text-editor/rich-text-editor-provider';
16
+ export type { RichTextEditorProviderProps } from './components/rich-text-editor/rich-text-editor-provider';
@@ -1,2 +1 @@
1
- import { ClassValue } from 'clsx';
2
- export declare function cn(...inputs: ClassValue[]): string;
1
+ export { cn } from 'cn';
@@ -1,5 +1,5 @@
1
1
  import { Content } from '@case-framework/survey-core';
2
- import { ChoiceOptionConfig } from '../model';
2
+ import { ChoiceOptionConfig } from '@case-framework/survey-items/choice';
3
3
  interface ChoiceOptionCreateProps {
4
4
  isOpen: boolean;
5
5
  open: () => void;
@@ -1,6 +1,6 @@
1
1
  import { Content, SurveyItemTranslations } from '@case-framework/survey-core';
2
- import { FormItemConfig } from '../../form/model';
3
- import { ChoiceOptionConfig } from '../model';
2
+ import { FormItemConfig } from '@case-framework/survey-items/form';
3
+ import { ChoiceOptionConfig } from '@case-framework/survey-items/choice';
4
4
  interface ChoiceOptionEditorCardProps {
5
5
  option: ChoiceOptionConfig;
6
6
  existingOptions: ChoiceOptionConfig[];
@@ -1,6 +1,6 @@
1
1
  import { Content } from '@case-framework/survey-core';
2
2
  import { default as React } from 'react';
3
- import { ChoiceOptionConfig } from '../model';
3
+ import { ChoiceOptionConfig } from '@case-framework/survey-items/choice';
4
4
  export interface ChoiceOptionListItem {
5
5
  option: ChoiceOptionConfig;
6
6
  label: string;
@@ -1,5 +1,5 @@
1
1
  import { SurveyItemTranslations } from '@case-framework/survey-core';
2
- import { FormItemConfig } from '../model';
2
+ import { FormItemConfig } from '@case-framework/survey-items/form';
3
3
  interface FormConfigEditorProps {
4
4
  itemId: string;
5
5
  config: FormItemConfig;
@@ -0,0 +1,10 @@
1
+ import { FormFieldType, FormFieldValidationType } from '@case-framework/survey-items/form';
2
+ export declare const FORM_BROWSER_AUTOCOMPLETE_OPTIONS: readonly ["name", "given-name", "family-name", "nickname", "email", "username", "organization", "organization-title", "street-address", "address-line1", "address-line2", "address-level2", "address-level1", "postal-code", "country-name", "tel", "url", "one-time-code"];
3
+ export interface FormFieldValidationSuggestion {
4
+ type: FormFieldValidationType;
5
+ label: string;
6
+ description: string;
7
+ valueKind: "none" | "number" | "text" | "date";
8
+ defaultValue?: number | string;
9
+ }
10
+ export declare function getFormFieldValidationSuggestions(type: FormFieldType): FormFieldValidationSuggestion[];
@@ -1,4 +1,4 @@
1
- import { FormFieldConfig } from '../model';
1
+ import { FormFieldConfig } from '@case-framework/survey-items/form';
2
2
  interface FormFieldEditDialogProps {
3
3
  open: boolean;
4
4
  field: FormFieldConfig | null;
@@ -1,4 +1,4 @@
1
- import { FormFieldGroupLayoutConfig } from '../model';
1
+ import { FormFieldGroupLayoutConfig } from '@case-framework/survey-items/form';
2
2
  interface FormFieldGroupLayoutDialogProps {
3
3
  open: boolean;
4
4
  initialLayout: FormFieldGroupLayoutConfig;
@@ -1,4 +1,4 @@
1
- import { FormFieldType } from '../model';
1
+ import { FormFieldType } from '@case-framework/survey-items/form';
2
2
  export interface FormFieldItemPreviewProps {
3
3
  codingKey: string;
4
4
  fieldType: FormFieldType;
@@ -1,4 +1,4 @@
1
- import { FormFieldConfig } from '../model';
1
+ import { FormFieldConfig } from '@case-framework/survey-items/form';
2
2
  interface FormFieldKeyDialogProps {
3
3
  open: boolean;
4
4
  field: FormFieldConfig | null;
@@ -1,4 +1,4 @@
1
- import { FormFieldConfig } from '../model';
1
+ import { FormFieldConfig } from '@case-framework/survey-items/form';
2
2
  interface FormFieldSortDialogProps {
3
3
  open: boolean;
4
4
  groupId: string | null;
@@ -1,12 +1,12 @@
1
- import { FormFieldType } from '../model';
1
+ import { FormFieldType } from '@case-framework/survey-items/form';
2
2
  export declare const FORM_FIELD_TYPES: ("number" | "input" | "select" | "textarea" | "switch" | "slider" | "datepicker")[];
3
3
  export declare const FORM_FIELD_TYPE_ICON: {
4
- input: react.ForwardRefExoticComponent<any>;
5
- textarea: react.ForwardRefExoticComponent<any>;
6
- number: react.ForwardRefExoticComponent<any>;
7
- datepicker: react.ForwardRefExoticComponent<any>;
8
- switch: react.ForwardRefExoticComponent<any>;
9
- select: react.ForwardRefExoticComponent<any>;
10
- slider: react.ForwardRefExoticComponent<any>;
4
+ input: import('react').ForwardRefExoticComponent<Omit<import('lucide-react').LucideProps, "ref"> & import('react').RefAttributes<SVGSVGElement>>;
5
+ textarea: import('react').ForwardRefExoticComponent<Omit<import('lucide-react').LucideProps, "ref"> & import('react').RefAttributes<SVGSVGElement>>;
6
+ number: import('react').ForwardRefExoticComponent<Omit<import('lucide-react').LucideProps, "ref"> & import('react').RefAttributes<SVGSVGElement>>;
7
+ datepicker: import('react').ForwardRefExoticComponent<Omit<import('lucide-react').LucideProps, "ref"> & import('react').RefAttributes<SVGSVGElement>>;
8
+ switch: import('react').ForwardRefExoticComponent<Omit<import('lucide-react').LucideProps, "ref"> & import('react').RefAttributes<SVGSVGElement>>;
9
+ select: import('react').ForwardRefExoticComponent<Omit<import('lucide-react').LucideProps, "ref"> & import('react').RefAttributes<SVGSVGElement>>;
10
+ slider: import('react').ForwardRefExoticComponent<Omit<import('lucide-react').LucideProps, "ref"> & import('react').RefAttributes<SVGSVGElement>>;
11
11
  };
12
12
  export declare function getFormFieldTypeLabel(t: (key: string) => string, fieldType: FormFieldType): string;
@@ -1,4 +1,4 @@
1
- import { FormFieldType, FormFieldGroupConfig } from '../model';
1
+ import { FormFieldType, FormFieldGroupConfig } from '@case-framework/survey-items/form';
2
2
  interface FormResponseFieldGroupsListProps {
3
3
  itemId: string;
4
4
  items: FormFieldGroupConfig[];
@@ -1,4 +1,4 @@
1
- import { FormFieldConfig } from '../model';
1
+ import { FormFieldConfig } from '@case-framework/survey-items/form';
2
2
  export declare function SimpleFormFieldEditor({ field, onSave, onCustomize, }: {
3
3
  field: FormFieldConfig;
4
4
  onSave: (nextField: FormFieldConfig) => void;
@@ -1,18 +1,9 @@
1
1
  import { SurveyEditor as SurveyEditorCore } from '@case-framework/survey-core/editor';
2
2
  import { ComposedEditorItemRegistry } from '../registry';
3
- import { SurveyApplyResult, SurveyBatchApplyResult, SurveyChangeSet, SurveyDocumentVersion } from '@case-framework/survey-assistant/protocol';
4
- export interface SurveyAssistantEditorApplyResult extends SurveyApplyResult {
5
- editor?: SurveyEditorCore;
6
- }
3
+ import { SurveyBatchApplyResult, SurveyChangeSet, SurveyDocumentVersion } from '@case-framework/survey-assistant/protocol';
7
4
  export interface SurveyAssistantEditorBatchApplyResult extends SurveyBatchApplyResult {
8
5
  editor?: SurveyEditorCore;
9
6
  }
10
- interface ApplySurveyAssistantChangeInput {
11
- change: SurveyChangeSet;
12
- currentPrecondition: SurveyDocumentVersion;
13
- editor: SurveyEditorCore;
14
- itemRegistry: ComposedEditorItemRegistry;
15
- }
16
7
  interface ApplySurveyAssistantChangesInput {
17
8
  changes: SurveyChangeSet[];
18
9
  currentPrecondition: SurveyDocumentVersion;
@@ -25,5 +16,4 @@ export declare const resolveSelectedLocaleAfterAssistantApply: ({ availableLocal
25
16
  selectedLocale: string;
26
17
  }) => string;
27
18
  export declare const applySurveyAssistantChangesToEditor: ({ changes, currentPrecondition, editor, itemRegistry, }: ApplySurveyAssistantChangesInput) => SurveyAssistantEditorBatchApplyResult;
28
- export declare const applySurveyAssistantChangeToEditor: ({ change, currentPrecondition, editor, itemRegistry, }: ApplySurveyAssistantChangeInput) => SurveyAssistantEditorApplyResult;
29
19
  export {};
@@ -1,2 +1,2 @@
1
- export { applySurveyAssistantChangeToEditor, applySurveyAssistantChangesToEditor, resolveSelectedLocaleAfterAssistantApply, type SurveyAssistantEditorApplyResult, type SurveyAssistantEditorBatchApplyResult, } from './apply';
1
+ export { applySurveyAssistantChangesToEditor, resolveSelectedLocaleAfterAssistantApply, type SurveyAssistantEditorBatchApplyResult, } from './apply';
2
2
  export { buildSurveyAssistantItemRegistryManifest, buildSurveyAssistantSnapshot, type SurveyAssistantSnapshotOptions, type SurveyEditorAssistantController, } from './snapshot';
@@ -1,6 +1,6 @@
1
1
  import { SurveyEditor } from '@case-framework/survey-core/editor';
2
2
  import { SurveyEditorLocation } from '../navigation/types';
3
- import { SurveyApplyResult, SurveyAssistantItemRegistryManifest, SurveyAssistantSnapshot, SurveyBatchApplyResult, SurveyChangeSet } from '@case-framework/survey-assistant/protocol';
3
+ import { SurveyAssistantItemRegistryManifest, SurveyAssistantSnapshot, SurveyBatchApplyResult, SurveyChangeSet } from '@case-framework/survey-assistant/protocol';
4
4
  import { ComposedEditorItemRegistry } from '../registry';
5
5
  export interface SurveyAssistantSnapshotOptions {
6
6
  createdAt?: string;
@@ -18,7 +18,6 @@ export interface SurveyAssistantSnapshotOptions {
18
18
  }
19
19
  export interface SurveyEditorAssistantController {
20
20
  getSnapshot(options?: SurveyAssistantSnapshotOptions): SurveyAssistantSnapshot;
21
- applyAssistantChange(change: SurveyChangeSet): SurveyApplyResult;
22
21
  applyAssistantChanges(changes: SurveyChangeSet[]): SurveyBatchApplyResult;
23
22
  }
24
23
  interface BuildSurveyAssistantSnapshotInput {
@@ -0,0 +1,8 @@
1
+ type FocusTarget = Pick<HTMLElement, "focus">;
2
+ interface FocusWhenAvailableOptions {
3
+ maxAttempts?: number;
4
+ requestFrame?: (callback: FrameRequestCallback) => number;
5
+ cancelFrame?: (handle: number) => void;
6
+ }
7
+ export declare const focusWhenAvailable: (findTarget: () => FocusTarget | null | undefined, { maxAttempts, requestFrame, cancelFrame, }?: FocusWhenAvailableOptions) => (() => void);
8
+ export {};
@@ -0,0 +1,16 @@
1
+ import { SurveyItemClipboardData } from '@case-framework/survey-core/editor';
2
+ export type ItemClipboardShortcut = "copy" | "paste";
3
+ interface ItemClipboardShortcutEvent {
4
+ altKey: boolean;
5
+ ctrlKey: boolean;
6
+ defaultPrevented: boolean;
7
+ isComposing: boolean;
8
+ key: string;
9
+ metaKey: boolean;
10
+ repeat: boolean;
11
+ shiftKey: boolean;
12
+ }
13
+ export declare const hasActiveTextSelection: () => boolean;
14
+ export declare const parseSurveyItemClipboardValue: (value: string | null) => SurveyItemClipboardData | null;
15
+ export declare const resolveItemClipboardShortcut: (event: ItemClipboardShortcutEvent, textSelectionActive?: boolean) => ItemClipboardShortcut | null;
16
+ export {};
@@ -0,0 +1,10 @@
1
+ import { SurveyExpressionReferenceDiagnostic } from '@case-framework/survey-core';
2
+ export interface ExpressionDiagnosticsStatusModel {
3
+ advisoryGroups: Array<{
4
+ diagnostics: SurveyExpressionReferenceDiagnostic[];
5
+ kind: "display-dependency" | "general";
6
+ }>;
7
+ blockingDiagnostics: SurveyExpressionReferenceDiagnostic[];
8
+ repairPrompt?: string;
9
+ }
10
+ export declare const createExpressionDiagnosticsStatusModel: (diagnostics: SurveyExpressionReferenceDiagnostic[]) => ExpressionDiagnosticsStatusModel;
@@ -5,7 +5,7 @@ export declare const editorWorkspacePresets: {
5
5
  readonly left: {
6
6
  readonly id: "outline";
7
7
  readonly defaultOpen: true;
8
- readonly defaultSize: 240;
8
+ readonly defaultSize: 288;
9
9
  readonly minSize: 160;
10
10
  readonly maxSize: 720;
11
11
  };
@@ -13,7 +13,7 @@ export declare const editorWorkspacePresets: {
13
13
  readonly id: "assistant";
14
14
  readonly defaultOpen: false;
15
15
  readonly defaultOpenAtViewportWidth: 1280;
16
- readonly defaultSize: 360;
16
+ readonly defaultSize: 288;
17
17
  readonly minSize: 280;
18
18
  readonly maxSize: 520;
19
19
  readonly allowContentOverflow: true;
@@ -25,7 +25,7 @@ export declare const editorWorkspacePresets: {
25
25
  readonly left: {
26
26
  readonly id: "outline";
27
27
  readonly defaultOpen: true;
28
- readonly defaultSize: 240;
28
+ readonly defaultSize: 288;
29
29
  readonly minSize: 160;
30
30
  readonly maxSize: 720;
31
31
  };
@@ -33,7 +33,7 @@ export declare const editorWorkspacePresets: {
33
33
  readonly id: "assistant";
34
34
  readonly defaultOpen: false;
35
35
  readonly defaultOpenAtViewportWidth: 1280;
36
- readonly defaultSize: 360;
36
+ readonly defaultSize: 288;
37
37
  readonly minSize: 280;
38
38
  readonly maxSize: 520;
39
39
  readonly allowContentOverflow: true;
@@ -45,7 +45,7 @@ export declare const editorWorkspacePresets: {
45
45
  readonly left: {
46
46
  readonly id: "outline";
47
47
  readonly defaultOpen: true;
48
- readonly defaultSize: 240;
48
+ readonly defaultSize: 288;
49
49
  readonly minSize: 160;
50
50
  readonly maxSize: 720;
51
51
  };
@@ -53,7 +53,7 @@ export declare const editorWorkspacePresets: {
53
53
  readonly id: "assistant";
54
54
  readonly defaultOpen: false;
55
55
  readonly defaultOpenAtViewportWidth: 1280;
56
- readonly defaultSize: 360;
56
+ readonly defaultSize: 288;
57
57
  readonly minSize: 280;
58
58
  readonly maxSize: 520;
59
59
  readonly allowContentOverflow: true;
@@ -66,7 +66,7 @@ export declare const editorWorkspacePresets: {
66
66
  readonly id: "assistant";
67
67
  readonly defaultOpen: false;
68
68
  readonly defaultOpenAtViewportWidth: 1280;
69
- readonly defaultSize: 360;
69
+ readonly defaultSize: 288;
70
70
  readonly minSize: 280;
71
71
  readonly maxSize: 520;
72
72
  readonly allowContentOverflow: true;