@actuate-media/cms-admin 0.13.0 → 0.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/dist/__tests__/components/comment-side-panel.test.js +93 -0
  2. package/dist/__tests__/components/comment-side-panel.test.js.map +1 -1
  3. package/dist/__tests__/components/mentionable-textarea.test.d.ts +2 -0
  4. package/dist/__tests__/components/mentionable-textarea.test.d.ts.map +1 -0
  5. package/dist/__tests__/components/mentionable-textarea.test.js +190 -0
  6. package/dist/__tests__/components/mentionable-textarea.test.js.map +1 -0
  7. package/dist/__tests__/lib/mention-picker.test.d.ts +2 -0
  8. package/dist/__tests__/lib/mention-picker.test.d.ts.map +1 -0
  9. package/dist/__tests__/lib/mention-picker.test.js +122 -0
  10. package/dist/__tests__/lib/mention-picker.test.js.map +1 -0
  11. package/dist/actuate-admin.css +1 -1
  12. package/dist/components/CommentSidePanel.d.ts +9 -1
  13. package/dist/components/CommentSidePanel.d.ts.map +1 -1
  14. package/dist/components/CommentSidePanel.js +8 -7
  15. package/dist/components/CommentSidePanel.js.map +1 -1
  16. package/dist/components/MentionableTextarea.d.ts +68 -0
  17. package/dist/components/MentionableTextarea.d.ts.map +1 -0
  18. package/dist/components/MentionableTextarea.js +181 -0
  19. package/dist/components/MentionableTextarea.js.map +1 -0
  20. package/dist/components/NotificationBell.d.ts.map +1 -1
  21. package/dist/components/NotificationBell.js +32 -11
  22. package/dist/components/NotificationBell.js.map +1 -1
  23. package/dist/lib/mention-picker.d.ts +69 -0
  24. package/dist/lib/mention-picker.d.ts.map +1 -0
  25. package/dist/lib/mention-picker.js +138 -0
  26. package/dist/lib/mention-picker.js.map +1 -0
  27. package/package.json +2 -2
  28. package/src/__tests__/components/comment-side-panel.test.tsx +134 -0
  29. package/src/__tests__/components/mentionable-textarea.test.tsx +226 -0
  30. package/src/__tests__/lib/mention-picker.test.ts +145 -0
  31. package/src/components/CommentSidePanel.tsx +37 -14
  32. package/src/components/MentionableTextarea.tsx +328 -0
  33. package/src/components/NotificationBell.tsx +31 -11
  34. package/src/lib/mention-picker.ts +180 -0
@@ -0,0 +1,68 @@
1
+ import React from 'react';
2
+ import { type MentionUser } from '../lib/mention-picker.js';
3
+ /**
4
+ * `<MentionableTextarea />` — drop-in replacement for `<textarea>` /
5
+ * `<input type="text">` that opens a Radix-styled mention picker
6
+ * whenever the user types `@`.
7
+ *
8
+ * Behaviour
9
+ * ─────────
10
+ * - The picker appears anchored to the textarea, below the input.
11
+ * We intentionally do NOT track the caret pixel position (that
12
+ * requires a textarea-mirror trick which doesn't add enough UX to
13
+ * justify the complexity); GitHub, Linear, and Asana all anchor
14
+ * their pickers this way on simple textareas.
15
+ * - Arrow Up / Arrow Down move the highlight. Enter / Tab commit the
16
+ * selection. Escape closes the picker without inserting anything.
17
+ * Mouse click on a row also commits.
18
+ * - The picker only fires server queries while a real mention is
19
+ * being typed; it short-circuits an empty `query` so the dropdown
20
+ * shows up immediately after `@` is typed (with an empty state)
21
+ * and only flips to "no matches" once the user has typed at least
22
+ * one character.
23
+ * - The textarea value is fully controlled by the parent — we never
24
+ * keep a separate copy. `onChange` is called with the next value
25
+ * on every keystroke AND every mention insertion.
26
+ *
27
+ * Dependency-injection seam
28
+ * ─────────────────────────
29
+ * The `search` prop accepts an override so tests can substitute a
30
+ * synchronous fake. Production callers leave it unset and the
31
+ * component uses the real `searchMentionUsers()` REST helper.
32
+ */
33
+ export interface MentionableTextareaProps {
34
+ value: string;
35
+ onChange: (next: string) => void;
36
+ /** Forwarded to the underlying textarea. */
37
+ placeholder?: string;
38
+ /** Forwarded to the underlying textarea. */
39
+ rows?: number;
40
+ className?: string;
41
+ /** Forwarded — useful for keyboard shortcuts the parent owns. */
42
+ onKeyDown?: (event: React.KeyboardEvent<HTMLTextAreaElement>) => void;
43
+ /** Forwarded — useful for click-to-stop-propagation in nested cards. */
44
+ onClick?: (event: React.MouseEvent<HTMLTextAreaElement>) => void;
45
+ /** Test hook — required when rendering with React state assertions. */
46
+ 'data-testid'?: string;
47
+ /**
48
+ * Override the user search. The default uses the REST helper.
49
+ * Tests inject an in-memory fake so dropdown contents are
50
+ * deterministic without HTTP mocking.
51
+ */
52
+ search?: (query: string) => Promise<MentionUser[]>;
53
+ /**
54
+ * Optional fixed id for the picker dropdown — pass when the parent
55
+ * wires up `aria-controls`. We generate one with `useId()` when
56
+ * unset.
57
+ */
58
+ pickerId?: string;
59
+ /**
60
+ * Format the displayed token. By default we show `@<name>` while
61
+ * the underlying value stores `@<userId>`. A future slice can swap
62
+ * to a rich-text editor where these diverge; the prop lets that
63
+ * land without changing the picker.
64
+ */
65
+ formatLabel?: (user: MentionUser) => string;
66
+ }
67
+ export declare function MentionableTextarea({ value, onChange, placeholder, rows, className, onKeyDown, onClick, 'data-testid': testId, search, pickerId: pickerIdProp, formatLabel, }: MentionableTextareaProps): React.JSX.Element;
68
+ //# sourceMappingURL=MentionableTextarea.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MentionableTextarea.d.ts","sourceRoot":"","sources":["../../src/components/MentionableTextarea.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA0D,MAAM,OAAO,CAAA;AAE9E,OAAO,EACL,KAAK,WAAW,EAIjB,MAAM,0BAA0B,CAAA;AAEjC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,WAAW,wBAAwB;IACvC,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAChC,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,4CAA4C;IAC5C,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,iEAAiE;IACjE,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,aAAa,CAAC,mBAAmB,CAAC,KAAK,IAAI,CAAA;IACrE,wEAAwE;IACxE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,UAAU,CAAC,mBAAmB,CAAC,KAAK,IAAI,CAAA;IAChE,uEAAuE;IACvE,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;;OAIG;IACH,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,WAAW,EAAE,CAAC,CAAA;IAClD;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,MAAM,CAAA;CAC5C;AAgBD,wBAAgB,mBAAmB,CAAC,EAClC,KAAK,EACL,QAAQ,EACR,WAAW,EACX,IAAQ,EACR,SAAS,EACT,SAAS,EACT,OAAO,EACP,aAAa,EAAE,MAAM,EACrB,MAAyE,EACzE,QAAQ,EAAE,YAAY,EACtB,WAAiC,GAClC,EAAE,wBAAwB,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAiO9C"}
@@ -0,0 +1,181 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useCallback, useEffect, useId, useRef, useState } from 'react';
4
+ import { detectMentionContext, insertMentionToken, searchMentionUsers, } from '../lib/mention-picker.js';
5
+ const initialPicker = {
6
+ open: false,
7
+ query: '',
8
+ highlight: 0,
9
+ users: [],
10
+ };
11
+ export function MentionableTextarea({ value, onChange, placeholder, rows = 3, className, onKeyDown, onClick, 'data-testid': testId, search = (q) => searchMentionUsers(q).then((r) => (r.ok ? r.result : [])), pickerId: pickerIdProp, formatLabel = (u) => `@${u.name}`, }) {
12
+ const generatedId = useId();
13
+ const pickerId = pickerIdProp ?? `actuate-mention-picker-${generatedId}`;
14
+ const textareaRef = useRef(null);
15
+ const [picker, setPicker] = useState(initialPicker);
16
+ // `pickerRef` mirrors `picker` for the keydown handler so the
17
+ // arrow-key / enter listeners don't go stale between renders.
18
+ const pickerRef = useRef(picker);
19
+ useEffect(() => {
20
+ pickerRef.current = picker;
21
+ }, [picker]);
22
+ const requestSeq = useRef(0);
23
+ const mountedRef = useRef(true);
24
+ useEffect(() => {
25
+ return () => {
26
+ mountedRef.current = false;
27
+ };
28
+ }, []);
29
+ const closePicker = useCallback(() => {
30
+ setPicker((p) => (p.open ? initialPicker : p));
31
+ }, []);
32
+ // Recompute the active mention context whenever the value or
33
+ // selection changes. Centralising this in one effect keeps the
34
+ // open/close logic in a single place — every textarea event
35
+ // (input, click, keyup) just calls `recompute()`.
36
+ const recompute = useCallback(async (nextValue, caret) => {
37
+ const ctx = detectMentionContext(nextValue, caret);
38
+ if (!ctx) {
39
+ closePicker();
40
+ return;
41
+ }
42
+ const id = ++requestSeq.current;
43
+ // Open immediately so the user sees a dropdown the moment they
44
+ // type `@`. Clear the `users` array on every new query so the
45
+ // user can never press Enter / Tab and commit a stale row
46
+ // from the previous query while the new request is in flight
47
+ // (PR #159 Copilot finding — type `@a` then `@bo` quickly and
48
+ // hit Enter before the `@bo` results arrive: without this
49
+ // reset, the picker would commit a row from `@a`).
50
+ setPicker((p) => ({
51
+ open: true,
52
+ query: ctx.query,
53
+ highlight: 0,
54
+ users: p.query === ctx.query ? p.users : [],
55
+ }));
56
+ try {
57
+ const users = await search(ctx.query);
58
+ if (!mountedRef.current)
59
+ return;
60
+ // Drop stale responses — only commit if our request is still
61
+ // the latest one. Otherwise the user has typed more and a
62
+ // newer query is in flight.
63
+ if (id !== requestSeq.current)
64
+ return;
65
+ setPicker((p) =>
66
+ // If the picker was closed (Escape) between request and
67
+ // response, don't reopen it.
68
+ p.open ? { ...p, users, highlight: 0 } : p);
69
+ }
70
+ catch {
71
+ if (!mountedRef.current)
72
+ return;
73
+ if (id !== requestSeq.current)
74
+ return;
75
+ // Surface no rows on failure — the textarea must keep
76
+ // working when the user is offline. The poll loop / native
77
+ // submit path is unaffected.
78
+ setPicker((p) => (p.open ? { ...p, users: [] } : p));
79
+ }
80
+ }, [closePicker, search]);
81
+ const commitMention = useCallback((user) => {
82
+ const el = textareaRef.current;
83
+ if (!el)
84
+ return;
85
+ const caret = el.selectionStart ?? value.length;
86
+ const ctx = detectMentionContext(value, caret);
87
+ if (!ctx) {
88
+ closePicker();
89
+ return;
90
+ }
91
+ const next = insertMentionToken(value, ctx, user.id);
92
+ onChange(next.value);
93
+ closePicker();
94
+ // Move the caret past the inserted token AFTER React paints
95
+ // the new value, so the selection isn't clobbered by the
96
+ // controlled update.
97
+ requestAnimationFrame(() => {
98
+ const live = textareaRef.current;
99
+ if (!live)
100
+ return;
101
+ live.focus();
102
+ live.setSelectionRange(next.caret, next.caret);
103
+ });
104
+ }, [closePicker, onChange, value]);
105
+ const handleChange = (event) => {
106
+ const next = event.target.value;
107
+ const caret = event.target.selectionStart ?? next.length;
108
+ onChange(next);
109
+ void recompute(next, caret);
110
+ };
111
+ const handleKeyDown = (event) => {
112
+ const p = pickerRef.current;
113
+ if (p.open && p.users.length > 0) {
114
+ if (event.key === 'ArrowDown') {
115
+ event.preventDefault();
116
+ setPicker((s) => ({ ...s, highlight: (s.highlight + 1) % s.users.length }));
117
+ return;
118
+ }
119
+ if (event.key === 'ArrowUp') {
120
+ event.preventDefault();
121
+ setPicker((s) => ({
122
+ ...s,
123
+ highlight: (s.highlight - 1 + s.users.length) % s.users.length,
124
+ }));
125
+ return;
126
+ }
127
+ if (event.key === 'Enter' || event.key === 'Tab') {
128
+ event.preventDefault();
129
+ // Defensive: highlight could theoretically point past the
130
+ // end of `users` if state went stale between renders. Guard
131
+ // it so we never `undefined`-bang.
132
+ const target = p.users[p.highlight];
133
+ if (target)
134
+ commitMention(target);
135
+ return;
136
+ }
137
+ }
138
+ if (event.key === 'Escape' && p.open) {
139
+ event.preventDefault();
140
+ closePicker();
141
+ return;
142
+ }
143
+ onKeyDown?.(event);
144
+ };
145
+ const handleClick = (event) => {
146
+ onClick?.(event);
147
+ const el = textareaRef.current;
148
+ if (!el)
149
+ return;
150
+ void recompute(el.value, el.selectionStart ?? el.value.length);
151
+ };
152
+ // Closing on outside click — when the user clicks anywhere outside
153
+ // the textarea or the picker, the dropdown should disappear so it
154
+ // doesn't sit on top of unrelated UI.
155
+ useEffect(() => {
156
+ if (!picker.open)
157
+ return;
158
+ const onDocMouseDown = (ev) => {
159
+ const t = ev.target;
160
+ if (!t)
161
+ return;
162
+ const parent = textareaRef.current?.parentElement;
163
+ if (parent && parent.contains(t))
164
+ return;
165
+ closePicker();
166
+ };
167
+ document.addEventListener('mousedown', onDocMouseDown);
168
+ return () => document.removeEventListener('mousedown', onDocMouseDown);
169
+ }, [picker.open, closePicker]);
170
+ return (_jsxs("div", { className: "relative", children: [_jsx("textarea", { ref: textareaRef, value: value, onChange: handleChange, onKeyDown: handleKeyDown, onClick: handleClick, placeholder: placeholder, rows: rows, className: className, "aria-autocomplete": "list", "aria-controls": picker.open ? pickerId : undefined, "aria-expanded": picker.open, "data-testid": testId }), picker.open && (_jsx("div", { id: pickerId, role: "listbox", "aria-label": "Mention a teammate", className: "absolute top-full left-0 z-30 mt-1 max-h-56 w-64 overflow-y-auto rounded border border-gray-200 bg-white shadow-lg", "data-testid": testId ? `${testId}-picker` : 'mention-picker', children: picker.users.length === 0 ? (_jsx("p", { className: "px-3 py-2 text-xs text-gray-500", children: picker.query ? 'No matches' : 'Type a name…' })) : (_jsx("ul", { children: picker.users.map((u, idx) => (_jsx("li", { children: _jsxs("button", { type: "button", role: "option", "aria-selected": idx === picker.highlight, onMouseDown: (e) => {
171
+ // mousedown (not click) — prevents the
172
+ // textarea from losing focus before we
173
+ // commit, which would otherwise hide the
174
+ // selection and feel janky.
175
+ e.preventDefault();
176
+ commitMention(u);
177
+ }, onMouseEnter: () => setPicker((s) => ({ ...s, highlight: idx })), className: `block w-full px-3 py-1.5 text-left text-xs ${idx === picker.highlight
178
+ ? 'bg-blue-50 text-blue-900'
179
+ : 'text-gray-800 hover:bg-gray-50'}`, "data-testid": testId ? `${testId}-picker-row-${u.id}` : `mention-row-${u.id}`, children: [_jsx("div", { className: "font-medium", children: formatLabel(u) }), _jsx("div", { className: "text-[10px] text-gray-500", children: u.email })] }) }, u.id))) })) }))] }));
180
+ }
181
+ //# sourceMappingURL=MentionableTextarea.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MentionableTextarea.js","sourceRoot":"","sources":["../../src/components/MentionableTextarea.tsx"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"NotificationBell.d.ts","sourceRoot":"","sources":["../../src/components/NotificationBell.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAmD,MAAM,OAAO,CAAA;AAEvE,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,mBAAmB,EACxB,KAAK,wBAAwB,EAC7B,KAAK,yBAAyB,EAO/B,MAAM,gCAAgC,CAAA;AAEvC;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,CAAC,IAAI,EAAE;QAAE,WAAW,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC,mBAAmB,CAAC,YAAY,EAAE,CAAC,CAAC,CAAA;IACvF,MAAM,EAAE,MAAM,OAAO,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC,CAAA;IAClD,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,mBAAmB,CAAC,YAAY,CAAC,CAAC,CAAA;IACpE,WAAW,EAAE,MAAM,OAAO,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC,CAAA;IACvD;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,yBAAyB,KAAK,wBAAwB,CAAA;CAC1E;AAUD,MAAM,WAAW,qBAAqB;IACpC;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,gFAAgF;IAChF,QAAQ,CAAC,EAAE,CAAC,YAAY,EAAE,YAAY,KAAK,IAAI,CAAA;IAC/C,+DAA+D;IAC/D,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;IACnC,uCAAuC;IACvC,GAAG,CAAC,EAAE,gBAAgB,CAAA;IACtB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,cAAuB,EACvB,QAAQ,EACR,OAAO,EACP,GAAgB,EAChB,SAAS,GACV,EAAE,qBAAqB,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAyM3C"}
1
+ {"version":3,"file":"NotificationBell.d.ts","sourceRoot":"","sources":["../../src/components/NotificationBell.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAmD,MAAM,OAAO,CAAA;AAEvE,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,mBAAmB,EACxB,KAAK,wBAAwB,EAC7B,KAAK,yBAAyB,EAO/B,MAAM,gCAAgC,CAAA;AAEvC;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,CAAC,IAAI,EAAE;QAAE,WAAW,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC,mBAAmB,CAAC,YAAY,EAAE,CAAC,CAAC,CAAA;IACvF,MAAM,EAAE,MAAM,OAAO,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC,CAAA;IAClD,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,mBAAmB,CAAC,YAAY,CAAC,CAAC,CAAA;IACpE,WAAW,EAAE,MAAM,OAAO,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC,CAAA;IACvD;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,yBAAyB,KAAK,wBAAwB,CAAA;CAC1E;AAUD,MAAM,WAAW,qBAAqB;IACpC;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,gFAAgF;IAChF,QAAQ,CAAC,EAAE,CAAC,YAAY,EAAE,YAAY,KAAK,IAAI,CAAA;IAC/C,+DAA+D;IAC/D,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;IACnC,uCAAuC;IACvC,GAAG,CAAC,EAAE,gBAAgB,CAAA;IACtB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,cAAuB,EACvB,QAAQ,EACR,OAAO,EACP,GAAgB,EAChB,SAAS,GACV,EAAE,qBAAqB,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CA6N3C"}
@@ -18,12 +18,18 @@ export function NotificationBell({ pollIntervalMs = 60_000, onSelect, onError, a
18
18
  // Set of notification IDs we've already rendered. The SSE handler
19
19
  // consults this synchronously so duplicate deliveries (REST refresh
20
20
  // + SSE push, or two SSE retries) don't double-bump the badge.
21
- // Kept in sync with `items` via an effect — the items state is the
22
- // source of truth; this ref is a derived O(1) lookup index.
21
+ //
22
+ // The ref is updated **synchronously** at every call site that
23
+ // changes the set of items (REST refresh, SSE push, dropdown clear).
24
+ // A prior implementation reconciled it via `useEffect([items])`,
25
+ // but that effect runs *after* React commits — so an SSE push that
26
+ // arrives between the REST list resolving (`items` mutated) and the
27
+ // effect running would read a stale ref, fall through the
28
+ // de-dup gate, and append a duplicate row. The reproducible
29
+ // regression was caught by the test
30
+ // `does not double-count a notification that arrives via both
31
+ // SSE and REST`.
23
32
  const seenIdsRef = useRef(new Set());
24
- useEffect(() => {
25
- seenIdsRef.current = new Set(items.map((n) => n.id));
26
- }, [items]);
27
33
  useEffect(() => {
28
34
  return () => {
29
35
  mountedRef.current = false;
@@ -47,9 +53,11 @@ export function NotificationBell({ pollIntervalMs = 60_000, onSelect, onError, a
47
53
  if (!out.ok) {
48
54
  onError?.(out.error);
49
55
  setItems([]);
56
+ seenIdsRef.current = new Set();
50
57
  }
51
58
  else {
52
59
  setItems(out.result);
60
+ seenIdsRef.current = new Set(out.result.map((n) => n.id));
53
61
  }
54
62
  setLoading(false);
55
63
  }, [api, onError]);
@@ -71,15 +79,28 @@ export function NotificationBell({ pollIntervalMs = 60_000, onSelect, onError, a
71
79
  onNotification: (n) => {
72
80
  if (!mountedRef.current)
73
81
  return;
74
- // Defensive: SSE events can race with REST refreshes (or with
75
- // their own retries). The seen-id ref is updated
76
- // synchronously so a second delivery of the same row is a
77
- // no-op for BOTH `items` and the unread badge — guarding only
78
- // setItems would still let the counter drift.
82
+ // SSE events can race with REST refreshes (or with their own
83
+ // retries). Two gates close the door on duplicates:
84
+ // 1. **Synchronous ref check** fast-path that also
85
+ // gates the unread badge bump, so a second delivery of
86
+ // the same row never drifts the counter. The ref is
87
+ // maintained synchronously by `refreshList` so the
88
+ // check sees a consistent snapshot.
89
+ // 2. **Inner setItems check** — final safety net. The
90
+ // updater sees the latest `arr` snapshot React has
91
+ // queued, which may differ from the ref if a
92
+ // `refreshList` resolved between this handler's ref
93
+ // read and the updater running. Without it, an
94
+ // interleaved REST refresh could leave `items` with a
95
+ // duplicate row.
79
96
  if (seenIdsRef.current.has(n.id))
80
97
  return;
81
98
  seenIdsRef.current.add(n.id);
82
- setItems((arr) => [n, ...arr]);
99
+ setItems((arr) => {
100
+ if (arr.some((existing) => existing.id === n.id))
101
+ return arr;
102
+ return [n, ...arr];
103
+ });
83
104
  if (!n.readAt)
84
105
  setUnread((v) => v + 1);
85
106
  },
@@ -1 +1 @@
1
- {"version":3,"file":"NotificationBell.js","sourceRoot":"","sources":["../../src/components/NotificationBell.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"NotificationBell.js","sourceRoot":"","sources":["../../src/components/NotificationBell.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,69 @@
1
+ export interface MentionUser {
2
+ id: string;
3
+ name: string;
4
+ email: string;
5
+ }
6
+ export type MentionSearchOutcome = {
7
+ ok: true;
8
+ result: MentionUser[];
9
+ } | {
10
+ ok: false;
11
+ error: string;
12
+ status: number;
13
+ };
14
+ export declare function searchMentionUsers(query: string): Promise<MentionSearchOutcome>;
15
+ /**
16
+ * Description of an active `@`-mention being typed in a textarea / input.
17
+ *
18
+ * - `start` and `end` are character offsets into the field value: the
19
+ * `@` itself sits at `start`, and `end` is the caret position
20
+ * (exclusive end of the query slice).
21
+ * - `query` is the substring between the `@` and the caret — exactly
22
+ * what we should pass to `searchMentionUsers()`.
23
+ *
24
+ * Callers replace `value.slice(start, end)` with the chosen token
25
+ * (`@<userId> `, including the trailing space) to commit a selection.
26
+ */
27
+ export interface MentionContext {
28
+ start: number;
29
+ end: number;
30
+ query: string;
31
+ }
32
+ /**
33
+ * Find an active mention at the caret. Mirrors the server-side
34
+ * `extractMentionedUserIds` regex
35
+ * (`/(^|\s)@[a-zA-Z0-9_-]{3,64}\b/g`) so the picker's intuition
36
+ * about what counts as a mention can never disagree with the
37
+ * server's notification routing.
38
+ *
39
+ * Returns `null` whenever:
40
+ * - the caret is at offset 0,
41
+ * - there is no `@` between the caret and the previous whitespace
42
+ * boundary,
43
+ * - the `@` is preceded by a non-whitespace, non-newline character
44
+ * (so an email address mid-word like `foo@bar` does NOT open
45
+ * the picker), or
46
+ * - the candidate query contains a character outside the mention
47
+ * charset (`[a-zA-Z0-9_-]`).
48
+ *
49
+ * The picker DOES open with a 0–2 character query — that's the
50
+ * "you've started typing a mention" UX. But it can NEVER commit
51
+ * such a token: `insertMentionToken` only fires for a `MentionUser`
52
+ * which always has an id of at least 3 chars, matching the server
53
+ * regex's min-length requirement.
54
+ */
55
+ export declare function detectMentionContext(value: string, caret: number): MentionContext | null;
56
+ /**
57
+ * Apply a mention selection to a text value. Returns the new value
58
+ * plus the caret position where the next keystroke should land.
59
+ *
60
+ * Inserts `@<userId> ` (trailing space) so the user can keep typing
61
+ * without manually moving the cursor past the token. If the caret
62
+ * already sits before a space, we don't insert a duplicate space.
63
+ */
64
+ export interface MentionInsertion {
65
+ value: string;
66
+ caret: number;
67
+ }
68
+ export declare function insertMentionToken(value: string, context: MentionContext, userId: string): MentionInsertion;
69
+ //# sourceMappingURL=mention-picker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mention-picker.d.ts","sourceRoot":"","sources":["../../src/lib/mention-picker.ts"],"names":[],"mappings":"AAuBA,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;CACd;AAED,MAAM,MAAM,oBAAoB,GAC5B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,WAAW,EAAE,CAAA;CAAE,GACnC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAEhD,wBAAsB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAerF;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;CACd;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAiCxF;AAwBD;;;;;;;GAOG;AACH,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;CACd;AAED,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,cAAc,EACvB,MAAM,EAAE,MAAM,GACb,gBAAgB,CAclB"}
@@ -0,0 +1,138 @@
1
+ /**
2
+ * Mention picker client logic + REST helper.
3
+ *
4
+ * Two responsibilities, deliberately separated so each can be unit
5
+ * tested without rendering React or hitting fetch:
6
+ *
7
+ * 1. `searchMentionUsers(query)` — typed wrapper over the new
8
+ * `GET /api/cms/users/search` endpoint introduced in Phase 7.
9
+ * Returns up to 10 `{ id, name, email }` rows matching the query.
10
+ * 2. `detectMentionContext(value, caret)` — pure parser that scans a
11
+ * text input value backwards from the caret to decide whether the
12
+ * user is currently typing a `@`-mention, and if so what the
13
+ * query fragment is. Returns `null` when no active mention.
14
+ *
15
+ * Wire format note: the picker INSERTS `@<userId>` tokens at the
16
+ * cursor (matching the server-side `extractMentionedUserIds` regex
17
+ * in `cms-core/realtime/notifications.ts`). The user sees the chosen
18
+ * user's *name* in the picker but the textarea always holds the id.
19
+ * Rendering names back in the comment view is a separate slice that
20
+ * can ship later without breaking the wire format.
21
+ */
22
+ import { cmsApi } from './api.js';
23
+ export async function searchMentionUsers(query) {
24
+ const trimmed = query.trim();
25
+ if (trimmed.length === 0) {
26
+ // Mirror the server's contract: an empty query returns an empty
27
+ // array. We short-circuit here so the picker doesn't spend a
28
+ // round-trip on a guaranteed-empty response.
29
+ return { ok: true, result: [] };
30
+ }
31
+ const res = await cmsApi(`/users/search?q=${encodeURIComponent(trimmed)}`, {
32
+ method: 'GET',
33
+ });
34
+ if (res.error || !res.data) {
35
+ return { ok: false, error: res.error ?? `Request failed (${res.status})`, status: res.status };
36
+ }
37
+ return { ok: true, result: res.data };
38
+ }
39
+ /**
40
+ * Find an active mention at the caret. Mirrors the server-side
41
+ * `extractMentionedUserIds` regex
42
+ * (`/(^|\s)@[a-zA-Z0-9_-]{3,64}\b/g`) so the picker's intuition
43
+ * about what counts as a mention can never disagree with the
44
+ * server's notification routing.
45
+ *
46
+ * Returns `null` whenever:
47
+ * - the caret is at offset 0,
48
+ * - there is no `@` between the caret and the previous whitespace
49
+ * boundary,
50
+ * - the `@` is preceded by a non-whitespace, non-newline character
51
+ * (so an email address mid-word like `foo@bar` does NOT open
52
+ * the picker), or
53
+ * - the candidate query contains a character outside the mention
54
+ * charset (`[a-zA-Z0-9_-]`).
55
+ *
56
+ * The picker DOES open with a 0–2 character query — that's the
57
+ * "you've started typing a mention" UX. But it can NEVER commit
58
+ * such a token: `insertMentionToken` only fires for a `MentionUser`
59
+ * which always has an id of at least 3 chars, matching the server
60
+ * regex's min-length requirement.
61
+ */
62
+ export function detectMentionContext(value, caret) {
63
+ if (typeof value !== 'string')
64
+ return null;
65
+ if (caret <= 0 || caret > value.length)
66
+ return null;
67
+ // Walk back from the caret looking for a `@`. Stop early on any
68
+ // character that is neither a valid mention char nor `@`. This
69
+ // means a typed space, newline, punctuation, etc. terminates the
70
+ // mention candidate the user was building.
71
+ let i = caret - 1;
72
+ while (i >= 0) {
73
+ const ch = value.charCodeAt(i);
74
+ if (ch === 64 /* @ */)
75
+ break;
76
+ if (!isMentionChar(ch))
77
+ return null;
78
+ i -= 1;
79
+ }
80
+ if (i < 0)
81
+ return null;
82
+ // The `@` must sit at the start of the field or be preceded by
83
+ // whitespace / newline. Otherwise we're mid-word (think `foo@bar`),
84
+ // which is not a mention.
85
+ if (i > 0) {
86
+ const prev = value.charCodeAt(i - 1);
87
+ if (!isBoundary(prev))
88
+ return null;
89
+ }
90
+ const query = value.slice(i + 1, caret);
91
+ // Server caps queries at 64 chars; the picker simply stops
92
+ // suggesting once the typed query exceeds that — extra typing
93
+ // closes the picker so the user can complete an email or other
94
+ // long token without staring at a dead dropdown.
95
+ if (query.length > 64)
96
+ return null;
97
+ return { start: i, end: caret, query };
98
+ }
99
+ function isMentionChar(code) {
100
+ // [a-zA-Z0-9_-] — keep this in lock-step with the regex in
101
+ // `cms-core/realtime/notifications.ts:extractMentionedUserIds`.
102
+ if (code === 95 /* _ */ || code === 45 /* - */)
103
+ return true;
104
+ if (code >= 48 && code <= 57)
105
+ return true; // 0-9
106
+ if (code >= 65 && code <= 90)
107
+ return true; // A-Z
108
+ if (code >= 97 && code <= 122)
109
+ return true; // a-z
110
+ return false;
111
+ }
112
+ function isBoundary(code) {
113
+ // ASCII space, tab, line-feed, or carriage-return. We deliberately
114
+ // do NOT widen this to the full Unicode whitespace class — the
115
+ // server-side `extractMentionedUserIds` regex in
116
+ // `cms-core/realtime/notifications.ts` uses `\s` which DOES match
117
+ // Unicode whitespace, but its `^` anchor means the only realistic
118
+ // mid-string boundaries in practice are these four ASCII chars
119
+ // (a CMS comment body containing U+00A0 NBSP before an `@` would
120
+ // be both unusual and not worth opening the picker for).
121
+ return code === 32 || code === 9 || code === 10 || code === 13;
122
+ }
123
+ export function insertMentionToken(value, context, userId) {
124
+ const hasTrailingSpace = value.charAt(context.end) === ' ';
125
+ // If the user already has a space immediately after the mention
126
+ // region, reuse it (don't double-space) but still advance the
127
+ // caret past that space so the next keystroke continues naturally
128
+ // rather than landing back in front of the space.
129
+ const trailingSpace = hasTrailingSpace ? '' : ' ';
130
+ const token = `@${userId}${trailingSpace}`;
131
+ const before = value.slice(0, context.start);
132
+ const after = value.slice(context.end);
133
+ return {
134
+ value: `${before}${token}${after}`,
135
+ caret: context.start + token.length + (hasTrailingSpace ? 1 : 0),
136
+ };
137
+ }
138
+ //# sourceMappingURL=mention-picker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mention-picker.js","sourceRoot":"","sources":["../../src/lib/mention-picker.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@actuate-media/cms-admin",
3
- "version": "0.13.0",
3
+ "version": "0.14.1",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/actuate-media/actuatecms.git",
@@ -87,7 +87,7 @@
87
87
  "tailwindcss": "^4.0.0",
88
88
  "typescript": "^5.7.0",
89
89
  "vitest": "^3.0.0",
90
- "@actuate-media/cms-core": "0.24.0",
90
+ "@actuate-media/cms-core": "0.25.1",
91
91
  "@actuate-media/component-blocks": "0.2.0"
92
92
  },
93
93
  "scripts": {