@estiva-app/ui 0.51.0 → 0.53.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.
- package/dist/ComposerTriggers.d.ts +191 -0
- package/dist/ComposerTriggers.d.ts.map +1 -0
- package/dist/SuggestionMenu.d.ts.map +1 -1
- package/dist/editor.d.ts +1 -0
- package/dist/editor.d.ts.map +1 -1
- package/dist/editor.js +341 -13
- package/dist/editor.js.map +4 -4
- package/dist/index.js +7 -2
- package/dist/index.js.map +3 -3
- package/dist/suggestionPopup.d.ts +9 -0
- package/dist/suggestionPopup.d.ts.map +1 -1
- package/package.json +6 -1
- package/registry.json +326 -3
- package/src/ComposerTriggers.mdx +115 -0
- package/src/ComposerTriggers.stories.tsx +99 -0
- package/src/ComposerTriggers.test.tsx +268 -0
- package/src/ComposerTriggers.tsx +547 -0
- package/src/SuggestionMenu.tsx +13 -3
- package/src/editor.ts +29 -0
- package/src/registry/registry.test.ts +8 -7
- package/src/suggestionPopup.tsx +29 -1
- package/stories/Choosing.mdx +1 -0
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import { Extension, type Editor } from '@tiptap/core';
|
|
3
|
+
import { type MentionOptions } from '@tiptap/extension-mention';
|
|
4
|
+
import type { SuggestionMenuRow } from './SuggestionMenu';
|
|
5
|
+
import { type SuggestionPopupOptions } from './suggestionPopup';
|
|
6
|
+
/** A person `@` and `!@` offer. */
|
|
7
|
+
export interface MentionPerson {
|
|
8
|
+
/** The app's own key for the person — the row's key and the chip's `id`. */
|
|
9
|
+
id: string;
|
|
10
|
+
name: string;
|
|
11
|
+
/** The second line of the row: a role, a team. */
|
|
12
|
+
description?: string;
|
|
13
|
+
/** Their Nostr key, when they have one — what the body is written with (SPEC §13.1). */
|
|
14
|
+
pubkey?: string | null;
|
|
15
|
+
/** The face at the row's start. Default: the package `Avatar` for the name. */
|
|
16
|
+
avatar?: ReactNode;
|
|
17
|
+
}
|
|
18
|
+
/** How many people the list shows. */
|
|
19
|
+
export declare const PEOPLE_LIMIT = 6;
|
|
20
|
+
/** The people whose name holds the query, the first {@link PEOPLE_LIMIT} of them. */
|
|
21
|
+
export declare function filterPeople(people: readonly MentionPerson[], query: string): MentionPerson[];
|
|
22
|
+
/**
|
|
23
|
+
* The people list `@` and `!@` open: the face, the name, the second line, and
|
|
24
|
+
* the Enter hint while highlighted — `MenuItem` at its tall size.
|
|
25
|
+
*/
|
|
26
|
+
export declare function peopleMenu(urgent: boolean): SuggestionPopupOptions<MentionPerson>;
|
|
27
|
+
export interface PersonMentionOptions {
|
|
28
|
+
/** Everyone the list can offer, asked each time the query changes. */
|
|
29
|
+
people: () => readonly MentionPerson[];
|
|
30
|
+
}
|
|
31
|
+
type Doc = {
|
|
32
|
+
descendants: (cb: (node: {
|
|
33
|
+
type: {
|
|
34
|
+
name: string;
|
|
35
|
+
};
|
|
36
|
+
attrs: Record<string, unknown>;
|
|
37
|
+
}) => boolean | void) => void;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* `@` — a person, as a chip that writes their key (SPEC §13.1).
|
|
41
|
+
*
|
|
42
|
+
* PersonMention.configure({ people: () => directory })
|
|
43
|
+
*
|
|
44
|
+
* Its `pubkey` and `label` are what `mentionText` takes.
|
|
45
|
+
*/
|
|
46
|
+
export declare const PersonMention: import("@tiptap/core").Node<MentionOptions<MentionPerson, MentionPerson> & PersonMentionOptions, any>;
|
|
47
|
+
/**
|
|
48
|
+
* `!@` — a person, urgently: the same chip in the urgent tone. Its text is an
|
|
49
|
+
* ordinary mention; the urgency travels as a tag (`urgentTagsFor`), so hand the
|
|
50
|
+
* write {@link urgentPubkeys}.
|
|
51
|
+
*/
|
|
52
|
+
export declare const UrgentPersonMention: import("@tiptap/core").Node<MentionOptions<MentionPerson, MentionPerson> & PersonMentionOptions, any>;
|
|
53
|
+
/**
|
|
54
|
+
* The keys the document's urgent mentions name — what the write turns into
|
|
55
|
+
* `["urgent", <pubkey>]` tags. A chip with no key has no tag to carry; its text
|
|
56
|
+
* is the old `!@Name`.
|
|
57
|
+
*/
|
|
58
|
+
export declare function urgentPubkeys(editor: {
|
|
59
|
+
state: {
|
|
60
|
+
doc: Doc;
|
|
61
|
+
};
|
|
62
|
+
}): string[] | undefined;
|
|
63
|
+
/** Something `[` offers: a reference drawn as who said it and how it opens. */
|
|
64
|
+
export interface CaptionedItem {
|
|
65
|
+
/** The referenced thing's id — the row's key and the chip's `id`. */
|
|
66
|
+
id: string;
|
|
67
|
+
/** Who, as the list shows them. */
|
|
68
|
+
label: string;
|
|
69
|
+
/** The opening words, marks stripped: the caption the row and the chip wear. */
|
|
70
|
+
snippet: string;
|
|
71
|
+
/** `nostr:…`, exactly as the body will carry it (`messageReference`). */
|
|
72
|
+
uri: string;
|
|
73
|
+
/** What the query is matched against beside `label`. Default: `snippet`. */
|
|
74
|
+
search?: string;
|
|
75
|
+
/** The row's second line, e.g. where the thing sits. The chip does not wear it. */
|
|
76
|
+
description?: string;
|
|
77
|
+
}
|
|
78
|
+
/** One labelled group of `[`'s rows, in the order the list draws them. */
|
|
79
|
+
export interface ReferenceSection {
|
|
80
|
+
label: string;
|
|
81
|
+
items: readonly CaptionedItem[];
|
|
82
|
+
}
|
|
83
|
+
/** How many references the list shows. */
|
|
84
|
+
export declare const REFERENCE_LIMIT = 6;
|
|
85
|
+
/**
|
|
86
|
+
* The references whose label or text holds the query — the last
|
|
87
|
+
* {@link REFERENCE_LIMIT}, in the order given: a thread is unbounded, and a
|
|
88
|
+
* list that grew with it would be a hundred rows of prose.
|
|
89
|
+
*/
|
|
90
|
+
export declare function filterReferences(items: readonly CaptionedItem[], query: string): CaptionedItem[];
|
|
91
|
+
export interface CaptionedReferenceOptions {
|
|
92
|
+
/** Drawn before the caption: a 14px icon. */
|
|
93
|
+
icon: ReactNode;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* A reference mid-sentence, drawn as `label: snippet` and written as its `uri`
|
|
97
|
+
* verbatim (SPEC §13.1). The caption is the snapshot it was picked with — a
|
|
98
|
+
* caption, never parsed. Inserted by {@link ReferenceTrigger}, a paste or a
|
|
99
|
+
* draft; it opens no list of its own.
|
|
100
|
+
*/
|
|
101
|
+
export declare const CaptionedReference: import("@tiptap/core").Node<MentionOptions<any, import("@tiptap/extension-mention").MentionNodeAttrs> & CaptionedReferenceOptions, any>;
|
|
102
|
+
export interface ReferenceMenuOptions {
|
|
103
|
+
/** Names the list, e.g. what can be referenced. */
|
|
104
|
+
ariaLabel: string;
|
|
105
|
+
/** The section's heading. */
|
|
106
|
+
sectionLabel: string;
|
|
107
|
+
/** At each row's start: a 16px icon. */
|
|
108
|
+
icon: ReactNode;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* The list `[` opens: `label: snippet` rows, the same box as the people list.
|
|
112
|
+
* One section headed `sectionLabel`, or — when the rows say which section they
|
|
113
|
+
* are in — a heading for each, in the order the rows arrive.
|
|
114
|
+
*/
|
|
115
|
+
export declare function referenceMenu({ ariaLabel, sectionLabel, icon }: ReferenceMenuOptions): SuggestionPopupOptions<CaptionedItem>;
|
|
116
|
+
export interface ReferenceTriggerOptions extends ReferenceMenuOptions {
|
|
117
|
+
/** Everything `[` can offer, asked each time the query changes. Narrowed by {@link filterReferences}. */
|
|
118
|
+
items: () => readonly CaptionedItem[];
|
|
119
|
+
/**
|
|
120
|
+
* In place of `items`: the sections to draw for what was typed, already
|
|
121
|
+
* narrowed and ordered by the app. Empty sections are not drawn.
|
|
122
|
+
*/
|
|
123
|
+
sections?: (query: string) => readonly ReferenceSection[];
|
|
124
|
+
/**
|
|
125
|
+
* Called with a listener while the list is open; the app calls it when what
|
|
126
|
+
* `sections` would answer has changed — a search landing — and the open list
|
|
127
|
+
* is drawn again for the same query. Returns the unsubscribe.
|
|
128
|
+
*/
|
|
129
|
+
subscribe?: (listener: () => void) => () => void;
|
|
130
|
+
/** The node a pick inserts. Default `captionedReference`. */
|
|
131
|
+
nodeName: string;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* `[` — reference something, inserted as a {@link CaptionedReference} chip.
|
|
135
|
+
*
|
|
136
|
+
* Its own extension rather than the chip's suggestion, so the chip's text (its
|
|
137
|
+
* `renderText`) does not change with the key that summons the list.
|
|
138
|
+
*/
|
|
139
|
+
export declare const ReferenceTrigger: Extension<ReferenceTriggerOptions, any>;
|
|
140
|
+
/** A row of the `/` list, and what choosing it does. */
|
|
141
|
+
export interface SlashCommand {
|
|
142
|
+
key: string;
|
|
143
|
+
row: SuggestionMenuRow;
|
|
144
|
+
/** Matched beside the row's label: an id, a trigger, a description. */
|
|
145
|
+
keywords?: readonly string[];
|
|
146
|
+
/** Runs once the `/query` that summoned the list has been removed. */
|
|
147
|
+
run: (editor: Editor) => void;
|
|
148
|
+
}
|
|
149
|
+
export interface SlashSection {
|
|
150
|
+
label: string;
|
|
151
|
+
commands: readonly SlashCommand[];
|
|
152
|
+
}
|
|
153
|
+
export type FormatId = 'paragraph' | 'heading' | 'subheading' | 'quote' | 'bulletList' | 'orderedList' | 'code';
|
|
154
|
+
export interface FormatDef {
|
|
155
|
+
id: FormatId;
|
|
156
|
+
label: string;
|
|
157
|
+
/** What you type to get it — the input rule the extension registers. Blank when there is none. */
|
|
158
|
+
trigger?: string;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* The formats `/` offers, in order. The hint is what you would type, not a key
|
|
162
|
+
* chord. Bold, italic and underline are absent: they act on text already
|
|
163
|
+
* written, so they are the selection toolbar's.
|
|
164
|
+
*/
|
|
165
|
+
export declare const FORMATS: readonly FormatDef[];
|
|
166
|
+
/** Code as a mark inside the line, or as a block of its own. */
|
|
167
|
+
export type CodeFormat = 'inline' | 'block';
|
|
168
|
+
/**
|
|
169
|
+
* Apply one format to the current block. `set*` wherever Tiptap has one:
|
|
170
|
+
* choosing Heading should make a heading, not turn one off. `false` means
|
|
171
|
+
* nothing changed, not that anything failed.
|
|
172
|
+
*/
|
|
173
|
+
export declare function applyFormat(editor: Editor, id: FormatId, code?: CodeFormat): boolean;
|
|
174
|
+
/** The Format section every app's `/` opens with. */
|
|
175
|
+
export declare function formatSection(code?: CodeFormat): SlashSection;
|
|
176
|
+
/** A row that types another trigger, so its own list opens — `@` from `/`. */
|
|
177
|
+
export declare function typeTrigger(input: string): SlashCommand['run'];
|
|
178
|
+
/** The sections narrowed to a query — the text typed after the `/`. Empty sections stay. */
|
|
179
|
+
export declare function filterSlashSections(sections: readonly SlashSection[], query: string): SlashSection[];
|
|
180
|
+
export interface SlashCommandsOptions {
|
|
181
|
+
/** The sections, in order: {@link formatSection} first, then the app's own. */
|
|
182
|
+
sections: readonly SlashSection[];
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* `/` — format the line or insert something, at the caret, mid-sentence too.
|
|
186
|
+
* A `/` inside a word (`and/or`, a path) opens nothing: the plugin wants a
|
|
187
|
+
* space or the line's start before it.
|
|
188
|
+
*/
|
|
189
|
+
export declare const SlashCommands: Extension<SlashCommandsOptions, any>;
|
|
190
|
+
export {};
|
|
191
|
+
//# sourceMappingURL=ComposerTriggers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ComposerTriggers.d.ts","sourceRoot":"","sources":["../src/ComposerTriggers.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SuggestionMenu.d.ts","sourceRoot":"","sources":["../src/SuggestionMenu.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"SuggestionMenu.d.ts","sourceRoot":"","sources":["../src/SuggestionMenu.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAiF,KAAK,SAAS,EAAE,KAAK,GAAG,EAAE,MAAM,OAAO,CAAA;AAC/H,OAAO,EAAwC,KAAK,aAAa,EAAE,MAAM,QAAQ,CAAA;AAGjF;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,OAAO,CAAC,EAAE,SAAS,CAAA;IACnB,gFAAgF;IAChF,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,6EAA6E;IAC7E,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,+EAA+E;IAC/E,IAAI,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;CAC7B;AAED,MAAM,WAAW,qBAAqB,CAAC,CAAC;IACtC,gEAAgE;IAChE,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,SAAS,CAAC,EAAE,CAAA;IACnB,8CAA8C;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,oDAAoD;AACpD,MAAM,WAAW,oBAAoB;IACnC,iFAAiF;IACjF,SAAS,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,OAAO,CAAA;CAC7C;AAED,MAAM,WAAW,mBAAmB,CAAC,CAAC;IACpC,gEAAgE;IAChE,IAAI,EAAE,OAAO,GAAG,IAAI,CAAA;IACpB,8EAA8E;IAC9E,aAAa,CAAC,EAAE,WAAW,GAAG,IAAI,CAAA;IAClC,6CAA6C;IAC7C,SAAS,EAAE,MAAM,CAAA;IACjB,yCAAyC;IACzC,KAAK,EAAE,MAAM,CAAA;IACb,4DAA4D;IAC5D,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,SAAS,qBAAqB,CAAC,CAAC,CAAC,EAAE,CAAA;IAC7C,8BAA8B;IAC9B,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,CAAA;IAC5B,wBAAwB;IACxB,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,iBAAiB,CAAA;IACnC,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAA;IAC3B,MAAM,CAAC,EAAE,GAAG,CAAC,oBAAoB,CAAC,CAAA;CACnC;AAED,wBAAgB,cAAc,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,mBAAmB,CAAC,CAAC,CAAC,sCAuHvJ"}
|
package/dist/editor.d.ts
CHANGED
|
@@ -9,5 +9,6 @@
|
|
|
9
9
|
*/
|
|
10
10
|
export { KeptSelection, SelectionToolbar, normalizeHref, type MarkId, type SelectionToolbarProps } from './SelectionToolbar';
|
|
11
11
|
export { suggestionPopup, isSuggestionActive, isSuggestionOpen, type SuggestionPopupOptions } from './suggestionPopup';
|
|
12
|
+
export { PersonMention, UrgentPersonMention, CaptionedReference, ReferenceTrigger, SlashCommands, peopleMenu, referenceMenu, filterPeople, urgentPubkeys, filterReferences, formatSection, applyFormat, typeTrigger, filterSlashSections, FORMATS, type MentionPerson, type PersonMentionOptions, type CaptionedItem, type CaptionedReferenceOptions, type ReferenceTriggerOptions, type ReferenceMenuOptions, type SlashCommand, type SlashSection, type SlashCommandsOptions, type FormatId, type FormatDef, type CodeFormat, } from './ComposerTriggers';
|
|
12
13
|
export { BlockId, UnknownBlock, ReferenceNode, AttachmentNode, type ReferenceNodeOptions, type ReferenceViewProps, type AttachmentNodeOptions, type AttachmentViewProps, } from './BlockNodes';
|
|
13
14
|
//# sourceMappingURL=editor.d.ts.map
|
package/dist/editor.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../src/editor.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,aAAa,EAAE,KAAK,MAAM,EAAE,KAAK,qBAAqB,EAAE,MAAM,oBAAoB,CAAA;AAC5H,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,KAAK,sBAAsB,EAAE,MAAM,mBAAmB,CAAA;AACtH,OAAO,EACL,OAAO,EACP,YAAY,EACZ,aAAa,EACb,cAAc,EACd,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACvB,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,GACzB,MAAM,cAAc,CAAA"}
|
|
1
|
+
{"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../src/editor.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,aAAa,EAAE,KAAK,MAAM,EAAE,KAAK,qBAAqB,EAAE,MAAM,oBAAoB,CAAA;AAC5H,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,KAAK,sBAAsB,EAAE,MAAM,mBAAmB,CAAA;AACtH,OAAO,EACL,aAAa,EACb,mBAAmB,EACnB,kBAAkB,EAClB,gBAAgB,EAChB,aAAa,EACb,UAAU,EACV,aAAa,EACb,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,aAAa,EACb,WAAW,EACX,WAAW,EACX,mBAAmB,EACnB,OAAO,EACP,KAAK,aAAa,EAClB,KAAK,oBAAoB,EACzB,KAAK,aAAa,EAClB,KAAK,yBAAyB,EAC9B,KAAK,uBAAuB,EAC5B,KAAK,oBAAoB,EACzB,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,oBAAoB,EACzB,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,KAAK,UAAU,GAChB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EACL,OAAO,EACP,YAAY,EACZ,aAAa,EACb,cAAc,EACd,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACvB,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,GACzB,MAAM,cAAc,CAAA"}
|
package/dist/editor.js
CHANGED
|
@@ -317,7 +317,12 @@ function suggestionPopup(options) {
|
|
|
317
317
|
return () => {
|
|
318
318
|
let component = null;
|
|
319
319
|
let container = null;
|
|
320
|
+
let last = null;
|
|
321
|
+
let unsubscribe;
|
|
320
322
|
const exit = () => {
|
|
323
|
+
unsubscribe?.();
|
|
324
|
+
unsubscribe = void 0;
|
|
325
|
+
last = null;
|
|
321
326
|
if (!component) return;
|
|
322
327
|
openCount = Math.max(0, openCount - 1);
|
|
323
328
|
lastClose = Date.now();
|
|
@@ -333,8 +338,20 @@ function suggestionPopup(options) {
|
|
|
333
338
|
container = document.createElement("div");
|
|
334
339
|
document.body.appendChild(container);
|
|
335
340
|
container.appendChild(component.element);
|
|
341
|
+
last = props;
|
|
342
|
+
const { subscribe, refresh } = options;
|
|
343
|
+
if (subscribe && refresh) {
|
|
344
|
+
unsubscribe = subscribe(() => {
|
|
345
|
+
if (!last || !component) return;
|
|
346
|
+
last = { ...last, items: refresh(last.query) };
|
|
347
|
+
component.updateProps({ ...last, options });
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
},
|
|
351
|
+
onUpdate: (props) => {
|
|
352
|
+
last = props;
|
|
353
|
+
component?.updateProps({ ...props, options });
|
|
336
354
|
},
|
|
337
|
-
onUpdate: (props) => component?.updateProps({ ...props, options }),
|
|
338
355
|
onKeyDown: ({ event }) => {
|
|
339
356
|
if (event.key === "Escape") {
|
|
340
357
|
exit();
|
|
@@ -347,12 +364,308 @@ function suggestionPopup(options) {
|
|
|
347
364
|
};
|
|
348
365
|
}
|
|
349
366
|
|
|
367
|
+
// src/ComposerTriggers.tsx
|
|
368
|
+
import { Extension as Extension2 } from "@tiptap/core";
|
|
369
|
+
import { PluginKey as PluginKey2 } from "@tiptap/pm/state";
|
|
370
|
+
import Mention from "@tiptap/extension-mention";
|
|
371
|
+
import Suggestion from "@tiptap/suggestion";
|
|
372
|
+
import { NodeViewWrapper, ReactNodeViewRenderer } from "@tiptap/react";
|
|
373
|
+
import { Avatar } from "@estiva-app/ui";
|
|
374
|
+
import { EnterHint } from "@estiva-app/ui";
|
|
375
|
+
import { inlineChipClassName } from "@estiva-app/ui";
|
|
376
|
+
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
377
|
+
var PEOPLE_LIMIT = 6;
|
|
378
|
+
function filterPeople(people, query) {
|
|
379
|
+
const q = query.toLowerCase();
|
|
380
|
+
return people.filter((person) => q === "" || person.name.toLowerCase().includes(q)).slice(0, PEOPLE_LIMIT);
|
|
381
|
+
}
|
|
382
|
+
function peopleMenu(urgent) {
|
|
383
|
+
const section = urgent ? "Urgent mention" : "People";
|
|
384
|
+
return {
|
|
385
|
+
ariaLabel: section,
|
|
386
|
+
// The people and the reference lists are the same box: 658px, capped at 360.
|
|
387
|
+
width: "w-[658px]",
|
|
388
|
+
maxHeight: "max-h-[360px]",
|
|
389
|
+
sections: (people) => [{ label: section, items: people, className: "px-3 py-1" }],
|
|
390
|
+
itemKey: (person) => person.id,
|
|
391
|
+
row: (person) => ({
|
|
392
|
+
label: person.name,
|
|
393
|
+
description: person.description,
|
|
394
|
+
leading: person.avatar ?? /* @__PURE__ */ jsx3(Avatar, { size: 32, alt: person.name }),
|
|
395
|
+
hint: /* @__PURE__ */ jsx3(EnterHint, {}),
|
|
396
|
+
size: "tall"
|
|
397
|
+
})
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
function optionsOf(editor, name) {
|
|
401
|
+
return editor.extensionManager.extensions.find((one) => one.name === name)?.options;
|
|
402
|
+
}
|
|
403
|
+
function personSuggestion(urgent, name) {
|
|
404
|
+
return {
|
|
405
|
+
...urgent ? { char: "!@" } : {},
|
|
406
|
+
items: ({ query, editor }) => filterPeople(optionsOf(editor, name)?.people() ?? [], query),
|
|
407
|
+
render: suggestionPopup(peopleMenu(urgent)),
|
|
408
|
+
command: ({ editor, range, props: person }) => {
|
|
409
|
+
editor.chain().focus().insertContentAt(range, [
|
|
410
|
+
{ type: name, attrs: { id: person.id, label: person.name, pubkey: person.pubkey ?? null } },
|
|
411
|
+
{ type: "text", text: " " }
|
|
412
|
+
]).run();
|
|
413
|
+
}
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
var HEX_KEY = /^[0-9a-f]{64}$/;
|
|
417
|
+
var NOSTR_URI = /^nostr:[a-z0-9]+$/i;
|
|
418
|
+
var fromData = (name, valid) => ({
|
|
419
|
+
parseHTML: (element) => {
|
|
420
|
+
const value = element.getAttribute(`data-${name}`);
|
|
421
|
+
return value !== null && (!valid || valid.test(value)) ? value : null;
|
|
422
|
+
},
|
|
423
|
+
// The node's own `renderHTML` writes it.
|
|
424
|
+
renderHTML: () => ({})
|
|
425
|
+
});
|
|
426
|
+
var personAttributes = () => ({
|
|
427
|
+
id: { default: null, ...fromData("id") },
|
|
428
|
+
label: { default: null, ...fromData("label") },
|
|
429
|
+
/**
|
|
430
|
+
* The person's Nostr key, when they have one — SPEC §13.1. `id` is the app's
|
|
431
|
+
* own and means nothing to another app; this is what the body is written
|
|
432
|
+
* with, so a mention survives a rename.
|
|
433
|
+
*/
|
|
434
|
+
pubkey: { default: null, ...fromData("pubkey", HEX_KEY) }
|
|
435
|
+
});
|
|
436
|
+
function personData(attrs) {
|
|
437
|
+
return {
|
|
438
|
+
"data-id": String(attrs.id ?? ""),
|
|
439
|
+
"data-label": String(attrs.label ?? ""),
|
|
440
|
+
...typeof attrs.pubkey === "string" && attrs.pubkey ? { "data-pubkey": attrs.pubkey } : {}
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
var PersonMention = Mention.extend({
|
|
444
|
+
name: "mention",
|
|
445
|
+
addOptions() {
|
|
446
|
+
return { ...this.parent(), HTMLAttributes: {}, people: () => [], suggestion: personSuggestion(false, this.name) };
|
|
447
|
+
},
|
|
448
|
+
addAttributes: personAttributes,
|
|
449
|
+
renderHTML({ node }) {
|
|
450
|
+
return ["span", { "data-mention": "true", ...personData(node.attrs), class: inlineChipClassName("person", "cursor-default") }, `@${node.attrs.label}`];
|
|
451
|
+
},
|
|
452
|
+
parseHTML() {
|
|
453
|
+
return [{ tag: "span[data-mention]" }];
|
|
454
|
+
}
|
|
455
|
+
});
|
|
456
|
+
var UrgentPersonMention = Mention.extend({
|
|
457
|
+
name: "urgentMention",
|
|
458
|
+
addOptions() {
|
|
459
|
+
return { ...this.parent(), HTMLAttributes: {}, people: () => [], suggestion: personSuggestion(true, this.name) };
|
|
460
|
+
},
|
|
461
|
+
addAttributes: personAttributes,
|
|
462
|
+
renderHTML({ node }) {
|
|
463
|
+
return [
|
|
464
|
+
"span",
|
|
465
|
+
{ "data-urgent-mention": "true", ...personData(node.attrs), class: inlineChipClassName("urgent", "cursor-default") },
|
|
466
|
+
`@${node.attrs.label}`
|
|
467
|
+
];
|
|
468
|
+
},
|
|
469
|
+
parseHTML() {
|
|
470
|
+
return [{ tag: "span[data-urgent-mention]" }];
|
|
471
|
+
}
|
|
472
|
+
});
|
|
473
|
+
function urgentPubkeys(editor) {
|
|
474
|
+
const urgent = [];
|
|
475
|
+
editor.state.doc.descendants((node) => {
|
|
476
|
+
if (node.type.name === "urgentMention" && typeof node.attrs.pubkey === "string" && node.attrs.pubkey) urgent.push(node.attrs.pubkey);
|
|
477
|
+
});
|
|
478
|
+
return urgent.length > 0 ? urgent : void 0;
|
|
479
|
+
}
|
|
480
|
+
var REFERENCE_LIMIT = 6;
|
|
481
|
+
function filterReferences(items, query) {
|
|
482
|
+
const q = query.toLowerCase();
|
|
483
|
+
const shown = q ? items.filter((item) => (item.search ?? item.snippet).toLowerCase().includes(q) || item.label.toLowerCase().includes(q)) : [...items];
|
|
484
|
+
return shown.slice(-REFERENCE_LIMIT);
|
|
485
|
+
}
|
|
486
|
+
var captionOf = (label, snippet) => snippet ? `${label}: ${snippet}` : label;
|
|
487
|
+
var CaptionedReference = Mention.extend({
|
|
488
|
+
name: "captionedReference",
|
|
489
|
+
group: "inline",
|
|
490
|
+
inline: true,
|
|
491
|
+
atom: true,
|
|
492
|
+
addOptions() {
|
|
493
|
+
return { ...this.parent(), HTMLAttributes: {}, icon: null, suggestion: { char: "\0", items: () => [] } };
|
|
494
|
+
},
|
|
495
|
+
addAttributes() {
|
|
496
|
+
return {
|
|
497
|
+
id: { default: null, ...fromData("id") },
|
|
498
|
+
label: { default: null, ...fromData("label") },
|
|
499
|
+
snippet: { default: "", parseHTML: (element) => element.getAttribute("data-snippet") ?? "", renderHTML: () => ({}) },
|
|
500
|
+
uri: { default: null, ...fromData("uri", NOSTR_URI) }
|
|
501
|
+
};
|
|
502
|
+
},
|
|
503
|
+
renderHTML({ node }) {
|
|
504
|
+
return [
|
|
505
|
+
"span",
|
|
506
|
+
{ [`data-${this.name.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`)}`]: "true", "data-id": String(node.attrs.id ?? ""), "data-label": String(node.attrs.label ?? ""), "data-snippet": String(node.attrs.snippet ?? ""), ...node.attrs.uri ? { "data-uri": String(node.attrs.uri) } : {}, class: inlineChipClassName("neutral", "cursor-default") },
|
|
507
|
+
captionOf(node.attrs.label, node.attrs.snippet)
|
|
508
|
+
];
|
|
509
|
+
},
|
|
510
|
+
parseHTML() {
|
|
511
|
+
return [{ tag: `span[data-${this.name.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`)}]` }];
|
|
512
|
+
},
|
|
513
|
+
addNodeView() {
|
|
514
|
+
const icon = this.options.icon;
|
|
515
|
+
return ReactNodeViewRenderer(
|
|
516
|
+
({ node }) => /* @__PURE__ */ jsxs2(NodeViewWrapper, { as: "span", className: inlineChipClassName("neutral", "max-w-[24ch] cursor-default"), children: [
|
|
517
|
+
/* @__PURE__ */ jsx3("span", { className: "flex items-center justify-center w-4 h-4 shrink-0 text-text-secondary", children: icon }),
|
|
518
|
+
/* @__PURE__ */ jsx3("span", { className: "truncate", children: captionOf(node.attrs.label, node.attrs.snippet) })
|
|
519
|
+
] }),
|
|
520
|
+
{ as: "span" }
|
|
521
|
+
);
|
|
522
|
+
}
|
|
523
|
+
});
|
|
524
|
+
function referenceMenu({ ariaLabel, sectionLabel, icon }) {
|
|
525
|
+
return {
|
|
526
|
+
ariaLabel,
|
|
527
|
+
width: "w-[658px]",
|
|
528
|
+
maxHeight: "max-h-[360px]",
|
|
529
|
+
sections: (items) => {
|
|
530
|
+
const groups = [];
|
|
531
|
+
for (const item of items) {
|
|
532
|
+
const label = item.section ?? sectionLabel;
|
|
533
|
+
const last = groups[groups.length - 1];
|
|
534
|
+
if (last?.label === label) last.items.push(item);
|
|
535
|
+
else groups.push({ label, items: [item], className: "px-2" });
|
|
536
|
+
}
|
|
537
|
+
return groups;
|
|
538
|
+
},
|
|
539
|
+
itemKey: (item) => `reference-${item.id}`,
|
|
540
|
+
row: (item) => ({ leading: icon, label: captionOf(item.label, item.snippet), description: item.description, hint: /* @__PURE__ */ jsx3(EnterHint, {}) })
|
|
541
|
+
};
|
|
542
|
+
}
|
|
543
|
+
var listed = (options, query) => options.sections ? options.sections(query).flatMap((section) => section.items.map((item) => ({ ...item, section: section.label }))) : filterReferences(options.items(), query);
|
|
544
|
+
var ReferenceTrigger = Extension2.create({
|
|
545
|
+
name: "referenceTrigger",
|
|
546
|
+
addOptions() {
|
|
547
|
+
return { items: () => [], nodeName: "captionedReference", ariaLabel: "References", sectionLabel: "References", icon: null };
|
|
548
|
+
},
|
|
549
|
+
addProseMirrorPlugins() {
|
|
550
|
+
const options = this.options;
|
|
551
|
+
return [
|
|
552
|
+
Suggestion({
|
|
553
|
+
editor: this.editor,
|
|
554
|
+
char: "[",
|
|
555
|
+
pluginKey: new PluginKey2("referenceTrigger"),
|
|
556
|
+
// As a mention's: only where the chip may go.
|
|
557
|
+
allow: ({ state, range }) => {
|
|
558
|
+
const type = state.schema.nodes[options.nodeName];
|
|
559
|
+
return !!type && !!state.doc.resolve(range.from).parent.type.contentMatch.matchType(type);
|
|
560
|
+
},
|
|
561
|
+
items: ({ query }) => listed(options, query),
|
|
562
|
+
render: suggestionPopup({ ...referenceMenu(options), subscribe: options.subscribe, refresh: (query) => listed(options, query) }),
|
|
563
|
+
command: ({ editor, range, props: item }) => {
|
|
564
|
+
editor.chain().focus().insertContentAt(range, [
|
|
565
|
+
{ type: options.nodeName, attrs: { id: item.id, label: item.label, snippet: item.snippet, uri: item.uri } },
|
|
566
|
+
{ type: "text", text: " " }
|
|
567
|
+
]).run();
|
|
568
|
+
}
|
|
569
|
+
})
|
|
570
|
+
];
|
|
571
|
+
}
|
|
572
|
+
});
|
|
573
|
+
var FORMATS = [
|
|
574
|
+
{ id: "paragraph", label: "Text" },
|
|
575
|
+
{ id: "heading", label: "Heading", trigger: "#" },
|
|
576
|
+
{ id: "subheading", label: "Subheading", trigger: "##" },
|
|
577
|
+
{ id: "quote", label: "Quote", trigger: ">" },
|
|
578
|
+
{ id: "code", label: "Code", trigger: "`" },
|
|
579
|
+
{ id: "bulletList", label: "Bulleted list", trigger: "-" },
|
|
580
|
+
{ id: "orderedList", label: "Numbered list", trigger: "1." }
|
|
581
|
+
];
|
|
582
|
+
function applyFormat(editor, id, code = "inline") {
|
|
583
|
+
const chain = editor.chain().focus();
|
|
584
|
+
const run = (command, ...args) => {
|
|
585
|
+
const named = chain[command];
|
|
586
|
+
return named ? named(...args).run() : false;
|
|
587
|
+
};
|
|
588
|
+
switch (id) {
|
|
589
|
+
case "paragraph":
|
|
590
|
+
return run("setParagraph");
|
|
591
|
+
case "heading":
|
|
592
|
+
return run("setHeading", { level: 1 });
|
|
593
|
+
case "subheading":
|
|
594
|
+
return run("setHeading", { level: 2 });
|
|
595
|
+
case "quote":
|
|
596
|
+
return run("toggleBlockquote");
|
|
597
|
+
case "bulletList":
|
|
598
|
+
return run("toggleBulletList");
|
|
599
|
+
case "orderedList":
|
|
600
|
+
return run("toggleOrderedList");
|
|
601
|
+
case "code":
|
|
602
|
+
return run(code === "block" ? "toggleCodeBlock" : "toggleCode");
|
|
603
|
+
default:
|
|
604
|
+
return false;
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
function formatSection(code = "inline") {
|
|
608
|
+
return {
|
|
609
|
+
label: "Format",
|
|
610
|
+
commands: FORMATS.map((format) => ({
|
|
611
|
+
key: `format-${format.id}`,
|
|
612
|
+
row: { label: format.label, shortcut: format.trigger },
|
|
613
|
+
keywords: [format.id],
|
|
614
|
+
run: (editor) => {
|
|
615
|
+
applyFormat(editor, format.id, code);
|
|
616
|
+
}
|
|
617
|
+
}))
|
|
618
|
+
};
|
|
619
|
+
}
|
|
620
|
+
function typeTrigger(input) {
|
|
621
|
+
return (editor) => {
|
|
622
|
+
requestAnimationFrame(() => editor.commands.insertContent(input));
|
|
623
|
+
};
|
|
624
|
+
}
|
|
625
|
+
function matches(command, q) {
|
|
626
|
+
return [command.row.label, ...command.keywords ?? []].some((text) => text.toLowerCase().includes(q));
|
|
627
|
+
}
|
|
628
|
+
function filterSlashSections(sections, query) {
|
|
629
|
+
const q = query.toLowerCase();
|
|
630
|
+
return sections.map((section) => ({ ...section, commands: q ? section.commands.filter((command) => matches(command, q)) : section.commands }));
|
|
631
|
+
}
|
|
632
|
+
var SlashCommands = Extension2.create({
|
|
633
|
+
name: "slashCommands",
|
|
634
|
+
addOptions() {
|
|
635
|
+
return { sections: [formatSection()] };
|
|
636
|
+
},
|
|
637
|
+
addProseMirrorPlugins() {
|
|
638
|
+
const sections = this.options.sections;
|
|
639
|
+
return [
|
|
640
|
+
Suggestion({
|
|
641
|
+
editor: this.editor,
|
|
642
|
+
char: "/",
|
|
643
|
+
startOfLine: false,
|
|
644
|
+
pluginKey: new PluginKey2("slashCommands"),
|
|
645
|
+
items: ({ query }) => filterSlashSections(sections, query).flatMap((section, at) => section.commands.map((command) => ({ ...command, section: at }))),
|
|
646
|
+
command: ({ editor, range, props }) => {
|
|
647
|
+
editor.chain().focus().deleteRange(range).run();
|
|
648
|
+
props.run(editor);
|
|
649
|
+
},
|
|
650
|
+
render: suggestionPopup({
|
|
651
|
+
ariaLabel: "Commands",
|
|
652
|
+
width: "w-[300px]",
|
|
653
|
+
maxHeight: "max-h-[400px]",
|
|
654
|
+
sections: (rows) => sections.map((section, at) => ({ label: section.label, items: rows.filter((row) => row.section === at) })),
|
|
655
|
+
itemKey: (row) => row.key,
|
|
656
|
+
row: (row) => row.row
|
|
657
|
+
})
|
|
658
|
+
})
|
|
659
|
+
];
|
|
660
|
+
}
|
|
661
|
+
});
|
|
662
|
+
|
|
350
663
|
// src/BlockNodes.tsx
|
|
351
|
-
import { Extension as
|
|
352
|
-
import { Plugin as Plugin2, PluginKey as
|
|
664
|
+
import { Extension as Extension3, Node as Node2 } from "@tiptap/core";
|
|
665
|
+
import { Plugin as Plugin2, PluginKey as PluginKey3 } from "@tiptap/pm/state";
|
|
353
666
|
import { Mapping, ReplaceAroundStep } from "@tiptap/pm/transform";
|
|
354
|
-
import { NodeViewWrapper, ReactNodeViewRenderer } from "@tiptap/react";
|
|
355
|
-
import { jsx as
|
|
667
|
+
import { NodeViewWrapper as NodeViewWrapper2, ReactNodeViewRenderer as ReactNodeViewRenderer2 } from "@tiptap/react";
|
|
668
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
356
669
|
var BLOCK_TYPES = [
|
|
357
670
|
"paragraph",
|
|
358
671
|
"heading",
|
|
@@ -497,7 +810,7 @@ function bringsInBlocks(transactions) {
|
|
|
497
810
|
})
|
|
498
811
|
);
|
|
499
812
|
}
|
|
500
|
-
var BlockId =
|
|
813
|
+
var BlockId = Extension3.create({
|
|
501
814
|
name: "blockId",
|
|
502
815
|
onCreate() {
|
|
503
816
|
const { state, view } = this.editor;
|
|
@@ -510,7 +823,7 @@ var BlockId = Extension2.create({
|
|
|
510
823
|
addProseMirrorPlugins() {
|
|
511
824
|
return [
|
|
512
825
|
new Plugin2({
|
|
513
|
-
key: new
|
|
826
|
+
key: new PluginKey3("blockIdSplit"),
|
|
514
827
|
appendTransaction: (transactions, old, state) => {
|
|
515
828
|
if (!bringsInBlocks(transactions)) return null;
|
|
516
829
|
const mapping = new Mapping();
|
|
@@ -569,7 +882,7 @@ var ReferenceNode = Node2.create({
|
|
|
569
882
|
addNodeView() {
|
|
570
883
|
const View = this.options.view;
|
|
571
884
|
if (!View) return null;
|
|
572
|
-
return
|
|
885
|
+
return ReactNodeViewRenderer2(({ node }) => /* @__PURE__ */ jsx4(NodeViewWrapper2, { as: "span", className: "inline", children: /* @__PURE__ */ jsx4(View, { uri: String(node.attrs.uri ?? "") }) }));
|
|
573
886
|
}
|
|
574
887
|
});
|
|
575
888
|
var UnknownBlock = Node2.create({
|
|
@@ -591,14 +904,14 @@ var UnknownBlock = Node2.create({
|
|
|
591
904
|
return ["div", { "data-unknown-block": String(node.attrs.blockId ?? "") }, String(node.attrs.text ?? "")];
|
|
592
905
|
},
|
|
593
906
|
addNodeView() {
|
|
594
|
-
return
|
|
907
|
+
return ReactNodeViewRenderer2(UnknownBlockView);
|
|
595
908
|
}
|
|
596
909
|
});
|
|
597
910
|
function UnknownBlockView({ node }) {
|
|
598
911
|
const source = node.attrs.source;
|
|
599
912
|
const text = String(node.attrs.text ?? "");
|
|
600
|
-
return /* @__PURE__ */
|
|
601
|
-
|
|
913
|
+
return /* @__PURE__ */ jsx4(
|
|
914
|
+
NodeViewWrapper2,
|
|
602
915
|
{
|
|
603
916
|
"data-block-id": source?.id,
|
|
604
917
|
"data-block-type": source?.type,
|
|
@@ -637,19 +950,34 @@ var AttachmentNode = Node2.create({
|
|
|
637
950
|
addNodeView() {
|
|
638
951
|
const View = this.options.view;
|
|
639
952
|
if (!View) return null;
|
|
640
|
-
return
|
|
953
|
+
return ReactNodeViewRenderer2(({ node }) => /* @__PURE__ */ jsx4(NodeViewWrapper2, { className: "my-2", children: /* @__PURE__ */ jsx4(View, { attrs: node.attrs }) }));
|
|
641
954
|
}
|
|
642
955
|
});
|
|
643
956
|
export {
|
|
644
957
|
AttachmentNode,
|
|
645
958
|
BlockId,
|
|
959
|
+
CaptionedReference,
|
|
960
|
+
FORMATS,
|
|
646
961
|
KeptSelection,
|
|
962
|
+
PersonMention,
|
|
647
963
|
ReferenceNode,
|
|
964
|
+
ReferenceTrigger,
|
|
648
965
|
SelectionToolbar,
|
|
966
|
+
SlashCommands,
|
|
649
967
|
UnknownBlock,
|
|
968
|
+
UrgentPersonMention,
|
|
969
|
+
applyFormat,
|
|
970
|
+
filterPeople,
|
|
971
|
+
filterReferences,
|
|
972
|
+
filterSlashSections,
|
|
973
|
+
formatSection,
|
|
650
974
|
isSuggestionActive,
|
|
651
975
|
isSuggestionOpen,
|
|
652
976
|
normalizeHref,
|
|
653
|
-
|
|
977
|
+
peopleMenu,
|
|
978
|
+
referenceMenu,
|
|
979
|
+
suggestionPopup,
|
|
980
|
+
typeTrigger,
|
|
981
|
+
urgentPubkeys
|
|
654
982
|
};
|
|
655
983
|
//# sourceMappingURL=editor.js.map
|