@haklex/rich-plugin-mention 0.0.65 → 0.0.66

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 ADDED
@@ -0,0 +1,82 @@
1
+ # @haklex/rich-plugin-mention
2
+
3
+ Mention typeahead plugin with platform selection for @-mentioning users across platforms (GitHub, Twitter, etc.).
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pnpm add @haklex/rich-plugin-mention
9
+ ```
10
+
11
+ ## Peer Dependencies
12
+
13
+ | Package | Version |
14
+ | --- | --- |
15
+ | `@lexical/react` | `^0.41.0` |
16
+ | `lexical` | `^0.41.0` |
17
+ | `react` | `>= 19` |
18
+ | `react-dom` | `>= 19` |
19
+
20
+ ## Usage
21
+
22
+ ```tsx
23
+ import { MentionMenuPlugin } from '@haklex/rich-plugin-mention'
24
+ import '@haklex/rich-plugin-mention/style.css'
25
+
26
+ function Editor() {
27
+ return (
28
+ <RichEditor>
29
+ <MentionMenuPlugin />
30
+ </RichEditor>
31
+ )
32
+ }
33
+ ```
34
+
35
+ Typing `@` triggers a typeahead menu where users can select a platform and enter a username. The plugin ships with builtin platform definitions for common services.
36
+
37
+ ```tsx
38
+ import {
39
+ builtinPlatforms,
40
+ getAllPlatforms,
41
+ MentionMenuItem,
42
+ } from '@haklex/rich-plugin-mention'
43
+ import type {
44
+ MentionPlatformDef,
45
+ MentionMenuPluginProps,
46
+ } from '@haklex/rich-plugin-mention'
47
+
48
+ // Access builtin platforms
49
+ const platforms = builtinPlatforms
50
+ const allPlatforms = getAllPlatforms()
51
+
52
+ // Define a custom platform
53
+ const customPlatform: MentionPlatformDef = {
54
+ // ...
55
+ }
56
+ ```
57
+
58
+ ## Exports
59
+
60
+ | Export | Type | Description |
61
+ | --- | --- | --- |
62
+ | `MentionMenuPlugin` | Component | Main plugin component to render inside `RichEditor` |
63
+ | `MentionMenuItem` | Component | Individual menu item component |
64
+ | `builtinPlatforms` | Constant | Array of builtin platform definitions |
65
+ | `getAllPlatforms` | Function | Returns all registered platforms |
66
+ | `MentionPlatformDef` | TypeScript type | Platform definition interface |
67
+ | `MentionMenuPluginProps` | TypeScript type | Props type for `MentionMenuPlugin` |
68
+
69
+ ## Sub-path Exports
70
+
71
+ | Path | Description |
72
+ | --- | --- |
73
+ | `@haklex/rich-plugin-mention` | Plugin component, menu items, platform utilities, and types |
74
+ | `@haklex/rich-plugin-mention/style.css` | Stylesheet |
75
+
76
+ ## Part of Haklex
77
+
78
+ This package is part of the [Haklex](../../README.md) rich editor ecosystem.
79
+
80
+ ## License
81
+
82
+ MIT
@@ -1,10 +1,10 @@
1
1
  import { MentionMenuItem } from './MentionMenuItem';
2
2
  interface MentionMenuListProps {
3
3
  options: MentionMenuItem[];
4
+ phase: 1 | 2;
4
5
  selectedIndex: number | null;
5
6
  selectOptionAndCleanUp: (option: MentionMenuItem) => void;
6
7
  setHighlightedIndex: (index: number) => void;
7
- phase: 1 | 2;
8
8
  }
9
9
  export declare function MentionMenuList({ options, selectedIndex, selectOptionAndCleanUp, setHighlightedIndex, phase, }: MentionMenuListProps): import("react/jsx-runtime").JSX.Element | null;
10
10
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"MentionMenuList.d.ts","sourceRoot":"","sources":["../src/MentionMenuList.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AAGxD,UAAU,oBAAoB;IAC5B,OAAO,EAAE,eAAe,EAAE,CAAA;IAC1B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,sBAAsB,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,IAAI,CAAA;IACzD,mBAAmB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IAC5C,KAAK,EAAE,CAAC,GAAG,CAAC,CAAA;CACb;AAED,wBAAgB,eAAe,CAAC,EAC9B,OAAO,EACP,aAAa,EACb,sBAAsB,EACtB,mBAAmB,EACnB,KAAK,GACN,EAAE,oBAAoB,kDA+EtB"}
1
+ {"version":3,"file":"MentionMenuList.d.ts","sourceRoot":"","sources":["../src/MentionMenuList.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGzD,UAAU,oBAAoB;IAC5B,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC;IACb,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,sBAAsB,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,IAAI,CAAC;IAC1D,mBAAmB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9C;AAED,wBAAgB,eAAe,CAAC,EAC9B,OAAO,EACP,aAAa,EACb,sBAAsB,EACtB,mBAAmB,EACnB,KAAK,GACN,EAAE,oBAAoB,kDAoEtB"}
@@ -2,5 +2,5 @@ import { MentionPlatformDef } from './MentionPlatformRegistry';
2
2
  export interface MentionMenuPluginProps {
3
3
  extraPlatforms?: MentionPlatformDef[];
4
4
  }
5
- export declare function MentionMenuPlugin({ extraPlatforms, }?: MentionMenuPluginProps): import("react/jsx-runtime").JSX.Element;
5
+ export declare function MentionMenuPlugin({ extraPlatforms }?: MentionMenuPluginProps): import("react/jsx-runtime").JSX.Element;
6
6
  //# sourceMappingURL=MentionMenuPlugin.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"MentionMenuPlugin.d.ts","sourceRoot":"","sources":["../src/MentionMenuPlugin.tsx"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAA;AAGnE,MAAM,WAAW,sBAAsB;IACrC,cAAc,CAAC,EAAE,kBAAkB,EAAE,CAAA;CACtC;AAqDD,wBAAgB,iBAAiB,CAAC,EAChC,cAAc,GACf,GAAE,sBAA2B,2CAgF7B"}
1
+ {"version":3,"file":"MentionMenuPlugin.d.ts","sourceRoot":"","sources":["../src/MentionMenuPlugin.tsx"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAGpE,MAAM,WAAW,sBAAsB;IACrC,cAAc,CAAC,EAAE,kBAAkB,EAAE,CAAC;CACvC;AAiDD,wBAAgB,iBAAiB,CAAC,EAAE,cAAc,EAAE,GAAE,sBAA2B,2CAyEhF"}
@@ -1,9 +1,9 @@
1
1
  import { ReactNode } from 'react';
2
2
  export interface MentionPlatformDef {
3
+ getUrl: (handle: string) => string;
4
+ icon: ReactNode;
3
5
  key: string;
4
6
  label: string;
5
- icon: ReactNode;
6
- getUrl: (handle: string) => string;
7
7
  }
8
8
  export declare const builtinPlatforms: MentionPlatformDef[];
9
9
  export declare function getAllPlatforms(extra?: MentionPlatformDef[]): MentionPlatformDef[];
@@ -1 +1 @@
1
- {"version":3,"file":"MentionPlatformRegistry.d.ts","sourceRoot":"","sources":["../src/MentionPlatformRegistry.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEtC,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,SAAS,CAAA;IACf,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAA;CACnC;AAED,eAAO,MAAM,gBAAgB,EAAE,kBAAkB,EAO9C,CAAA;AAEH,wBAAgB,eAAe,CAC7B,KAAK,CAAC,EAAE,kBAAkB,EAAE,GAC3B,kBAAkB,EAAE,CAOtB"}
1
+ {"version":3,"file":"MentionPlatformRegistry.d.ts","sourceRoot":"","sources":["../src/MentionPlatformRegistry.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAC;IACnC,IAAI,EAAE,SAAS,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf;AAED,eAAO,MAAM,gBAAgB,EAAE,kBAAkB,EAOhD,CAAC;AAEF,wBAAgB,eAAe,CAAC,KAAK,CAAC,EAAE,kBAAkB,EAAE,GAAG,kBAAkB,EAAE,CAMlF"}
package/dist/index.mjs CHANGED
@@ -3,7 +3,7 @@ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { en
3
3
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
4
  import { MenuOption, useBasicTypeaheadTriggerMatch, LexicalTypeaheadMenuPlugin } from "@lexical/react/LexicalTypeaheadMenuPlugin";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
- import { $createMentionNode } from "@haklex/rich-editor";
6
+ import { $createMentionNode } from "@haklex/rich-editor/nodes";
7
7
  import { PortalThemeWrapper } from "@haklex/rich-style-token";
8
8
  import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
9
9
  import { $createTextNode } from "lexical";
@@ -53,33 +53,26 @@ function MentionMenuList({
53
53
  /* @__PURE__ */ jsx("span", { className: platformTagIcon, children: item.icon }),
54
54
  item.description.split(" — ")[0]
55
55
  ] }),
56
- item.handleText ? /* @__PURE__ */ jsx(
57
- "ul",
56
+ item.handleText ? /* @__PURE__ */ jsx("ul", { role: "listbox", style: { listStyle: "none", margin: 0, padding: 0 }, children: /* @__PURE__ */ jsx(
57
+ "li",
58
58
  {
59
- style: { listStyle: "none", margin: 0, padding: 0 },
60
- role: "listbox",
61
- children: /* @__PURE__ */ jsx(
62
- "li",
63
- {
64
- className: mentionMenuItem,
65
- role: "option",
66
- "aria-selected": selectedIndex === 0,
67
- onClick: () => selectOptionAndCleanUp(item),
68
- onMouseEnter: () => setHighlightedIndex(0),
69
- ref: item.setRefElement,
70
- tabIndex: -1,
71
- style: { margin: 0 },
72
- children: /* @__PURE__ */ jsxs("span", { className: mentionMenuItemText, children: [
73
- /* @__PURE__ */ jsxs("span", { className: mentionMenuItemTitle, children: [
74
- "@",
75
- item.handleText
76
- ] }),
77
- /* @__PURE__ */ jsx("span", { className: mentionMenuItemDescription, children: "Enter to confirm" })
78
- ] })
79
- }
80
- )
59
+ "aria-selected": selectedIndex === 0,
60
+ className: mentionMenuItem,
61
+ ref: item.setRefElement,
62
+ role: "option",
63
+ style: { margin: 0 },
64
+ tabIndex: -1,
65
+ onClick: () => selectOptionAndCleanUp(item),
66
+ onMouseEnter: () => setHighlightedIndex(0),
67
+ children: /* @__PURE__ */ jsxs("span", { className: mentionMenuItemText, children: [
68
+ /* @__PURE__ */ jsxs("span", { className: mentionMenuItemTitle, children: [
69
+ "@",
70
+ item.handleText
71
+ ] }),
72
+ /* @__PURE__ */ jsx("span", { className: mentionMenuItemDescription, children: "Enter to confirm" })
73
+ ] })
81
74
  }
82
- ) : /* @__PURE__ */ jsx("div", { className: phase2Hint, children: "Type username, Enter to confirm" })
75
+ ) }) : /* @__PURE__ */ jsx("div", { className: phase2Hint, children: "Type username, Enter to confirm" })
83
76
  ] }) });
84
77
  }
85
78
  if (options.length === 0) {
@@ -88,13 +81,13 @@ function MentionMenuList({
88
81
  return /* @__PURE__ */ jsx("ul", { className: mentionMenu, role: "listbox", children: options.map((item, index) => /* @__PURE__ */ jsxs(
89
82
  "li",
90
83
  {
84
+ "aria-selected": index === selectedIndex,
91
85
  className: mentionMenuItem,
86
+ ref: item.setRefElement,
92
87
  role: "option",
93
- "aria-selected": index === selectedIndex,
88
+ tabIndex: -1,
94
89
  onClick: () => selectOptionAndCleanUp(item),
95
90
  onMouseEnter: () => setHighlightedIndex(index),
96
- ref: item.setRefElement,
97
- tabIndex: -1,
98
91
  children: [
99
92
  /* @__PURE__ */ jsx("span", { className: mentionMenuItemIcon, children: item.icon }),
100
93
  /* @__PURE__ */ jsxs("span", { className: mentionMenuItemText, children: [
@@ -106,20 +99,19 @@ function MentionMenuList({
106
99
  item.key
107
100
  )) });
108
101
  }
109
- const builtinPlatforms = Object.entries(
110
- platformMetaMap
111
- ).map(([key, meta]) => ({
112
- key,
113
- label: meta.label,
114
- icon: meta.icon,
115
- getUrl: meta.getUrl
116
- }));
102
+ const builtinPlatforms = Object.entries(platformMetaMap).map(
103
+ ([key, meta]) => ({
104
+ key,
105
+ label: meta.label,
106
+ icon: meta.icon,
107
+ getUrl: meta.getUrl
108
+ })
109
+ );
117
110
  function getAllPlatforms(extra) {
118
111
  if (!extra) return builtinPlatforms;
119
112
  const map = /* @__PURE__ */ new Map();
120
113
  for (const p of builtinPlatforms) map.set(p.key.toUpperCase(), p);
121
- for (const p of extra)
122
- map.set(p.key.toUpperCase(), { ...p, key: p.key.toUpperCase() });
114
+ for (const p of extra) map.set(p.key.toUpperCase(), { ...p, key: p.key.toUpperCase() });
123
115
  return [...map.values()];
124
116
  }
125
117
  const MENTION_PUNCTUATION = `\\.,\\+\\*\\?\\$\\@\\|#{}\\(\\)\\^\\-\\[\\]\\\\/!%'"~=<>_;`;
@@ -155,15 +147,10 @@ function parseQueryPhase(query, platforms) {
155
147
  );
156
148
  return { phase: 1, options: filtered };
157
149
  }
158
- function MentionMenuPlugin({
159
- extraPlatforms
160
- } = {}) {
150
+ function MentionMenuPlugin({ extraPlatforms } = {}) {
161
151
  const [editor] = useLexicalComposerContext();
162
152
  const [queryString, setQueryString] = useState(null);
163
- const platforms = useMemo(
164
- () => getAllPlatforms(extraPlatforms),
165
- [extraPlatforms]
166
- );
153
+ const platforms = useMemo(() => getAllPlatforms(extraPlatforms), [extraPlatforms]);
167
154
  const { phase, options } = useMemo(
168
155
  () => parseQueryPhase(queryString ?? "", platforms),
169
156
  [queryString, platforms]
@@ -199,10 +186,8 @@ function MentionMenuPlugin({
199
186
  return /* @__PURE__ */ jsx(
200
187
  LexicalTypeaheadMenuPlugin,
201
188
  {
202
- onQueryChange: setQueryString,
203
- onSelectOption,
204
- triggerFn: checkForTriggerMatch,
205
189
  options,
190
+ triggerFn: checkForTriggerMatch,
206
191
  menuRenderFn: (anchorElementRef, { selectedIndex, selectOptionAndCleanUp, setHighlightedIndex }) => {
207
192
  if (!anchorElementRef.current) return null;
208
193
  if (phase === 1 && options.length === 0) return null;
@@ -211,15 +196,17 @@ function MentionMenuPlugin({
211
196
  MentionMenuList,
212
197
  {
213
198
  options,
214
- selectedIndex,
199
+ phase,
215
200
  selectOptionAndCleanUp,
216
- setHighlightedIndex,
217
- phase
201
+ selectedIndex,
202
+ setHighlightedIndex
218
203
  }
219
204
  ) }),
220
205
  anchorElementRef.current
221
206
  );
222
- }
207
+ },
208
+ onQueryChange: setQueryString,
209
+ onSelectOption
223
210
  }
224
211
  );
225
212
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@haklex/rich-plugin-mention",
3
3
  "type": "module",
4
- "version": "0.0.65",
4
+ "version": "0.0.66",
5
5
  "description": "Mention typeahead plugin with platform selection",
6
6
  "license": "MIT",
7
7
  "exports": {
@@ -22,9 +22,9 @@
22
22
  "react-dom": ">=19"
23
23
  },
24
24
  "dependencies": {
25
- "@haklex/rich-renderer-mention": "0.0.65",
26
- "@haklex/rich-editor": "0.0.65",
27
- "@haklex/rich-style-token": "0.0.65"
25
+ "@haklex/rich-editor": "0.0.66",
26
+ "@haklex/rich-renderer-mention": "0.0.66",
27
+ "@haklex/rich-style-token": "0.0.66"
28
28
  },
29
29
  "devDependencies": {
30
30
  "@lexical/react": "^0.41.0",
@@ -42,6 +42,11 @@
42
42
  "publishConfig": {
43
43
  "access": "public"
44
44
  },
45
+ "repository": {
46
+ "type": "git",
47
+ "url": "https://github.com/Innei/haklex.git",
48
+ "directory": "packages/rich-plugin-mention"
49
+ },
45
50
  "scripts": {
46
51
  "build": "vite build",
47
52
  "dev:build": "vite build --watch"