@tutti-os/ui-rich-text 0.0.13 → 0.0.15
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/README.md +1 -1
- package/dist/at-panel/index.d.ts +7 -0
- package/dist/at-panel/index.js +63 -14
- package/dist/at-panel/index.js.map +1 -1
- package/dist/{chunk-QK6NMNYN.js → chunk-YFXORJLD.js} +52 -40
- package/dist/chunk-YFXORJLD.js.map +1 -0
- package/dist/editor/index.d.ts +0 -5
- package/dist/editor/index.js +62 -104
- package/dist/editor/index.js.map +1 -1
- package/dist/plugins/index.js +1 -1
- package/dist/types/index.d.ts +2 -2
- package/package.json +4 -4
- package/dist/chunk-QK6NMNYN.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/plugins/mention.ts","../src/plugins/trigger.ts","../src/plugins/triggerRegistry.ts","../src/plugins/mentionRegistry.ts"],"sourcesContent":["import type {\n RichTextMentionAttrs,\n RichTextMentionInsert,\n RichTextMentionPresentation,\n RichTextMentionPlugin,\n RichTextResolvedMention,\n RichTextResolvedMentionView\n} from \"../types/mention.ts\";\n\nconst richTextMentionTrigger = \"@\";\n\nfunction normalizeOptionalString(value?: string | null): string | undefined {\n const trimmed = value?.trim();\n return trimmed ? trimmed : undefined;\n}\n\nfunction normalizeMentionLabel(value: string): string {\n return value.trim().replace(/^@+/, \"\").trim();\n}\n\nfunction normalizeStringRecord(\n values?: Readonly<Record<string, string>> | null\n): Readonly<Record<string, string>> | undefined {\n if (!values) {\n return undefined;\n }\n\n const nextEntries = Object.entries(values)\n .map(([key, value]) => [key.trim(), value.trim()] as const)\n .filter(([key, value]) => key.length > 0 && value.length > 0);\n\n if (nextEntries.length === 0) {\n return undefined;\n }\n\n return Object.freeze(Object.fromEntries(nextEntries));\n}\n\nfunction normalizeMentionPresentation(\n presentation?: RichTextMentionPresentation | null\n): RichTextMentionPresentation | undefined {\n if (!presentation) {\n return undefined;\n }\n\n const normalized: RichTextMentionPresentation = {};\n for (const key of richTextMentionPresentationKeys) {\n const value = normalizeOptionalString(presentation[key]);\n if (value) {\n normalized[key] = value;\n }\n }\n\n return Object.keys(normalized).length > 0\n ? Object.freeze(normalized)\n : undefined;\n}\n\nconst richTextMentionPresentationKeys = [\n \"agentProviderId\",\n \"agentIconUrl\",\n \"iconUrl\",\n \"thumbnailUrl\",\n \"subtitle\",\n \"description\",\n \"participant\",\n \"status\",\n \"statusDataStatus\",\n \"statusLabel\",\n \"statusPulse\",\n \"userAvatarPlaceholderUrl\"\n] as const satisfies readonly (keyof RichTextMentionPresentation)[];\n\nexport function createRichTextMentionAttrs(\n providerId: string,\n mention: RichTextMentionInsert\n): RichTextMentionAttrs {\n const normalizedProviderId = providerId.trim();\n const entityId = mention.entityId.trim();\n const label = normalizeMentionLabel(mention.label);\n\n if (!normalizedProviderId) {\n throw new Error(\"Rich text mention provider id is required.\");\n }\n if (!entityId) {\n throw new Error(\"Rich text mention entityId is required.\");\n }\n if (!label) {\n throw new Error(\"Rich text mention label is required.\");\n }\n\n const attrs: RichTextMentionAttrs = {\n trigger: richTextMentionTrigger,\n providerId: normalizedProviderId,\n entityId,\n label\n };\n const scope = normalizeStringRecord(mention.scope);\n const presentation = normalizeMentionPresentation(mention.presentation);\n if (scope) {\n attrs.scope = scope;\n }\n if (presentation) {\n attrs.presentation = presentation;\n }\n return attrs;\n}\n\nexport function isRichTextMentionAttrs(\n value: unknown\n): value is RichTextMentionAttrs {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n\n const candidate = value as Partial<RichTextMentionAttrs>;\n return (\n candidate.trigger === richTextMentionTrigger &&\n typeof candidate.providerId === \"string\" &&\n candidate.providerId.trim().length > 0 &&\n typeof candidate.entityId === \"string\" &&\n candidate.entityId.trim().length > 0 &&\n typeof candidate.label === \"string\" &&\n candidate.label.trim().length > 0\n );\n}\n\nexport function getRichTextMentionDisplayText(\n attrs: RichTextMentionAttrs\n): string {\n const label = normalizeMentionLabel(attrs.label);\n return label ? `@${label}` : \"\";\n}\n\nexport function resolveRichTextMentionView(\n mention: RichTextMentionAttrs,\n resolved?: RichTextResolvedMention | null\n): RichTextResolvedMentionView {\n const state = resolved?.state ?? \"active\";\n const label = normalizeMentionLabel(resolved?.label ?? mention.label);\n const tooltip = normalizeOptionalString(resolved?.tooltip);\n\n return {\n state,\n label,\n tooltip,\n presentation: normalizeMentionPresentation(\n resolved?.presentation ?? mention.presentation\n ),\n entity: resolved?.entity,\n interactive: state === \"active\"\n };\n}\n\nexport function createRichTextMentionPlugin<TItem, TResolved = unknown>(\n plugin: RichTextMentionPlugin<TItem, TResolved>\n): RichTextMentionPlugin<TItem, TResolved> {\n const id = plugin.id.trim();\n if (!id) {\n throw new Error(\"Rich text mention plugin id is required.\");\n }\n\n return {\n ...plugin,\n id,\n trigger: richTextMentionTrigger\n };\n}\n","import { createRichTextMentionAttrs } from \"./mention.ts\";\nimport {\n createRichTextMentionMarkdown,\n createRichTextLinkMarkdown\n} from \"../core/richTextDocument.ts\";\nimport type {\n RichTextTriggerProvider,\n RichTextMarkdownLinkInsertResult,\n RichTextMentionTriggerInsertResult,\n RichTextTriggerInsertResult,\n RichTextTextInsertResult\n} from \"../types/trigger.ts\";\n\nfunction normalizeRequiredString(value: string, fieldName: string): string {\n const trimmed = value.trim();\n if (!trimmed) {\n throw new Error(`Rich text ${fieldName} is required.`);\n }\n return trimmed;\n}\n\nexport function createRichTextTextInsertResult(\n text: string\n): RichTextTextInsertResult {\n return {\n kind: \"text\",\n text\n };\n}\n\nexport function createRichTextMarkdownLinkInsertResult(\n label: string,\n href: string\n): RichTextMarkdownLinkInsertResult {\n return {\n kind: \"markdown-link\",\n label: normalizeRequiredString(label, \"insert label\"),\n href: normalizeRequiredString(href, \"insert href\")\n };\n}\n\nexport function createRichTextMentionInsertResult(\n mention: RichTextMentionTriggerInsertResult[\"mention\"]\n): RichTextMentionTriggerInsertResult {\n return {\n kind: \"mention\",\n mention\n };\n}\n\nexport function renderRichTextTriggerInsertResult(\n providerId: string,\n result: RichTextTriggerInsertResult\n): string {\n switch (result.kind) {\n case \"mention\":\n return createRichTextMentionMarkdown(\n createRichTextMentionAttrs(providerId, result.mention)\n );\n case \"markdown-link\":\n return createRichTextLinkMarkdown({\n name: result.label,\n path: result.href,\n kind: result.href.endsWith(\"/\") ? \"folder\" : \"file\"\n });\n case \"text\":\n return result.text;\n default:\n return \"\";\n }\n}\n\nexport function createRichTextTriggerProvider<TItem>(\n provider: RichTextTriggerProvider<TItem>\n): RichTextTriggerProvider<TItem> {\n const id = normalizeRequiredString(provider.id, \"provider id\");\n\n return {\n ...provider,\n id\n };\n}\n","import type {\n RichTextTrigger,\n RichTextTriggerBoundary,\n RichTextTriggerConfig,\n RichTextTriggerInsertResult,\n RichTextTriggerProvider,\n RichTextTriggerQueryInput,\n RichTextTriggerQueryMatch,\n RichTextTriggerRegistry\n} from \"../types/trigger.ts\";\n\nfunction normalizeProviderId(providerId: string): string {\n return providerId.trim();\n}\n\nfunction normalizeProviderTrigger(\n provider: RichTextTriggerProvider\n): RichTextTrigger {\n return provider.trigger;\n}\n\nfunction normalizeProviderBoundary(\n provider: RichTextTriggerProvider\n): RichTextTriggerBoundary {\n return provider.boundary ?? \"punctuation\";\n}\n\nfunction normalizeProviderTriggerConfig(\n provider: RichTextTriggerProvider\n): RichTextTriggerConfig {\n return {\n trigger: normalizeProviderTrigger(provider),\n boundary: normalizeProviderBoundary(provider)\n };\n}\n\nfunction normalizeOptionalIconUrl(\n value: string | null | undefined\n): string | undefined {\n const trimmed = value?.trim();\n return trimmed ? trimmed : undefined;\n}\n\nfunction resolveInsertResultIconUrl(\n insertResult: RichTextTriggerInsertResult\n): string | undefined {\n if (insertResult.kind !== \"mention\") {\n return undefined;\n }\n return normalizeOptionalIconUrl(insertResult.mention.presentation?.iconUrl);\n}\n\nasync function resolveItemIconUrl<TItem>(\n provider: RichTextTriggerProvider<TItem>,\n item: TItem,\n insertResult: RichTextTriggerInsertResult\n): Promise<string | undefined> {\n if (provider.getItemIconUrl) {\n try {\n const iconUrl = normalizeOptionalIconUrl(\n await Promise.resolve(provider.getItemIconUrl(item))\n );\n if (iconUrl) {\n return iconUrl;\n }\n } catch {\n return resolveInsertResultIconUrl(insertResult);\n }\n }\n return resolveInsertResultIconUrl(insertResult);\n}\n\nexport function createRichTextTriggerRegistry(\n providers: readonly RichTextTriggerProvider[]\n): RichTextTriggerRegistry {\n const providerMap = new Map<string, RichTextTriggerProvider>();\n const triggerConfigKeys = new Set<string>();\n const triggerConfigs: RichTextTriggerConfig[] = [];\n\n for (const provider of providers) {\n const providerId = normalizeProviderId(provider.id);\n if (!providerId) {\n throw new Error(\"Rich text trigger provider id is required.\");\n }\n if (providerMap.has(providerId)) {\n throw new Error(`Duplicate rich text trigger provider id: ${providerId}`);\n }\n providerMap.set(providerId, provider);\n const triggerConfig = normalizeProviderTriggerConfig(provider);\n const triggerConfigKey = `${triggerConfig.trigger}:${triggerConfig.boundary}`;\n if (!triggerConfigKeys.has(triggerConfigKey)) {\n triggerConfigKeys.add(triggerConfigKey);\n triggerConfigs.push(triggerConfig);\n }\n }\n\n async function query(\n input: RichTextTriggerQueryInput\n ): Promise<readonly RichTextTriggerQueryMatch[]> {\n if (input.abortSignal?.aborted) {\n return [];\n }\n\n const matches = await Promise.all(\n [...providerMap.values()]\n .filter(\n (provider) => normalizeProviderTrigger(provider) === input.trigger\n )\n .map(async (provider) => {\n if (input.abortSignal?.aborted) {\n return [];\n }\n const items = await provider.query(input);\n if (input.abortSignal?.aborted) {\n return [];\n }\n return Promise.all(\n items.map(async (item) => {\n const insertResult = provider.toInsertResult(item);\n return {\n providerId: provider.id,\n trigger: input.trigger,\n key: provider.getItemKey(item),\n label: provider.getItemLabel(item),\n subtitle: provider.getItemSubtitle?.(item) || undefined,\n iconUrl: await resolveItemIconUrl(provider, item, insertResult),\n keywords: provider.getItemKeywords?.(item),\n item,\n insertResult\n };\n })\n );\n })\n );\n\n const flatMatches = matches.flat();\n const limit = input.maxResults;\n if (typeof limit === \"number\" && limit >= 0) {\n return flatMatches.slice(0, limit);\n }\n return flatMatches;\n }\n\n return {\n listProviders: () => [...providerMap.values()],\n getProvider: (providerId: string) =>\n providerMap.get(normalizeProviderId(providerId)),\n listTriggerConfigs: () => [...triggerConfigs],\n query\n };\n}\n","import {\n createRichTextMentionAttrs,\n resolveRichTextMentionView\n} from \"./mention.ts\";\nimport type {\n RichTextMentionPlugin,\n RichTextMentionQueryInput,\n RichTextMentionQueryMatch,\n RichTextMentionRegistry,\n RichTextMentionResolveInput,\n RichTextResolvedMentionView\n} from \"../types/mention.ts\";\n\nfunction normalizePluginId(pluginId: string): string {\n return pluginId.trim();\n}\n\nexport function createRichTextMentionRegistry(\n plugins: readonly RichTextMentionPlugin[]\n): RichTextMentionRegistry {\n const pluginMap = new Map<string, RichTextMentionPlugin>();\n\n for (const plugin of plugins) {\n const pluginId = normalizePluginId(plugin.id);\n if (!pluginId) {\n throw new Error(\"Rich text mention plugin id is required.\");\n }\n if (pluginMap.has(pluginId)) {\n throw new Error(`Duplicate rich text mention plugin id: ${pluginId}`);\n }\n pluginMap.set(pluginId, plugin);\n }\n\n async function query(\n input: RichTextMentionQueryInput\n ): Promise<readonly RichTextMentionQueryMatch[]> {\n const matches = await Promise.all(\n [...pluginMap.values()].map(async (plugin) => {\n const items = await plugin.query(input);\n return items.map<RichTextMentionQueryMatch>((item) => ({\n pluginId: plugin.id,\n key: plugin.getItemKey(item),\n label: plugin.getItemLabel(item),\n subtitle: plugin.getItemSubtitle?.(item) || undefined,\n keywords: plugin.getItemKeywords?.(item),\n item,\n mention: createRichTextMentionAttrs(plugin.id, plugin.toMention(item))\n }));\n })\n );\n\n const flatMatches = matches.flat();\n const limit = input.maxResults;\n if (typeof limit === \"number\" && limit >= 0) {\n return flatMatches.slice(0, limit);\n }\n return flatMatches;\n }\n\n async function resolve(\n input: RichTextMentionResolveInput\n ): Promise<RichTextResolvedMentionView> {\n const plugin = pluginMap.get(input.mention.providerId);\n if (!plugin) {\n return resolveRichTextMentionView(input.mention, {\n state: \"missing\"\n });\n }\n\n if (!plugin.resolveMention) {\n return resolveRichTextMentionView(input.mention, {\n state: \"active\"\n });\n }\n\n return resolveRichTextMentionView(\n input.mention,\n await plugin.resolveMention(input)\n );\n }\n\n return {\n listPlugins: () => [...pluginMap.values()],\n getPlugin: (pluginId: string) => pluginMap.get(normalizePluginId(pluginId)),\n query,\n resolve\n };\n}\n"],"mappings":"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","names":[]}
|
package/dist/editor/index.d.ts
CHANGED
|
@@ -28,11 +28,6 @@ interface RichTextTriggerEditorProps {
|
|
|
28
28
|
focusSignal?: unknown;
|
|
29
29
|
menuZIndex?: string | number;
|
|
30
30
|
}
|
|
31
|
-
declare global {
|
|
32
|
-
interface Window {
|
|
33
|
-
__tuttiRichTextDebugLog?: (event: string, payload: unknown) => void;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
31
|
declare function RichTextTriggerEditor({ value, onChange, triggerProviders, placeholder, disabled, className, textareaClassName, placeholderClassName, minQueryLength, maxResults, removeDecorationAriaLabel, i18n, textOverrides, overlay, focusSignal, menuZIndex }: RichTextTriggerEditorProps): JSX.Element;
|
|
37
32
|
|
|
38
33
|
interface RichTextTriggerTextareaProps {
|
package/dist/editor/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
getRichTextMentionDisplayText,
|
|
8
8
|
renderRichTextTriggerInsertResult,
|
|
9
9
|
resolveRichTextMentionView
|
|
10
|
-
} from "../chunk-
|
|
10
|
+
} from "../chunk-YFXORJLD.js";
|
|
11
11
|
import {
|
|
12
12
|
findRichTextMarkdownLinks,
|
|
13
13
|
isRichTextMentionHref,
|
|
@@ -114,12 +114,14 @@ function resolveRichTextTriggerText(overrides, removeDecorationAriaLabel, i18n =
|
|
|
114
114
|
var defaultRichTextTriggerText = resolveRichTextTriggerText();
|
|
115
115
|
|
|
116
116
|
// src/editor/RichTextTriggerMenuItem.tsx
|
|
117
|
+
import { FileIcon, FolderFilledIcon } from "@tutti-os/ui-system/icons";
|
|
117
118
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
118
119
|
function RichTextTriggerMenuItem({
|
|
120
|
+
iconUrl,
|
|
119
121
|
label,
|
|
120
122
|
selected,
|
|
121
123
|
subtitle,
|
|
122
|
-
|
|
124
|
+
workspaceReferenceFileKind,
|
|
123
125
|
onSelect
|
|
124
126
|
}) {
|
|
125
127
|
return /* @__PURE__ */ jsxs(
|
|
@@ -137,7 +139,13 @@ function RichTextTriggerMenuItem({
|
|
|
137
139
|
onSelect();
|
|
138
140
|
},
|
|
139
141
|
children: [
|
|
140
|
-
/* @__PURE__ */ jsx(
|
|
142
|
+
/* @__PURE__ */ jsx(
|
|
143
|
+
RichTextTriggerMenuIcon,
|
|
144
|
+
{
|
|
145
|
+
iconUrl,
|
|
146
|
+
workspaceReferenceFileKind
|
|
147
|
+
}
|
|
148
|
+
),
|
|
141
149
|
/* @__PURE__ */ jsxs("span", { className: "flex min-w-0 flex-auto flex-col items-start gap-0.5", children: [
|
|
142
150
|
/* @__PURE__ */ jsx("span", { className: "w-full overflow-hidden text-ellipsis whitespace-nowrap text-[13px] leading-5 font-semibold", children: label }),
|
|
143
151
|
subtitle ? /* @__PURE__ */ jsx("span", { className: "w-full overflow-hidden text-ellipsis whitespace-nowrap text-[11px] leading-4 text-[var(--text-secondary)]", children: subtitle }) : null
|
|
@@ -146,17 +154,30 @@ function RichTextTriggerMenuItem({
|
|
|
146
154
|
}
|
|
147
155
|
);
|
|
148
156
|
}
|
|
149
|
-
function
|
|
150
|
-
|
|
157
|
+
function RichTextTriggerMenuIcon({
|
|
158
|
+
iconUrl,
|
|
159
|
+
workspaceReferenceFileKind
|
|
151
160
|
}) {
|
|
152
|
-
const
|
|
161
|
+
const normalizedIconUrl = iconUrl?.trim() ?? "";
|
|
162
|
+
if (workspaceReferenceFileKind) {
|
|
163
|
+
const Icon = workspaceReferenceFileKind === "folder" ? FolderFilledIcon : FileIcon;
|
|
164
|
+
return /* @__PURE__ */ jsx(
|
|
165
|
+
"span",
|
|
166
|
+
{
|
|
167
|
+
"aria-hidden": "true",
|
|
168
|
+
className: "inline-grid size-4 flex-none place-items-center text-[var(--folder)]",
|
|
169
|
+
"data-rich-text-trigger-icon": "true",
|
|
170
|
+
children: /* @__PURE__ */ jsx(Icon, { className: "size-4" })
|
|
171
|
+
}
|
|
172
|
+
);
|
|
173
|
+
}
|
|
153
174
|
return /* @__PURE__ */ jsx(
|
|
154
175
|
"span",
|
|
155
176
|
{
|
|
156
177
|
"aria-hidden": "true",
|
|
157
178
|
className: "inline-grid size-4 flex-none place-items-center overflow-hidden rounded bg-[var(--bg-block,var(--transparency-block))]",
|
|
158
|
-
"data-rich-text-trigger-
|
|
159
|
-
children:
|
|
179
|
+
"data-rich-text-trigger-icon": "true",
|
|
180
|
+
children: normalizedIconUrl ? /* @__PURE__ */ jsx(
|
|
160
181
|
"img",
|
|
161
182
|
{
|
|
162
183
|
alt: "",
|
|
@@ -164,7 +185,7 @@ function RichTextTriggerMenuThumbnail({
|
|
|
164
185
|
decoding: "async",
|
|
165
186
|
draggable: false,
|
|
166
187
|
loading: "lazy",
|
|
167
|
-
src:
|
|
188
|
+
src: normalizedIconUrl
|
|
168
189
|
}
|
|
169
190
|
) : /* @__PURE__ */ jsx("span", { className: "block size-3 rounded-[3px] bg-[var(--transparency-block)]" })
|
|
170
191
|
}
|
|
@@ -283,7 +304,10 @@ var MentionReference = Node.create({
|
|
|
283
304
|
];
|
|
284
305
|
},
|
|
285
306
|
addNodeView() {
|
|
286
|
-
return ReactNodeViewRenderer(MentionReferenceNodeView
|
|
307
|
+
return ReactNodeViewRenderer(MentionReferenceNodeView, {
|
|
308
|
+
as: "span",
|
|
309
|
+
className: "inline-flex max-w-full align-baseline"
|
|
310
|
+
});
|
|
287
311
|
}
|
|
288
312
|
});
|
|
289
313
|
|
|
@@ -397,7 +421,8 @@ function WorkspaceReferenceNodeView({
|
|
|
397
421
|
removable: isEditable,
|
|
398
422
|
removeButtonProps: isEditable ? {
|
|
399
423
|
"aria-label": removeActionAriaLabel,
|
|
400
|
-
|
|
424
|
+
onPointerDown: handleRemove,
|
|
425
|
+
tabIndex: -1
|
|
401
426
|
} : void 0
|
|
402
427
|
}
|
|
403
428
|
) }),
|
|
@@ -486,6 +511,20 @@ var WorkspaceReference = Node2.create({
|
|
|
486
511
|
|
|
487
512
|
// src/editor/RichTextTriggerEditor.tsx
|
|
488
513
|
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
514
|
+
var RICH_TEXT_MENTION_PRESENTATION_KEYS = [
|
|
515
|
+
"agentProviderId",
|
|
516
|
+
"agentIconUrl",
|
|
517
|
+
"iconUrl",
|
|
518
|
+
"thumbnailUrl",
|
|
519
|
+
"subtitle",
|
|
520
|
+
"description",
|
|
521
|
+
"participant",
|
|
522
|
+
"status",
|
|
523
|
+
"statusDataStatus",
|
|
524
|
+
"statusLabel",
|
|
525
|
+
"statusPulse",
|
|
526
|
+
"userAvatarPlaceholderUrl"
|
|
527
|
+
];
|
|
489
528
|
function RichTextTriggerEditor({
|
|
490
529
|
value,
|
|
491
530
|
onChange,
|
|
@@ -652,24 +691,10 @@ function RichTextTriggerEditor({
|
|
|
652
691
|
}
|
|
653
692
|
const updateQueryState = () => {
|
|
654
693
|
const nextQuery = findEditorAtQuery(editor, activeTriggerConfigs);
|
|
655
|
-
logRichTextTriggerDebug("query-state", {
|
|
656
|
-
activeTriggerConfigs,
|
|
657
|
-
focused: editor.isFocused,
|
|
658
|
-
query: nextQuery,
|
|
659
|
-
selection: {
|
|
660
|
-
empty: editor.state.selection.empty,
|
|
661
|
-
from: editor.state.selection.from,
|
|
662
|
-
to: editor.state.selection.to
|
|
663
|
-
},
|
|
664
|
-
textBeforeCursor: readEditorTextBeforeCursor(editor)
|
|
665
|
-
});
|
|
666
694
|
setQuery(nextQuery);
|
|
667
695
|
};
|
|
668
696
|
const updateFocus = () => {
|
|
669
697
|
const nextFocused = editor.isFocused;
|
|
670
|
-
logRichTextTriggerDebug("focus-state", {
|
|
671
|
-
focused: nextFocused
|
|
672
|
-
});
|
|
673
698
|
setIsFocused(nextFocused);
|
|
674
699
|
updateQueryState();
|
|
675
700
|
};
|
|
@@ -693,11 +718,6 @@ function RichTextTriggerEditor({
|
|
|
693
718
|
return;
|
|
694
719
|
}
|
|
695
720
|
if (query.keyword.length < minQueryLength) {
|
|
696
|
-
logRichTextTriggerDebug("query-skipped", {
|
|
697
|
-
minQueryLength,
|
|
698
|
-
query,
|
|
699
|
-
reason: "keyword-too-short"
|
|
700
|
-
});
|
|
701
721
|
setMatches([]);
|
|
702
722
|
setActiveIndex(0);
|
|
703
723
|
setIsLoading(false);
|
|
@@ -705,11 +725,6 @@ function RichTextTriggerEditor({
|
|
|
705
725
|
}
|
|
706
726
|
const abortController = new AbortController();
|
|
707
727
|
setIsLoading(true);
|
|
708
|
-
logRichTextTriggerDebug("query-start", {
|
|
709
|
-
maxResults,
|
|
710
|
-
minQueryLength,
|
|
711
|
-
query
|
|
712
|
-
});
|
|
713
728
|
void queryRichTextTriggerMatches(registry, {
|
|
714
729
|
abortSignal: abortController.signal,
|
|
715
730
|
keyword: query.keyword,
|
|
@@ -728,16 +743,6 @@ function RichTextTriggerEditor({
|
|
|
728
743
|
if (abortController.signal.aborted) {
|
|
729
744
|
return;
|
|
730
745
|
}
|
|
731
|
-
logRichTextTriggerDebug("query-result", {
|
|
732
|
-
matchCount: nextMatches.length,
|
|
733
|
-
matches: nextMatches.map((match) => ({
|
|
734
|
-
key: match.key,
|
|
735
|
-
label: match.label,
|
|
736
|
-
providerId: match.providerId,
|
|
737
|
-
trigger: match.trigger
|
|
738
|
-
})),
|
|
739
|
-
query
|
|
740
|
-
});
|
|
741
746
|
setMatches(nextMatches);
|
|
742
747
|
setActiveIndex(
|
|
743
748
|
(current) => nextMatches.length === 0 ? 0 : Math.max(0, Math.min(current, nextMatches.length - 1))
|
|
@@ -760,10 +765,6 @@ function RichTextTriggerEditor({
|
|
|
760
765
|
]);
|
|
761
766
|
useLayoutEffect(() => {
|
|
762
767
|
if (!editor || !query) {
|
|
763
|
-
logRichTextTriggerDebug("menu-point-cleared", {
|
|
764
|
-
hasEditor: Boolean(editor),
|
|
765
|
-
query
|
|
766
|
-
});
|
|
767
768
|
setMenuPoint(null);
|
|
768
769
|
return;
|
|
769
770
|
}
|
|
@@ -773,16 +774,6 @@ function RichTextTriggerEditor({
|
|
|
773
774
|
x: coords.left,
|
|
774
775
|
y: coords.bottom + menuOffset
|
|
775
776
|
};
|
|
776
|
-
logRichTextTriggerDebug("menu-point", {
|
|
777
|
-
coords: {
|
|
778
|
-
bottom: coords.bottom,
|
|
779
|
-
left: coords.left,
|
|
780
|
-
right: coords.right,
|
|
781
|
-
top: coords.top
|
|
782
|
-
},
|
|
783
|
-
menuPoint: nextMenuPoint,
|
|
784
|
-
query
|
|
785
|
-
});
|
|
786
777
|
setMenuPoint(nextMenuPoint);
|
|
787
778
|
};
|
|
788
779
|
updateMenuPoint();
|
|
@@ -799,27 +790,6 @@ function RichTextTriggerEditor({
|
|
|
799
790
|
const canQueryTrigger = !!query && activeTriggerConfigs.length > 0 && query.keyword.length >= minQueryLength;
|
|
800
791
|
const isMenuOpen = canQueryTrigger && (isFocused || !!menuPoint);
|
|
801
792
|
const isEmpty = !editor || serializeRichTextDocumentToContent(editor.getJSON()).trim().length === 0;
|
|
802
|
-
useEffect2(() => {
|
|
803
|
-
logRichTextTriggerDebug("menu-state", {
|
|
804
|
-
activeIndex,
|
|
805
|
-
canQueryTrigger,
|
|
806
|
-
isFocused,
|
|
807
|
-
isLoading,
|
|
808
|
-
isMenuOpen,
|
|
809
|
-
matchesLength: matches.length,
|
|
810
|
-
menuPoint,
|
|
811
|
-
query
|
|
812
|
-
});
|
|
813
|
-
}, [
|
|
814
|
-
activeIndex,
|
|
815
|
-
canQueryTrigger,
|
|
816
|
-
isFocused,
|
|
817
|
-
isLoading,
|
|
818
|
-
isMenuOpen,
|
|
819
|
-
matches.length,
|
|
820
|
-
menuPoint,
|
|
821
|
-
query
|
|
822
|
-
]);
|
|
823
793
|
const applyMatch = (match) => {
|
|
824
794
|
if (!editor || !query) {
|
|
825
795
|
return;
|
|
@@ -918,7 +888,10 @@ function RichTextTriggerEditor({
|
|
|
918
888
|
label: match.label,
|
|
919
889
|
selected: index === activeIndex,
|
|
920
890
|
subtitle: match.subtitle,
|
|
921
|
-
|
|
891
|
+
iconUrl: match.iconUrl,
|
|
892
|
+
workspaceReferenceFileKind: getWorkspaceReferenceFileKind(
|
|
893
|
+
match.insertResult
|
|
894
|
+
),
|
|
922
895
|
onSelect: () => applyMatch(match)
|
|
923
896
|
},
|
|
924
897
|
`${match.providerId}:${match.key}`
|
|
@@ -936,21 +909,6 @@ function findEditorAtQuery(editor, triggers) {
|
|
|
936
909
|
}
|
|
937
910
|
return query;
|
|
938
911
|
}
|
|
939
|
-
function readEditorTextBeforeCursor(editor) {
|
|
940
|
-
const { selection } = editor.state;
|
|
941
|
-
if (!selection.empty) {
|
|
942
|
-
return null;
|
|
943
|
-
}
|
|
944
|
-
const { $from } = selection;
|
|
945
|
-
if (!$from.parent.isTextblock) {
|
|
946
|
-
return null;
|
|
947
|
-
}
|
|
948
|
-
return $from.parent.textBetween(0, $from.parentOffset, "\n", "\uFFFC");
|
|
949
|
-
}
|
|
950
|
-
function logRichTextTriggerDebug(event, payload) {
|
|
951
|
-
console.info(`[tutti-rich-text-trigger] ${event}`, payload);
|
|
952
|
-
window.__tuttiRichTextDebugLog?.(event, payload);
|
|
953
|
-
}
|
|
954
912
|
function findEditorTriggerQuery(editor, triggers) {
|
|
955
913
|
const { selection } = editor.state;
|
|
956
914
|
if (!selection.empty) {
|
|
@@ -1006,6 +964,12 @@ function renderInsertResultAsEditorContent(providerId, result) {
|
|
|
1006
964
|
return null;
|
|
1007
965
|
}
|
|
1008
966
|
}
|
|
967
|
+
function getWorkspaceReferenceFileKind(result) {
|
|
968
|
+
if (result.kind !== "markdown-link") {
|
|
969
|
+
return void 0;
|
|
970
|
+
}
|
|
971
|
+
return result.href.endsWith("/") ? "folder" : "file";
|
|
972
|
+
}
|
|
1009
973
|
function collectHydratableMentionNodes(editor) {
|
|
1010
974
|
const mentions = [];
|
|
1011
975
|
editor.state.doc.descendants((node, pos) => {
|
|
@@ -1075,13 +1039,7 @@ function normalizeMentionPresentation(value) {
|
|
|
1075
1039
|
}
|
|
1076
1040
|
const source = value;
|
|
1077
1041
|
const next = {};
|
|
1078
|
-
for (const key of
|
|
1079
|
-
"iconUrl",
|
|
1080
|
-
"thumbnailUrl",
|
|
1081
|
-
"subtitle",
|
|
1082
|
-
"description",
|
|
1083
|
-
"status"
|
|
1084
|
-
]) {
|
|
1042
|
+
for (const key of RICH_TEXT_MENTION_PRESENTATION_KEYS) {
|
|
1085
1043
|
const fieldValue = source[key];
|
|
1086
1044
|
if (typeof fieldValue !== "string") {
|
|
1087
1045
|
continue;
|
|
@@ -1763,7 +1721,7 @@ function RichTextTriggerTextarea({
|
|
|
1763
1721
|
label: match.label,
|
|
1764
1722
|
selected: index === activeIndex,
|
|
1765
1723
|
subtitle: match.subtitle,
|
|
1766
|
-
|
|
1724
|
+
iconUrl: match.iconUrl,
|
|
1767
1725
|
onSelect: () => applyMatch(match)
|
|
1768
1726
|
},
|
|
1769
1727
|
`${match.providerId}:${match.key}`
|