@tutti-os/ui-rich-text 0.0.12 → 0.0.13

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.
@@ -0,0 +1,264 @@
1
+ // src/at-panel/searchHelpers.ts
2
+ var RICH_TEXT_AT_ALL_FILTER_ID = "all";
3
+ var DEFAULT_RICH_TEXT_AT_PANEL_PAGE_SIZE = 5;
4
+ function normalizeAtPanelQuery(value) {
5
+ return value.replace(/\s+/g, " ").trim();
6
+ }
7
+ function buildDefaultRichTextTriggerProviderGroups(input) {
8
+ return input.providers.map((provider) => ({
9
+ id: provider.id,
10
+ label: input.labels?.[provider.id] ?? provider.id,
11
+ providerIds: [provider.id],
12
+ filterId: provider.id
13
+ }));
14
+ }
15
+ function buildRichTextAtFilterTabs(input) {
16
+ const seen = /* @__PURE__ */ new Set([RICH_TEXT_AT_ALL_FILTER_ID]);
17
+ const tabs = [
18
+ {
19
+ id: RICH_TEXT_AT_ALL_FILTER_ID,
20
+ label: input.allLabel
21
+ }
22
+ ];
23
+ for (const group of input.groups) {
24
+ const filterId = group.filterId ?? group.id;
25
+ if (seen.has(filterId)) {
26
+ continue;
27
+ }
28
+ seen.add(filterId);
29
+ tabs.push({
30
+ id: filterId,
31
+ label: input.labels?.[filterId] ?? group.label
32
+ });
33
+ }
34
+ return tabs;
35
+ }
36
+ function filterGroupsForRichTextAtPanel(input) {
37
+ if (input.filterId === RICH_TEXT_AT_ALL_FILTER_ID) {
38
+ return input.groups;
39
+ }
40
+ return input.groups.filter(
41
+ (group) => (group.filterId ?? group.id) === input.filterId
42
+ );
43
+ }
44
+ function groupRichTextAtMatches(input) {
45
+ const visibleGroups = filterGroupsForRichTextAtPanel({
46
+ filterId: input.filterId,
47
+ groups: input.groups
48
+ });
49
+ const pageSize = input.pageSize ?? DEFAULT_RICH_TEXT_AT_PANEL_PAGE_SIZE;
50
+ return visibleGroups.map((group) => {
51
+ const providerIds = new Set(group.providerIds);
52
+ const items = input.matches.filter(
53
+ (match) => providerIds.has(match.providerId)
54
+ );
55
+ const groupPageSize = group.pageSize ?? pageSize;
56
+ const visibleCount = Math.min(
57
+ items.length,
58
+ input.expandedCounts?.[group.id] ?? groupPageSize
59
+ );
60
+ if (items.length === 0 && !group.emptyLabel) {
61
+ return null;
62
+ }
63
+ return {
64
+ id: group.id,
65
+ label: group.label,
66
+ items: items.slice(0, visibleCount),
67
+ totalCount: items.length,
68
+ visibleCount,
69
+ hasMore: items.length > visibleCount,
70
+ emptyLabel: group.emptyLabel
71
+ };
72
+ }).filter((group) => group !== null);
73
+ }
74
+ function richTextAtGroupExpandCount(group, pageSize = DEFAULT_RICH_TEXT_AT_PANEL_PAGE_SIZE) {
75
+ const remaining = Math.max(0, group.totalCount - group.visibleCount);
76
+ return Math.min(pageSize, remaining);
77
+ }
78
+ function findRichTextTriggerProviderGroup(groups, groupId) {
79
+ return groups.find((group) => group.id === groupId);
80
+ }
81
+
82
+ // src/at-panel/buildMentionPaletteState.ts
83
+ function buildMentionPaletteState(input) {
84
+ const searchGroups = groupRichTextAtMatches({
85
+ expandedCounts: input.expandedCounts,
86
+ filterId: input.activeFilterId,
87
+ groups: input.providerGroups,
88
+ matches: input.matches,
89
+ pageSize: input.pageSize
90
+ });
91
+ const groups = searchGroups.map((group) => ({
92
+ id: group.id,
93
+ label: input.shouldRenderGroupLabel != null && !input.shouldRenderGroupLabel(group.id, searchGroups.length) ? void 0 : group.label,
94
+ items: group.items,
95
+ totalCount: group.totalCount,
96
+ visibleCount: group.visibleCount,
97
+ hasMore: group.hasMore,
98
+ emptyLabel: group.emptyLabel,
99
+ expandLabel: group.hasMore && input.showMoreLabel != null ? input.showMoreLabel(group.totalCount - group.visibleCount) : void 0
100
+ }));
101
+ const categories = input.filterTabs;
102
+ const filter = input.activeFilterId;
103
+ const query = input.query;
104
+ const isEmptyQuery = query === "";
105
+ if (input.isLoading) {
106
+ return {
107
+ status: "loading",
108
+ query,
109
+ mode: isEmptyQuery ? "browse" : "results",
110
+ filter,
111
+ categories,
112
+ groups,
113
+ error: null
114
+ };
115
+ }
116
+ if (isEmptyQuery) {
117
+ return {
118
+ status: "idle",
119
+ query,
120
+ mode: "browse",
121
+ filter,
122
+ categories,
123
+ groups,
124
+ error: null
125
+ };
126
+ }
127
+ return {
128
+ status: "ready",
129
+ query,
130
+ mode: "results",
131
+ filter,
132
+ categories,
133
+ groups,
134
+ error: null
135
+ };
136
+ }
137
+
138
+ // src/at-panel/mentionPaletteEntries.ts
139
+ function hasInteractiveGroupEntries(groups) {
140
+ return groups.some((group) => group.items.length > 0 || group.hasMore);
141
+ }
142
+ function flattenMentionPaletteEntries(state, getItemKey) {
143
+ if (state.mode === "browse" && !hasInteractiveGroupEntries(state.groups)) {
144
+ return state.categories.map((category) => ({
145
+ key: `category:${category.id}`,
146
+ type: "category",
147
+ categoryId: category.id
148
+ }));
149
+ }
150
+ const entries = [];
151
+ for (const group of state.groups) {
152
+ group.items.forEach((item, index) => {
153
+ entries.push({
154
+ key: `${group.id}:${getItemKey(item, group.id)}`,
155
+ type: "item",
156
+ groupId: group.id,
157
+ itemIndex: index
158
+ });
159
+ });
160
+ if (group.hasMore) {
161
+ entries.push({
162
+ key: `expand:${group.id}`,
163
+ type: "expand",
164
+ groupId: group.id
165
+ });
166
+ }
167
+ }
168
+ return entries;
169
+ }
170
+
171
+ // src/at-panel/mentionStatusTone.ts
172
+ function activityMentionStatusBadgeClassName(tone) {
173
+ switch (tone) {
174
+ case "blue":
175
+ return "bg-sky-500/10 text-sky-700";
176
+ case "amber":
177
+ return "bg-[color:color-mix(in_srgb,var(--color-amber-500)_12%,transparent)] text-[var(--color-amber-500)]";
178
+ case "green":
179
+ return "bg-[var(--tsh-ui-pill-success-bg)] text-[var(--tsh-ui-pill-success-fg)]";
180
+ case "red":
181
+ return "bg-[var(--on-danger)] text-[var(--state-danger)]";
182
+ default:
183
+ return "bg-[var(--transparency-block)] text-[var(--text-secondary)]";
184
+ }
185
+ }
186
+ function issueMentionStatusBadgeClassName(tone) {
187
+ switch (tone) {
188
+ case "green":
189
+ return "bg-[color:color-mix(in_srgb,var(--state-success)_12%,transparent)] text-[var(--state-success)]";
190
+ case "red":
191
+ return "bg-[var(--on-danger)] text-[var(--state-danger)]";
192
+ default:
193
+ return "bg-[var(--transparency-block)] text-[var(--text-secondary)]";
194
+ }
195
+ }
196
+ function mentionStatusBadgeClassName(input) {
197
+ return input.variant === "issue" ? issueMentionStatusBadgeClassName(input.tone) : activityMentionStatusBadgeClassName(input.tone);
198
+ }
199
+ function activityMentionStatusTone(status) {
200
+ switch (status.trim().toLowerCase()) {
201
+ case "working":
202
+ return "blue";
203
+ case "waiting":
204
+ case "canceled":
205
+ return "amber";
206
+ case "completed":
207
+ case "idle":
208
+ return "green";
209
+ case "failed":
210
+ return "red";
211
+ default:
212
+ return "neutral";
213
+ }
214
+ }
215
+ function issueMentionStatusTone(status) {
216
+ switch (status.trim().toLowerCase()) {
217
+ case "completed":
218
+ return "green";
219
+ case "failed":
220
+ case "canceled":
221
+ return "red";
222
+ default:
223
+ return "neutral";
224
+ }
225
+ }
226
+
227
+ // src/at-panel/mentionFileVisualKind.ts
228
+ function resolveMentionFileVisualKind(input) {
229
+ if (input.mentionNavigation === "agent-generated-folder-back") {
230
+ return "back";
231
+ }
232
+ if (input.entryKind === "directory") {
233
+ return "folder";
234
+ }
235
+ return input.baseVisualKind;
236
+ }
237
+ function resolveMentionFileThumbnailUrl(input) {
238
+ if (input.visualKind !== "image") {
239
+ return void 0;
240
+ }
241
+ const thumbnailUrl = input.thumbnailUrl?.trim() ?? "";
242
+ return thumbnailUrl || void 0;
243
+ }
244
+
245
+ export {
246
+ RICH_TEXT_AT_ALL_FILTER_ID,
247
+ DEFAULT_RICH_TEXT_AT_PANEL_PAGE_SIZE,
248
+ normalizeAtPanelQuery,
249
+ buildDefaultRichTextTriggerProviderGroups,
250
+ buildRichTextAtFilterTabs,
251
+ groupRichTextAtMatches,
252
+ richTextAtGroupExpandCount,
253
+ findRichTextTriggerProviderGroup,
254
+ buildMentionPaletteState,
255
+ flattenMentionPaletteEntries,
256
+ activityMentionStatusBadgeClassName,
257
+ issueMentionStatusBadgeClassName,
258
+ mentionStatusBadgeClassName,
259
+ activityMentionStatusTone,
260
+ issueMentionStatusTone,
261
+ resolveMentionFileVisualKind,
262
+ resolveMentionFileThumbnailUrl
263
+ };
264
+ //# sourceMappingURL=chunk-E4PWFY3N.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/at-panel/searchHelpers.ts","../src/at-panel/buildMentionPaletteState.ts","../src/at-panel/mentionPaletteEntries.ts","../src/at-panel/mentionStatusTone.ts","../src/at-panel/mentionFileVisualKind.ts"],"sourcesContent":["import type { RichTextTriggerQueryMatch as RichTextAtQueryMatch } from \"../types/trigger.ts\";\nimport type {\n RichTextAtFilterId,\n RichTextAtFilterTab,\n RichTextAtGroupId,\n RichTextTriggerProviderGroup,\n RichTextAtSearchGroup\n} from \"./types.ts\";\n\nexport const RICH_TEXT_AT_ALL_FILTER_ID = \"all\";\nexport const DEFAULT_RICH_TEXT_AT_PANEL_PAGE_SIZE = 5;\n\nexport function normalizeAtPanelQuery(value: string): string {\n return value.replace(/\\s+/g, \" \").trim();\n}\n\nexport function buildDefaultRichTextTriggerProviderGroups(input: {\n providers: readonly { id: string }[];\n labels?: Readonly<Record<string, string>>;\n}): RichTextTriggerProviderGroup[] {\n return input.providers.map((provider) => ({\n id: provider.id,\n label: input.labels?.[provider.id] ?? provider.id,\n providerIds: [provider.id],\n filterId: provider.id\n }));\n}\n\nexport function buildRichTextAtFilterTabs(input: {\n allLabel: string;\n groups: readonly RichTextTriggerProviderGroup[];\n labels?: Readonly<Record<string, string>>;\n}): RichTextAtFilterTab[] {\n const seen = new Set<string>([RICH_TEXT_AT_ALL_FILTER_ID]);\n const tabs: RichTextAtFilterTab[] = [\n {\n id: RICH_TEXT_AT_ALL_FILTER_ID,\n label: input.allLabel\n }\n ];\n for (const group of input.groups) {\n const filterId = group.filterId ?? group.id;\n if (seen.has(filterId)) {\n continue;\n }\n seen.add(filterId);\n tabs.push({\n id: filterId,\n label: input.labels?.[filterId] ?? group.label\n });\n }\n return tabs;\n}\n\nexport function filterGroupsForRichTextAtPanel(input: {\n filterId: RichTextAtFilterId;\n groups: readonly RichTextTriggerProviderGroup[];\n}): readonly RichTextTriggerProviderGroup[] {\n if (input.filterId === RICH_TEXT_AT_ALL_FILTER_ID) {\n return input.groups;\n }\n return input.groups.filter(\n (group) => (group.filterId ?? group.id) === input.filterId\n );\n}\n\nexport function groupRichTextAtMatches(input: {\n expandedCounts?: Readonly<Record<string, number | undefined>>;\n filterId: RichTextAtFilterId;\n groups: readonly RichTextTriggerProviderGroup[];\n matches: readonly RichTextAtQueryMatch[];\n pageSize?: number;\n}): RichTextAtSearchGroup[] {\n const visibleGroups = filterGroupsForRichTextAtPanel({\n filterId: input.filterId,\n groups: input.groups\n });\n const pageSize = input.pageSize ?? DEFAULT_RICH_TEXT_AT_PANEL_PAGE_SIZE;\n return visibleGroups\n .map<RichTextAtSearchGroup | null>((group) => {\n const providerIds = new Set(group.providerIds);\n const items = input.matches.filter((match) =>\n providerIds.has(match.providerId)\n );\n const groupPageSize = group.pageSize ?? pageSize;\n const visibleCount = Math.min(\n items.length,\n input.expandedCounts?.[group.id] ?? groupPageSize\n );\n if (items.length === 0 && !group.emptyLabel) {\n return null;\n }\n return {\n id: group.id,\n label: group.label,\n items: items.slice(0, visibleCount),\n totalCount: items.length,\n visibleCount,\n hasMore: items.length > visibleCount,\n emptyLabel: group.emptyLabel\n } satisfies RichTextAtSearchGroup;\n })\n .filter((group): group is RichTextAtSearchGroup => group !== null);\n}\n\nexport function richTextAtGroupExpandCount(\n group: RichTextAtSearchGroup,\n pageSize = DEFAULT_RICH_TEXT_AT_PANEL_PAGE_SIZE\n): number {\n const remaining = Math.max(0, group.totalCount - group.visibleCount);\n return Math.min(pageSize, remaining);\n}\n\nexport function findRichTextTriggerProviderGroup(\n groups: readonly RichTextTriggerProviderGroup[],\n groupId: RichTextAtGroupId\n): RichTextTriggerProviderGroup | undefined {\n return groups.find((group) => group.id === groupId);\n}\n","import type { RichTextTriggerQueryMatch as RichTextAtQueryMatch } from \"../types/trigger.ts\";\nimport type {\n MentionPaletteGroup,\n MentionPaletteState\n} from \"./mentionPaletteTypes.ts\";\nimport { groupRichTextAtMatches } from \"./searchHelpers.ts\";\nimport type { RichTextTriggerProviderGroup } from \"./types.ts\";\n\nexport function buildMentionPaletteState(input: {\n matches: readonly RichTextAtQueryMatch[];\n providerGroups: readonly RichTextTriggerProviderGroup[];\n filterTabs: readonly { id: string; label: string }[];\n activeFilterId: string;\n expandedCounts: Record<string, number | undefined>;\n query: string;\n isLoading: boolean;\n pageSize?: number;\n showMoreLabel?: (count: number) => string;\n /**\n * Optional predicate gating whether a group's header label is emitted. When\n * provided and it returns false, the group renders without a label (matching\n * the agent composer's conditional `shouldRenderMentionGroupLabel` rule, e.g.\n * hiding a single group's header when it just duplicates the active filter\n * tab). When omitted, the group label is always emitted (legacy behavior).\n */\n shouldRenderGroupLabel?: (groupId: string, groupCount: number) => boolean;\n}): MentionPaletteState<RichTextAtQueryMatch> {\n const searchGroups = groupRichTextAtMatches({\n expandedCounts: input.expandedCounts,\n filterId: input.activeFilterId,\n groups: input.providerGroups,\n matches: input.matches,\n pageSize: input.pageSize\n });\n\n const groups: readonly MentionPaletteGroup<RichTextAtQueryMatch>[] =\n searchGroups.map((group) => ({\n id: group.id,\n label:\n input.shouldRenderGroupLabel != null &&\n !input.shouldRenderGroupLabel(group.id, searchGroups.length)\n ? undefined\n : group.label,\n items: group.items,\n totalCount: group.totalCount,\n visibleCount: group.visibleCount,\n hasMore: group.hasMore,\n emptyLabel: group.emptyLabel,\n expandLabel:\n group.hasMore && input.showMoreLabel != null\n ? input.showMoreLabel(group.totalCount - group.visibleCount)\n : undefined\n }));\n\n const categories = input.filterTabs;\n const filter = input.activeFilterId;\n const query = input.query;\n const isEmptyQuery = query === \"\";\n\n if (input.isLoading) {\n return {\n status: \"loading\",\n query,\n mode: isEmptyQuery ? \"browse\" : \"results\",\n filter,\n categories,\n groups,\n error: null\n };\n }\n\n if (isEmptyQuery) {\n return {\n status: \"idle\",\n query,\n mode: \"browse\",\n filter,\n categories,\n groups,\n error: null\n };\n }\n\n return {\n status: \"ready\",\n query,\n mode: \"results\",\n filter,\n categories,\n groups,\n error: null\n };\n}\n","import type {\n MentionPaletteEntry,\n MentionPaletteState\n} from \"./mentionPaletteTypes.ts\";\n\n/**\n * Returns true when at least one group has items or a \"load more\" trigger,\n * i.e. there is something interactive to render beyond category headers.\n */\nfunction hasInteractiveGroupEntries<TItem>(\n groups: MentionPaletteState<TItem>[\"groups\"]\n): boolean {\n return groups.some((group) => group.items.length > 0 || group.hasMore);\n}\n\n/**\n * Flatten the palette state into a stable, ordered list of navigable entries.\n *\n * Mirrors the ordering and key format of `flattenAgentMentionPaletteEntries`\n * from AgentFileMentionPalette.tsx, but is generic over item type.\n *\n * Key formats:\n * category entry → `category:<categoryId>`\n * item entry → `<groupId>:<getItemKey(item, groupId)>`\n * expand entry → `expand:<groupId>`\n */\nexport function flattenMentionPaletteEntries<TItem>(\n state: MentionPaletteState<TItem>,\n getItemKey: (item: TItem, groupId: string) => string\n): MentionPaletteEntry[] {\n // Browse mode with no interactive group content → show category nav only\n if (state.mode === \"browse\" && !hasInteractiveGroupEntries(state.groups)) {\n return state.categories.map((category) => ({\n key: `category:${category.id}`,\n type: \"category\" as const,\n categoryId: category.id\n }));\n }\n\n const entries: MentionPaletteEntry[] = [];\n\n for (const group of state.groups) {\n group.items.forEach((item, index) => {\n entries.push({\n key: `${group.id}:${getItemKey(item, group.id)}`,\n type: \"item\",\n groupId: group.id,\n itemIndex: index\n });\n });\n\n if (group.hasMore) {\n entries.push({\n key: `expand:${group.id}`,\n type: \"expand\",\n groupId: group.id\n });\n }\n }\n\n return entries;\n}\n","/**\n * Tone → className maps for the {@link MentionStatusBadge} rendered inside a\n * {@link MentionRow}. The surface resolves a status into a data-only\n * {@link MentionRowStatusTag} (label + tone + variant); this module owns the\n * presentational mapping so the styling stays in one place and identical across\n * surfaces.\n */\nexport type MentionRowStatusTone =\n | \"amber\"\n | \"blue\"\n | \"green\"\n | \"neutral\"\n | \"red\";\n\nexport type MentionRowStatusVariant = \"activity\" | \"issue\";\n\n/**\n * Background/text classes for the agent activity status badge. Ported verbatim\n * from the agent's `mentionStatusBadgeClassName` so the rendered DOM is\n * unchanged.\n */\nexport function activityMentionStatusBadgeClassName(\n tone: MentionRowStatusTone\n): string {\n switch (tone) {\n case \"blue\":\n return \"bg-sky-500/10 text-sky-700\";\n case \"amber\":\n return \"bg-[color:color-mix(in_srgb,var(--color-amber-500)_12%,transparent)] text-[var(--color-amber-500)]\";\n case \"green\":\n return \"bg-[var(--tsh-ui-pill-success-bg)] text-[var(--tsh-ui-pill-success-fg)]\";\n case \"red\":\n return \"bg-[var(--on-danger)] text-[var(--state-danger)]\";\n default:\n return \"bg-[var(--transparency-block)] text-[var(--text-secondary)]\";\n }\n}\n\n/**\n * Background/text classes for the issue status badge. Ported verbatim from the\n * agent's `issueMentionStatusBadgeClassName` (keyed by the issue tone the\n * surface resolves).\n */\nexport function issueMentionStatusBadgeClassName(\n tone: MentionRowStatusTone\n): string {\n switch (tone) {\n case \"green\":\n return \"bg-[color:color-mix(in_srgb,var(--state-success)_12%,transparent)] text-[var(--state-success)]\";\n case \"red\":\n return \"bg-[var(--on-danger)] text-[var(--state-danger)]\";\n default:\n return \"bg-[var(--transparency-block)] text-[var(--text-secondary)]\";\n }\n}\n\nexport function mentionStatusBadgeClassName(input: {\n tone: MentionRowStatusTone;\n variant: MentionRowStatusVariant;\n}): string {\n return input.variant === \"issue\"\n ? issueMentionStatusBadgeClassName(input.tone)\n : activityMentionStatusBadgeClassName(input.tone);\n}\n\n/**\n * Map a normalized agent-activity display status to its badge tone. Shared by\n * every `@`-mention surface that renders a session row (agent composer,\n * issue-manager) so the activity status badge color is identical across\n * surfaces. Mirrors the agent composer's local `mentionStatusTone` mapping\n * verbatim (the agent keeps its own copy producing identical values). The label\n * is resolved by each surface; only the tone lives here.\n */\nexport function activityMentionStatusTone(\n status: string\n): MentionRowStatusTone {\n switch (status.trim().toLowerCase()) {\n case \"working\":\n return \"blue\";\n case \"waiting\":\n case \"canceled\":\n return \"amber\";\n case \"completed\":\n case \"idle\":\n return \"green\";\n case \"failed\":\n return \"red\";\n default:\n return \"neutral\";\n }\n}\n\n/**\n * Map an issue status string to its badge tone. Shared by every `@`-mention\n * surface that renders an issue row (agent composer, issue-manager) so the\n * status badge color is identical across surfaces. The label is resolved by\n * each surface's own i18n; only the tone lives here.\n */\nexport function issueMentionStatusTone(status: string): MentionRowStatusTone {\n switch (status.trim().toLowerCase()) {\n case \"completed\":\n return \"green\";\n case \"failed\":\n case \"canceled\":\n return \"red\";\n default:\n return \"neutral\";\n }\n}\n","/**\n * Pure, dependency-free file visual-kind helpers shared by every `@`-mention\n * surface that renders a {@link MentionRow}. The *base* extension → kind\n * resolution lives in each surface (the agent maps file-manager kinds, etc.);\n * this module owns only the surface-agnostic vocabulary and the thumbnail rule\n * so the shared row renderer never imports a workspace feature.\n */\nexport type MentionFileVisualKind =\n | \"back\"\n | \"document\"\n | \"code\"\n | \"markdown\"\n | \"image\"\n | \"video\"\n | \"folder\";\n\nexport interface MentionFileVisualKindInput {\n entryKind?: string | null;\n mentionNavigation?: string | null;\n /**\n * The base visual kind already resolved from the file extension/name by the\n * surface (e.g. the agent's file-manager mapping). Used as the fallback when\n * the entry is neither a back-navigation marker nor a directory.\n */\n baseVisualKind: MentionFileVisualKind;\n}\n\n/**\n * Resolve the row's visual kind from a pre-resolved {@link MentionFileVisualKindInput.baseVisualKind}\n * plus the structural markers (back navigation, directory) that override it.\n */\nexport function resolveMentionFileVisualKind(\n input: MentionFileVisualKindInput\n): MentionFileVisualKind {\n if (input.mentionNavigation === \"agent-generated-folder-back\") {\n return \"back\";\n }\n if (input.entryKind === \"directory\") {\n return \"folder\";\n }\n return input.baseVisualKind;\n}\n\n/**\n * The thumbnail is only shown for image entries with a non-empty thumbnail URL.\n */\nexport function resolveMentionFileThumbnailUrl(input: {\n visualKind: MentionFileVisualKind;\n thumbnailUrl?: string | null;\n}): string | undefined {\n if (input.visualKind !== \"image\") {\n return undefined;\n }\n const thumbnailUrl = input.thumbnailUrl?.trim() ?? \"\";\n return thumbnailUrl || undefined;\n}\n"],"mappings":"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","names":[]}
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  createRichTextLinkMarkdown,
3
3
  createRichTextMentionMarkdown
4
- } from "./chunk-52PIIFZA.js";
4
+ } from "./chunk-QOVFZUZN.js";
5
5
 
6
6
  // src/plugins/mention.ts
7
7
  var richTextMentionTrigger = "@";
@@ -9,22 +9,52 @@ function normalizeOptionalString(value) {
9
9
  const trimmed = value?.trim();
10
10
  return trimmed ? trimmed : void 0;
11
11
  }
12
- function normalizeMentionMeta(meta) {
13
- if (!meta) {
12
+ function normalizeMentionLabel(value) {
13
+ return value.trim().replace(/^@+/, "").trim();
14
+ }
15
+ function normalizeStringRecord(values) {
16
+ if (!values) {
14
17
  return void 0;
15
18
  }
16
- const nextEntries = Object.entries(meta).map(([key, value]) => [key.trim(), value.trim()]).filter(([key, value]) => key.length > 0 && value.length > 0);
19
+ const nextEntries = Object.entries(values).map(([key, value]) => [key.trim(), value.trim()]).filter(([key, value]) => key.length > 0 && value.length > 0);
17
20
  if (nextEntries.length === 0) {
18
21
  return void 0;
19
22
  }
20
23
  return Object.freeze(Object.fromEntries(nextEntries));
21
24
  }
22
- function createRichTextMentionAttrs(pluginId, mention) {
23
- const plugin = pluginId.trim();
25
+ function normalizeMentionPresentation(presentation) {
26
+ if (!presentation) {
27
+ return void 0;
28
+ }
29
+ const normalized = {};
30
+ const iconUrl = normalizeOptionalString(presentation.iconUrl);
31
+ const thumbnailUrl = normalizeOptionalString(presentation.thumbnailUrl);
32
+ const subtitle = normalizeOptionalString(presentation.subtitle);
33
+ const description = normalizeOptionalString(presentation.description);
34
+ const status = normalizeOptionalString(presentation.status);
35
+ if (iconUrl) {
36
+ normalized.iconUrl = iconUrl;
37
+ }
38
+ if (thumbnailUrl) {
39
+ normalized.thumbnailUrl = thumbnailUrl;
40
+ }
41
+ if (subtitle) {
42
+ normalized.subtitle = subtitle;
43
+ }
44
+ if (description) {
45
+ normalized.description = description;
46
+ }
47
+ if (status) {
48
+ normalized.status = status;
49
+ }
50
+ return Object.keys(normalized).length > 0 ? Object.freeze(normalized) : void 0;
51
+ }
52
+ function createRichTextMentionAttrs(providerId, mention) {
53
+ const normalizedProviderId = providerId.trim();
24
54
  const entityId = mention.entityId.trim();
25
- const label = mention.label.trim();
26
- if (!plugin) {
27
- throw new Error("Rich text mention plugin id is required.");
55
+ const label = normalizeMentionLabel(mention.label);
56
+ if (!normalizedProviderId) {
57
+ throw new Error("Rich text mention provider id is required.");
28
58
  }
29
59
  if (!entityId) {
30
60
  throw new Error("Rich text mention entityId is required.");
@@ -32,37 +62,44 @@ function createRichTextMentionAttrs(pluginId, mention) {
32
62
  if (!label) {
33
63
  throw new Error("Rich text mention label is required.");
34
64
  }
35
- return {
65
+ const attrs = {
36
66
  trigger: richTextMentionTrigger,
37
- plugin,
67
+ providerId: normalizedProviderId,
38
68
  entityId,
39
- label,
40
- href: normalizeOptionalString(mention.href),
41
- kind: normalizeOptionalString(mention.kind),
42
- version: normalizeOptionalString(mention.version),
43
- meta: normalizeMentionMeta(mention.meta)
69
+ label
44
70
  };
71
+ const scope = normalizeStringRecord(mention.scope);
72
+ const presentation = normalizeMentionPresentation(mention.presentation);
73
+ if (scope) {
74
+ attrs.scope = scope;
75
+ }
76
+ if (presentation) {
77
+ attrs.presentation = presentation;
78
+ }
79
+ return attrs;
45
80
  }
46
81
  function isRichTextMentionAttrs(value) {
47
82
  if (!value || typeof value !== "object") {
48
83
  return false;
49
84
  }
50
85
  const candidate = value;
51
- return candidate.trigger === richTextMentionTrigger && typeof candidate.plugin === "string" && candidate.plugin.trim().length > 0 && typeof candidate.entityId === "string" && candidate.entityId.trim().length > 0 && typeof candidate.label === "string" && candidate.label.trim().length > 0;
86
+ return candidate.trigger === richTextMentionTrigger && typeof candidate.providerId === "string" && candidate.providerId.trim().length > 0 && typeof candidate.entityId === "string" && candidate.entityId.trim().length > 0 && typeof candidate.label === "string" && candidate.label.trim().length > 0;
52
87
  }
53
88
  function getRichTextMentionDisplayText(attrs) {
54
- return `@${attrs.label}`;
89
+ const label = normalizeMentionLabel(attrs.label);
90
+ return label ? `@${label}` : "";
55
91
  }
56
92
  function resolveRichTextMentionView(mention, resolved) {
57
93
  const state = resolved?.state ?? "active";
58
- const label = resolved?.label?.trim() || mention.label;
59
- const href = normalizeOptionalString(resolved?.href);
94
+ const label = normalizeMentionLabel(resolved?.label ?? mention.label);
60
95
  const tooltip = normalizeOptionalString(resolved?.tooltip);
61
96
  return {
62
97
  state,
63
98
  label,
64
99
  tooltip,
65
- href,
100
+ presentation: normalizeMentionPresentation(
101
+ resolved?.presentation ?? mention.presentation
102
+ ),
66
103
  entity: resolved?.entity,
67
104
  interactive: state === "active"
68
105
  };
@@ -79,8 +116,7 @@ function createRichTextMentionPlugin(plugin) {
79
116
  };
80
117
  }
81
118
 
82
- // src/plugins/at.ts
83
- var richTextAtTrigger = "@";
119
+ // src/plugins/trigger.ts
84
120
  function normalizeRequiredString(value, fieldName) {
85
121
  const trimmed = value.trim();
86
122
  if (!trimmed) {
@@ -107,7 +143,7 @@ function createRichTextMentionInsertResult(mention) {
107
143
  mention
108
144
  };
109
145
  }
110
- function renderRichTextAtInsertResult(providerId, result) {
146
+ function renderRichTextTriggerInsertResult(providerId, result) {
111
147
  switch (result.kind) {
112
148
  case "mention":
113
149
  return createRichTextMentionMarkdown(
@@ -125,37 +161,74 @@ function renderRichTextAtInsertResult(providerId, result) {
125
161
  return "";
126
162
  }
127
163
  }
128
- function createRichTextAtProvider(provider) {
164
+ function createRichTextTriggerProvider(provider) {
129
165
  const id = normalizeRequiredString(provider.id, "provider id");
130
166
  return {
131
167
  ...provider,
132
- id,
133
- trigger: richTextAtTrigger
168
+ id
134
169
  };
135
170
  }
136
171
 
137
- // src/plugins/atRegistry.ts
172
+ // src/plugins/triggerRegistry.ts
138
173
  function normalizeProviderId(providerId) {
139
174
  return providerId.trim();
140
175
  }
141
- function createRichTextAtRegistry(providers) {
176
+ function normalizeProviderTrigger(provider) {
177
+ return provider.trigger;
178
+ }
179
+ function normalizeProviderBoundary(provider) {
180
+ return provider.boundary ?? "punctuation";
181
+ }
182
+ function normalizeProviderTriggerConfig(provider) {
183
+ return {
184
+ trigger: normalizeProviderTrigger(provider),
185
+ boundary: normalizeProviderBoundary(provider)
186
+ };
187
+ }
188
+ function normalizeOptionalThumbnailUrl(value) {
189
+ const trimmed = value?.trim();
190
+ return trimmed ? trimmed : void 0;
191
+ }
192
+ async function resolveItemThumbnailUrl(provider, item) {
193
+ if (!provider.getItemThumbnailUrl) {
194
+ return void 0;
195
+ }
196
+ try {
197
+ return normalizeOptionalThumbnailUrl(
198
+ await Promise.resolve(provider.getItemThumbnailUrl(item))
199
+ );
200
+ } catch {
201
+ return void 0;
202
+ }
203
+ }
204
+ function createRichTextTriggerRegistry(providers) {
142
205
  const providerMap = /* @__PURE__ */ new Map();
206
+ const triggerConfigKeys = /* @__PURE__ */ new Set();
207
+ const triggerConfigs = [];
143
208
  for (const provider of providers) {
144
209
  const providerId = normalizeProviderId(provider.id);
145
210
  if (!providerId) {
146
- throw new Error("Rich text @ provider id is required.");
211
+ throw new Error("Rich text trigger provider id is required.");
147
212
  }
148
213
  if (providerMap.has(providerId)) {
149
- throw new Error(`Duplicate rich text @ provider id: ${providerId}`);
214
+ throw new Error(`Duplicate rich text trigger provider id: ${providerId}`);
150
215
  }
151
216
  providerMap.set(providerId, provider);
217
+ const triggerConfig = normalizeProviderTriggerConfig(provider);
218
+ const triggerConfigKey = `${triggerConfig.trigger}:${triggerConfig.boundary}`;
219
+ if (!triggerConfigKeys.has(triggerConfigKey)) {
220
+ triggerConfigKeys.add(triggerConfigKey);
221
+ triggerConfigs.push(triggerConfig);
222
+ }
152
223
  }
153
224
  async function query(input) {
154
225
  if (input.abortSignal?.aborted) {
155
226
  return [];
156
227
  }
157
228
  const matches = await Promise.all(
158
- [...providerMap.values()].map(async (provider) => {
229
+ [...providerMap.values()].filter(
230
+ (provider) => normalizeProviderTrigger(provider) === input.trigger
231
+ ).map(async (provider) => {
159
232
  if (input.abortSignal?.aborted) {
160
233
  return [];
161
234
  }
@@ -163,15 +236,19 @@ function createRichTextAtRegistry(providers) {
163
236
  if (input.abortSignal?.aborted) {
164
237
  return [];
165
238
  }
166
- return items.map((item) => ({
167
- providerId: provider.id,
168
- key: provider.getItemKey(item),
169
- label: provider.getItemLabel(item),
170
- subtitle: provider.getItemSubtitle?.(item) || void 0,
171
- keywords: provider.getItemKeywords?.(item),
172
- item,
173
- insertResult: provider.toInsertResult(item)
174
- }));
239
+ return Promise.all(
240
+ items.map(async (item) => ({
241
+ providerId: provider.id,
242
+ trigger: input.trigger,
243
+ key: provider.getItemKey(item),
244
+ label: provider.getItemLabel(item),
245
+ subtitle: provider.getItemSubtitle?.(item) || void 0,
246
+ thumbnailUrl: await resolveItemThumbnailUrl(provider, item),
247
+ keywords: provider.getItemKeywords?.(item),
248
+ item,
249
+ insertResult: provider.toInsertResult(item)
250
+ }))
251
+ );
175
252
  })
176
253
  );
177
254
  const flatMatches = matches.flat();
@@ -184,6 +261,7 @@ function createRichTextAtRegistry(providers) {
184
261
  return {
185
262
  listProviders: () => [...providerMap.values()],
186
263
  getProvider: (providerId) => providerMap.get(normalizeProviderId(providerId)),
264
+ listTriggerConfigs: () => [...triggerConfigs],
187
265
  query
188
266
  };
189
267
  }
@@ -227,7 +305,7 @@ function createRichTextMentionRegistry(plugins) {
227
305
  return flatMatches;
228
306
  }
229
307
  async function resolve(input) {
230
- const plugin = pluginMap.get(input.mention.plugin);
308
+ const plugin = pluginMap.get(input.mention.providerId);
231
309
  if (!plugin) {
232
310
  return resolveRichTextMentionView(input.mention, {
233
311
  state: "missing"
@@ -260,9 +338,9 @@ export {
260
338
  createRichTextTextInsertResult,
261
339
  createRichTextMarkdownLinkInsertResult,
262
340
  createRichTextMentionInsertResult,
263
- renderRichTextAtInsertResult,
264
- createRichTextAtProvider,
265
- createRichTextAtRegistry,
341
+ renderRichTextTriggerInsertResult,
342
+ createRichTextTriggerProvider,
343
+ createRichTextTriggerRegistry,
266
344
  createRichTextMentionRegistry
267
345
  };
268
- //# sourceMappingURL=chunk-K5POY2YJ.js.map
346
+ //# sourceMappingURL=chunk-QK6NMNYN.js.map
@@ -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 const iconUrl = normalizeOptionalString(presentation.iconUrl);\n const thumbnailUrl = normalizeOptionalString(presentation.thumbnailUrl);\n const subtitle = normalizeOptionalString(presentation.subtitle);\n const description = normalizeOptionalString(presentation.description);\n const status = normalizeOptionalString(presentation.status);\n\n if (iconUrl) {\n normalized.iconUrl = iconUrl;\n }\n if (thumbnailUrl) {\n normalized.thumbnailUrl = thumbnailUrl;\n }\n if (subtitle) {\n normalized.subtitle = subtitle;\n }\n if (description) {\n normalized.description = description;\n }\n if (status) {\n normalized.status = status;\n }\n\n return Object.keys(normalized).length > 0\n ? Object.freeze(normalized)\n : undefined;\n}\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 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 normalizeOptionalThumbnailUrl(\n value: string | null | undefined\n): string | undefined {\n const trimmed = value?.trim();\n return trimmed ? trimmed : undefined;\n}\n\nasync function resolveItemThumbnailUrl<TItem>(\n provider: RichTextTriggerProvider<TItem>,\n item: TItem\n): Promise<string | undefined> {\n if (!provider.getItemThumbnailUrl) {\n return undefined;\n }\n try {\n return normalizeOptionalThumbnailUrl(\n await Promise.resolve(provider.getItemThumbnailUrl(item))\n );\n } catch {\n return undefined;\n }\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 providerId: provider.id,\n trigger: input.trigger,\n key: provider.getItemKey(item),\n label: provider.getItemLabel(item),\n subtitle: provider.getItemSubtitle?.(item) || undefined,\n thumbnailUrl: await resolveItemThumbnailUrl(provider, item),\n keywords: provider.getItemKeywords?.(item),\n item,\n insertResult: provider.toInsertResult(item)\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":[]}