@edux-design/comments 0.1.4 → 0.2.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.
@@ -0,0 +1,65 @@
1
+ # Comment composer
2
+
3
+ `CommentComposer` owns the editor presentation and accessible interactions. The host owns comment transport, authorisation, discussion threads, mention lookup and request status.
4
+
5
+ ## Values and mentions
6
+
7
+ The existing `value` string and `onChange({ target: { value } })` contract remains available. Legacy `onChange` continues to use Tiptap `getText()`: mentions are `@handle` (or `@label`, then `@mention` when neither exists). The new snapshot's `text` uses the full visible mention label `@handle · Name`, suitable for Payload's existing transport body. Plain-text echoes of either form preserve mention nodes and the selection.
8
+
9
+ `valueFormat="html"` is the backward-compatible default for string input. Set `valueFormat="text"` for literal application text (so `<em>text</em>` remains literal text), and use `richValue` JSON to restore rich drafts. Treating untrusted strings as HTML should be a deliberate host decision.
10
+
11
+ Use `onValueChange` for a complete editor snapshot:
12
+
13
+ ```jsx
14
+ <CommentComposer
15
+ value={text}
16
+ onChange={(event) => setText(event.target.value)}
17
+ onValueChange={({ text, html, json, mentions, isEmpty }) =>
18
+ saveDraft({ text, json, mentions })
19
+ }
20
+ />
21
+ ```
22
+
23
+ The snapshot has normalised `text`, original `legacyText`, serialised `html`, Tiptap `json`, ordered `mentions` (`{ id, handle, label }`; IDs retain their original string/number type or null), and `isEmpty`. Mentions are read from the document model, including immediately after insertion; no DOM selector, MutationObserver or node-view timing workaround is needed. Snapshot `text` replaces NBSP with ordinary space, removes U+200B–U+200D/U+FEFF and replaces each model line break with one space; it does not trim. Visual node-view layout does not add artificial line breaks. Duplicate mentions remain separate occurrences. Snapshot HTML is editor output, not a general-purpose sanitiser for untrusted HTML.
24
+
25
+ Use `richValue` with the snapshot's JSON to restore/drive a rich draft without losing mention identities. If both `richValue` and `value` are provided, `richValue` takes precedence. The composer recognises echoes of the most recent 100 model transactions so normal batched/debounced parent updates do not overwrite newer keystrokes; older updates are treated as explicit controlled replacements. This history is bounded even when an observing host never echoes values. Controlled prop replacements do not emit change callbacks. Editor edits and public `clear()` do. An omitted value is uncontrolled and an initially empty editor disables submission.
26
+
27
+ ## Focus and refs
28
+
29
+ The existing forwarded `ref` still points to the editor's wrapping `HTMLDivElement`. Add `composerRef` for a `CommentComposerHandle`:
30
+
31
+ | Method | Behaviour |
32
+ | ------------------------- | ------------------------------------------------------------------------------------------------------- |
33
+ | `focus(position = 'end')` | Focus the editor at `start`, `end`, `all` or a numeric document position; return success. |
34
+ | `clear()` | Clear content and emit value callbacks; return success. Controlled hosts should echo the cleared value. |
35
+ | `getValue()` | Return a current `CommentComposerValue`, or `null` before the editor is ready. |
36
+ | `submit()` | Request normal form submission using the same empty/disabled/pending guard as the internal button. |
37
+
38
+ `editorLabel` keeps the published default “Comment”; Payload can pass “Write a comment” and labels the multiline textbox directly. `editorAttributes` forwards editable `id`, `aria-describedby`, `aria-invalid` and `aria-required`, including runtime updates. `autoFocus` is opt-in and schedules focus after editor readiness/on re-enabling, with frame cleanup on unmount. Imperative focus requests made before editor readiness are queued. Disabled/pending composers reject focus, clear and submit operations and prevent editing. `getValue` remains available for reading a pending draft. The form exposes `aria-busy` while `isSubmitting` is true. `submittingLabel` defaults to “Posting...” and supports context-specific pending labels.
39
+
40
+ ## External submit
41
+
42
+ ```jsx
43
+ const composerRef = useRef(null);
44
+
45
+ <CommentComposer
46
+ id="reply"
47
+ composerRef={composerRef}
48
+ externalSubmit
49
+ submitOnModEnter
50
+ editorLabel="Reply to this thread"
51
+ valueFormat="text"
52
+ value={text}
53
+ onValueChange={(value) => setText(value.text)}
54
+ onSubmit={(event) => sendReply(composerRef.current.getValue())}
55
+ />
56
+ <Button form="reply" type="submit">Send reply</Button>
57
+ ```
58
+
59
+ `externalSubmit` omits only the built-in submit button. Cancellation and action slots remain usable. Associate a native submit button with the form `id`, or call `composerRef.current.submit()`. All routes preserve `onSubmit`'s form event and call `preventDefault` before handing control to the host. The opt-in `submitOnModEnter` enables Control/Command+Enter without overriding ordinary Enter or composition. The native `onKeyDown` handler is composed once before this shortcut, so either it or `onKeyDownCapture` can prevent the package action.
60
+
61
+ ## Layout and theme
62
+
63
+ The default editor remains 120px high; `rows` sets 30px per row. Colour modes use existing semantic tokens; root padding, border widths and editor height are unchanged when themes switch. The editor transition respects reduced motion. The host supplies the panel width; no portal, application focus trap or transport logic is added. Supply React 19 and the package's declared Tiptap 3 peers consistently.
64
+
65
+ Storybook includes basic text submission, mention insertion, external submission/focus, rich drafts, disabled/pending states, narrow layout and light/dark colour modes. Interaction plays exercise the real editor, rapid controlled typing, accessible menu selection/Escape, and host-controlled failure/retry without clearing a failed draft.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@edux-design/comments",
3
- "version": "0.1.4",
3
+ "version": "0.2.0",
4
4
  "private": false,
5
5
  "sideEffects": [
6
6
  "**/*.css"
@@ -8,30 +8,11 @@
8
8
  "types": "./dist/index.d.ts",
9
9
  "exports": {
10
10
  ".": {
11
+ "types": "./dist/index.d.ts",
11
12
  "import": "./dist/index.mjs",
12
- "require": "./dist/index.js",
13
- "types": "./dist/index.d.ts"
13
+ "require": "./dist/index.js"
14
14
  }
15
15
  },
16
- "scripts": {
17
- "lint": "eslint . --max-warnings 0",
18
- "build": "tsup src/index.js --format esm,cjs --dts",
19
- "dev": "tsup src/index.js --watch --format esm,cjs --dts",
20
- "generate:component": "turbo gen react-component",
21
- "check-types": "tsc --noEmit"
22
- },
23
- "devDependencies": {
24
- "typescript": "^5.9.2",
25
- "tailwindcss": "^4.1.12",
26
- "postcss": "^8.5.6",
27
- "tsup": "^8.5.0",
28
- "@tailwindcss/cli": "^4.1.12",
29
- "@tailwindcss/postcss": "^4.1.12",
30
- "@tiptap/core": "^2.14.0",
31
- "@tiptap/react": "^2.14.0",
32
- "@tiptap/starter-kit": "^2.14.0",
33
- "@tiptap/extension-placeholder": "^2.14.0"
34
- },
35
16
  "dependencies": {
36
17
  "@edux-design/avatars": "*",
37
18
  "@edux-design/buttons": "*",
@@ -47,5 +28,13 @@
47
28
  "@tiptap/react": "^3.15.3",
48
29
  "@tiptap/starter-kit": "^3.15.3",
49
30
  "@tiptap/extension-placeholder": "^3.15.3"
50
- }
31
+ },
32
+ "files": [
33
+ "dist",
34
+ "docs",
35
+ "README.md",
36
+ "CHANGELOG.md",
37
+ "LICENSE",
38
+ "LICENSE.md"
39
+ ]
51
40
  }