@mieweb/ui 0.11.0-dev.53 → 0.11.0-dev.55

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/agent/README.md CHANGED
@@ -22,8 +22,8 @@ governing spec: later tickets cite it instead of re-deciding.
22
22
  | ------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
23
23
  | [mieweb-ui.instructions.md](mieweb-ui.instructions.md) | The rules template. Copied verbatim to the consumer's `.github/instructions/` (VS Code Copilot auto-applies it via the `applyTo` frontmatter) and embedded, minus frontmatter, in a marked block in the consumer's `AGENTS.md` (the cross-tool convention). |
24
24
  | [init-agent.mjs](init-agent.mjs) | The `mieweb-ui` bin. Idempotent — rerun after upgrading `@mieweb/ui` to refresh all targets. `--experimental-agents` additionally installs the agent team below. |
25
- | [agents/](agents/) | Agent templates: `mieweb-ui-design` (orchestrator) + `mieweb-ui-styling` + `mieweb-ui-install` + `mieweb-ui-a11y` + `mieweb-ui-i18n` + `mieweb-ui-migration`. Installed to the consumer's `.github/agents/` behind `--experimental-agents`. |
26
- | [skills/](skills/) | Skill templates: `mieweb-ui-catalog`, `mieweb-ui-tokens`, `mieweb-ui-icons` (generated — `pnpm agent:skills`, never hand-edit) + `mieweb-ui-brands`, `mieweb-ui-tailwind4`, `mieweb-ui-a11y-checklist`, `mieweb-ui-i18n-checklist` (hand-written). Installed to `.github/skills/` behind `--experimental-agents`. |
25
+ | [agents/](agents/) | Agent templates: `mieweb-ui-design` (orchestrator) + `mieweb-ui-styling` + `mieweb-ui-install` + `mieweb-ui-a11y` + `mieweb-ui-i18n` + `mieweb-ui-migration` + `mieweb-ui-richtext`. Installed to the consumer's `.github/agents/` behind `--experimental-agents`. |
26
+ | [skills/](skills/) | Skill templates: `mieweb-ui-catalog`, `mieweb-ui-tokens`, `mieweb-ui-icons` (generated — `pnpm agent:skills`, never hand-edit) + `mieweb-ui-brands`, `mieweb-ui-tailwind4`, `mieweb-ui-a11y-checklist`, `mieweb-ui-i18n-checklist`, `mieweb-ui-kerebron` (hand-written). Installed to `.github/skills/` behind `--experimental-agents`. |
27
27
  | `evals/` _(Phase 2+)_ | Golden-question eval sets per specialist; the regression harness for agent knowledge. |
28
28
 
29
29
  Rule content is sourced from [lessons/component-policy.md](../lessons/component-policy.md);
@@ -23,6 +23,10 @@ handoffs:
23
23
  agent: MIE UI Migration Agent
24
24
  prompt: Audit the code discussed above for @mieweb/ui compliance (raw HTML elements, custom modal/card/badge patterns, hand-rolled icons, CSS foundation) and report findings with a prioritized replacement plan.
25
25
  send: false
26
+ - label: Rich text editors
27
+ agent: MIE UI Rich Text Agent
28
+ prompt: Handle the rich-text question above (Kerebron editors, install legs, WASM/patches, collaboration, markdown round-trip, EmailEditor) and report the minimal fix.
29
+ send: false
26
30
  ---
27
31
 
28
32
  # MIE UI Design Agent (orchestrator)
@@ -60,9 +64,10 @@ comparison tables) and `mieweb-ui-icons` (icon aliases and conventions):
60
64
  | ARIA, keyboard nav, screen readers, contrast | MIE UI A11y Agent |
61
65
  | translations, locale bundles, Intl formats, RTL | MIE UI i18n Agent |
62
66
  | migrating code to @mieweb/ui, raw-HTML compliance | MIE UI Migration Agent |
67
+ | rich text editors (RichEditor, TextAreaRich, EmailEditor), Kerebron peers/WASM/patches, collab, Markdown rendering | MIE UI Rich Text Agent |
63
68
 
64
69
  More specialists (Grids, DataVis, Views,
65
- SuperChat, Rich Text) land in later phases; until one ships, answer its domain
70
+ SuperChat) land in later phases; until one ships, answer its domain
66
71
  from the skills and the component docs, or defer (below).
67
72
 
68
73
  **Tie-breakers:**
@@ -0,0 +1,86 @@
1
+ ---
2
+ name: MIE UI Rich Text Agent
3
+ description: Rich-text editing specialist for the @mieweb/ui design system — the Kerebron entry (RichEditor, CodeEditor, TextAreaRich), the Kerebron-backed main-barrel Textarea, EmailEditor, MarkdownRenderer, Yjs collaboration, WASM grammar serving, the exact-0.8.12 peer set with ProseMirror overrides, and the consumer-side @kerebron patches. Invoke for integrating or configuring any rich-text editor, typing/toolbar/WASM/collab failures, markdown round-trip or value-contract questions, and email-safe editing.
4
+ tools: ['search', 'codebase', 'fetch', 'runInTerminal']
5
+ handoffs:
6
+ - label: Apply Fixes
7
+ agent: agent
8
+ prompt: Apply the rich-text integration fixes identified above to the codebase.
9
+ send: false
10
+ ---
11
+
12
+ # MIE UI Rich Text Agent
13
+
14
+ You are the rich-text editing specialist for the **@mieweb/ui** design
15
+ system. Consumers come to you to wire a Kerebron editor into their app, to
16
+ pick the right configuration for a surface they have already chosen, and when
17
+ an editor misbehaves — typing throws, toolbars are dead, grammars 404, marks
18
+ vanish on save, collaboration silently stops syncing. You diagnose from
19
+ evidence and report a minimal fix — you do not edit files (offer the
20
+ **Apply Fixes** handoff instead).
21
+
22
+ ## Your sources of truth (never inline-duplicate them)
23
+
24
+ - **`mieweb-ui-kerebron` skill** — the domain bible: surfaces and their value
25
+ contracts, the three-legged install (exact-0.8.12 peers, ProseMirror
26
+ overrides, CSS + WASM assets), the consumer-side patches and what breaks
27
+ without each, RichEditor integration facts (read-once props, `getContent()`
28
+ on submit, `mediaUpload`, `omitExtensions`), collaboration and its degrade
29
+ path, Textarea-on-Kerebron behaviour changes, EmailEditor constraints, and
30
+ the symptom→fix troubleshooting table. Start every answer here.
31
+ - **`mieweb-ui-catalog` skill** — entry-point map and per-entry peer/CSS
32
+ requirements across the whole library.
33
+ - **`mieweb-ui-tailwind4` skill** — general install/CSS foundation when the
34
+ problem is upstream of the editors (missing `kerebron.css` is yours;
35
+ missing `styles.css` plumbing is Install's).
36
+
37
+ ## Workflow
38
+
39
+ 1. **Settle the value contract first.** Markdown → `RichEditor`; HTML in
40
+ textarea chrome → Kerebron `TextAreaRich`; plain text → `Textarea`; email
41
+ blocks → `EmailEditor`; display-only Markdown → `MarkdownRenderer`. Most
42
+ misconfigurations are a surface/format mismatch — e.g. echoing flattened
43
+ `Textarea` output back into a rich surface.
44
+ 2. **Check the three install legs before the component.** Peers at exactly
45
+ 0.8.12, the four ProseMirror overrides in the host, `kerebron.css` +
46
+ WASM assets at `/kerebron-wasm`. `pnpm why prosemirror-model` (or
47
+ `npm ls`/`yarn why`) must show a single version.
48
+ 3. **Then the patches.** Dead toolbar dropdowns, dropped
49
+ highlight/sup/sub marks, and the axe `select-name` failure are all
50
+ missing-host-patch symptoms — the library's own `patchedDependencies` do
51
+ not propagate.
52
+ 4. **Match the skill's troubleshooting table** before reasoning from scratch;
53
+ it covers the known failure modes with their issue numbers.
54
+ 5. **Report, then hand off.** State root cause, evidence, and the smallest
55
+ fix. Offer **Apply Fixes** for the edit.
56
+
57
+ ## Redirects
58
+
59
+ - "Which editor/component should I use?" → **MIE UI Design Agent** (selection
60
+ is the orchestrator's domain; you own configuration, APIs and debugging of
61
+ a chosen surface).
62
+ - Library-wide install plumbing — Tailwind setup, `styles.css`, dark mode,
63
+ brand CSS, non-editor peer errors → **MIE UI Install Agent**. You own the
64
+ Kerebron legs (peers/overrides/WASM/patches/`kerebron.css`).
65
+ - Token choices and visual theming of editor chrome → **MIE UI Styling
66
+ Agent**.
67
+ - Accessibility audits beyond the editor-specific facts you carry (labelling
68
+ via `aria-label`, the codecrock patch) → **MIE UI A11y Agent**.
69
+
70
+ ## Rules
71
+
72
+ 1. Never invent editor props, extension names, or Kerebron APIs — verify
73
+ against the skill, the library's types, or the consumer's installed
74
+ packages.
75
+ 2. The legacy `RichTextEditor` and legacy `TextAreaRich` are deprecated
76
+ (mieweb/ui#692): never recommend them for new work; steer to the Kerebron
77
+ surfaces and flag any new usage you encounter.
78
+ 3. Respect read-once props: any answer that changes `collab`, `mediaUpload`,
79
+ `modifyMenu` or `omitExtensions` at runtime must say "remount via `key`".
80
+ 4. If documents persist anywhere, insist on an upload hook — base64
81
+ embedding is a data-size defect, not a style choice. The hook is
82
+ `mediaUpload.uploadHandler` on the surfaces that expose it (`RichEditor`,
83
+ Kerebron `TextAreaRich`); `EmailEditor`'s is `onUploadImage`.
84
+ 5. Prefer the smallest change that fixes the root cause; no editor rewrites.
85
+ 6. The installed `mieweb-ui.instructions.md` rules apply to any code you
86
+ recommend.
@@ -20,6 +20,7 @@ These files are maintainer-side quality tooling. They are **not** shipped by
20
20
  | [a11y.md](./a11y.md) | Accessibility | MIE UI A11y Agent |
21
21
  | [i18n.md](./i18n.md) | Internationalization / RTL | MIE UI i18n Agent |
22
22
  | [migration.md](./migration.md) | Migration / compliance (incl. icons) | MIE UI Migration Agent |
23
+ | [richtext.md](./richtext.md) | Rich text / Kerebron editors | MIE UI Rich Text Agent |
23
24
 
24
25
  ## Entry format
25
26
 
@@ -0,0 +1,229 @@
1
+ # Evals — Rich text / Kerebron editors
2
+
3
+ Primary agent: **MIE UI Rich Text Agent**. See [README.md](./README.md) for
4
+ format and scoring.
5
+
6
+ ### RT-1 — Which editor for the stored format
7
+
8
+ - **Ask:** "I need a rich input whose saved value is HTML, looking like a plain textarea until the user asks for the toolbar. Which component?"
9
+ - **Expect:** Kerebron `TextAreaRich` from `@mieweb/ui/kerebron` (HTML
10
+ contract, one Input row tall, auto-grows, toolbar hidden until asked) — not
11
+ `RichEditor` (Markdown contract) and not the deprecated main-barrel
12
+ `TextAreaRich`. Selection may be answered by the orchestrator directly.
13
+ - **Agent:** MIE UI Design Agent (selection) → MIE UI Rich Text Agent for config
14
+ - **Source:** src/catalog/Editors.mdx — Which one? table; agent/skills/mieweb-ui-kerebron/SKILL.md — Surfaces
15
+
16
+ ### RT-2 — Install legs
17
+
18
+ - **Ask:** "What exactly do I install and configure to use RichEditor in my Vite app?"
19
+ - **Expect:** All three legs: (1) `@kerebron/*` peers at **exactly 0.8.12**
20
+ (`--save-exact`; `editor`, `editor-kits`, `extension-basic-editor`,
21
+ `extension-menu`, `wasm`), (2) the four ProseMirror overrides in the host
22
+ (view 1.42.3, model 1.25.9, state 1.4.3, transform 1.10.4), (3)
23
+ `@mieweb/ui/kerebron.css` + serve `@kerebron/wasm/assets` at
24
+ `/kerebron-wasm`. Plus the consumer-side `@kerebron` patches.
25
+ - **Agent:** MIE UI Rich Text Agent
26
+ - **Source:** MIGRATION.md — eSheet and EncounterVisit / 0.12 sections; agent/skills/mieweb-ui-kerebron/SKILL.md — Install
27
+
28
+ ### RT-3 — Fragment RangeError
29
+
30
+ - **Ask:** "Typing in any editor throws `RangeError: Can not convert <…> to a Fragment (looks like multiple versions of prosemirror-model were loaded)`. What's wrong?"
31
+ - **Expect:** Split ProseMirror resolution (mieweb/ui#709): Kerebron range
32
+ drifted to 0.8.13+ or transitive `^`-ranges floated on a fresh install. Fix:
33
+ pin `@kerebron/*` to 0.8.12 exactly + add the four overrides;
34
+ `pnpm dedupe` cannot fix it; verify with `pnpm why prosemirror-model`
35
+ (single version).
36
+ - **Agent:** MIE UI Rich Text Agent
37
+ - **Source:** MIGRATION.md — mieweb/ui#709 section; kerebron skill troubleshooting
38
+
39
+ ### RT-4 — Why prosemirror-view 1.42.3
40
+
41
+ - **Ask:** "Kerebron pins prosemirror-view 1.40.0 — why does the override force 1.42.3?"
42
+ - **Expect:** The protected MDY link bridge uses 1.42.3; two view instances
43
+ can make decorations incompatible and leave the older view's behavior
44
+ active.
45
+ - **Agent:** MIE UI Rich Text Agent
46
+ - **Source:** MIGRATION.md — prosemirror-view note
47
+
48
+ ### RT-5 — WASM 404s
49
+
50
+ - **Ask:** "Code blocks have no syntax highlighting and the console shows 404s for `.wasm` files."
51
+ - **Expect:** The editor loads tree-sitter grammars at runtime from
52
+ `/kerebron-wasm`; serve `@kerebron/wasm`'s `assets/` dir at that path (copy
53
+ or symlink into `public/`, or Storybook `staticDirs`), or pass a custom
54
+ `assetLoad` (`createAssetLoad('/other-path')`).
55
+ - **Agent:** MIE UI Rich Text Agent
56
+ - **Source:** src/kerebron.ts header; RichEditor `assetLoad` prop docs
57
+
58
+ ### RT-6 — Dead toolbar dropdowns
59
+
60
+ - **Ask:** "The Heading and List dropdowns in the RichEditor toolbar don't open when clicked."
61
+ - **Expect:** Host is missing the `@kerebron/extension-menu` patch — the
62
+ library's `patchedDependencies` don't propagate; apply
63
+ `patches/@kerebron__extension-menu@0.8.12.patch` in the host (pnpm-format;
64
+ npm/yarn convert for patch-package).
65
+ - **Agent:** MIE UI Rich Text Agent
66
+ - **Source:** RichEditor.stories.tsx docs; patches/; kerebron skill — patches table
67
+
68
+ ### RT-7 — Marks dropped on save
69
+
70
+ - **Ask:** "Highlight, superscript and subscript formatting disappears when the document is saved and reloaded."
71
+ - **Expect:** Missing `@kerebron/extension-markdown` patch (mieweb/ui#536):
72
+ the serializer's mark table has no entries for those marks, so they're
73
+ silently dropped on the markdown round-trip; patched they serialize as
74
+ `<mark>`/`<sup>`/`<sub>` inline HTML.
75
+ - **Agent:** MIE UI Rich Text Agent
76
+ - **Source:** patches/@kerebron__extension-markdown@0.8.12.patch; kerebron skill — patches table
77
+
78
+ ### RT-8 — Reading the value on submit
79
+
80
+ - **Ask:** "Should I trust my `onChange`-mirrored state when the user hits Save?"
81
+ - **Expect:** No — `onChange` can lag the last keystroke; call the ref's
82
+ `getContent()` on submit (async, awaits the initial load; rejects if setup
83
+ failed — see `onError`).
84
+ - **Agent:** MIE UI Rich Text Agent
85
+ - **Source:** RichEditorHandle docs — getContent
86
+
87
+ ### RT-9 — Changing collab/mediaUpload at runtime
88
+
89
+ - **Ask:** "How do I switch the RichEditor to a different collaboration room without reloading the page?"
90
+ - **Expect:** `collab` (like `mediaUpload`, `modifyMenu`, `omitExtensions`)
91
+ is read once at mount — **remount via `key`** to switch rooms; collab mode
92
+ is uncontrolled.
93
+ - **Agent:** MIE UI Rich Text Agent
94
+ - **Source:** RichEditor collab prop docs; kerebron skill — read-once props
95
+
96
+ ### RT-10 — Pasted images bloat the document
97
+
98
+ - **Ask:** "A pasted screenshot turned my saved markdown into a 6 MB payload. How do I prevent that?"
99
+ - **Expect:** Set `mediaUpload.uploadHandler` — without it images embed as
100
+ base64 `data:` URLs (and video as reload-dead blob URLs); the handler
101
+ uploads the file and returns a URL so the document carries a link, not
102
+ bytes. Required whenever documents persist.
103
+ - **Agent:** MIE UI Rich Text Agent
104
+ - **Source:** RichEditor mediaUpload prop docs
105
+
106
+ ### RT-11 — Removing a feature wholesale
107
+
108
+ - **Ask:** "How do I remove checklists (toolbar button, `- [ ]` shortcut, paste) from the editor in one move?"
109
+ - **Expect:** `omitExtensions={['task_list', 'task_item']}` — toolbar, input
110
+ rules and paste handling are all schema-driven, so dropping the nodes
111
+ removes the whole feature; read once at mount.
112
+ - **Agent:** MIE UI Rich Text Agent
113
+ - **Source:** RichEditor omitExtensions prop docs
114
+
115
+ ### RT-12 — Collab silently local
116
+
117
+ - **Ask:** "I pass `collab={{ room }}` but edits don't sync between users, and there's no error."
118
+ - **Expect:** `onUnavailable` reports **kit-load failures only** (optional
119
+ peers `@kerebron/extension-yjs`, `yjs`, `y-protocols` missing): the editor
120
+ mounts as a local one and the callback fires once, before the editor is
121
+ created. A reachable-but-disconnected relay is different — the kit stays
122
+ loaded and the provider retries on its own, with no callback. Fix: install
123
+ the peers and pass `collab.onUnavailable` to surface load failures; for
124
+ connectivity, check the `/yjs` websocket relay (`wsUrl` default
125
+ `<ws|wss>://<location.host>/yjs`).
126
+ - **Agent:** MIE UI Rich Text Agent
127
+ - **Source:** RichEditor collab docs; collabKit.ts; kerebron skill — Collaboration
128
+
129
+ ### RT-13 — MISSING_EXPORT at build
130
+
131
+ - **Ask:** "My `vite build` fails with `MISSING_EXPORT` from `@kerebron/extension-yjs` in a `collabKit-*` chunk, but I never use collaboration."
132
+ - **Expect:** Optional collab peers absent + an @mieweb/ui version older than
133
+ the mieweb/ui#706 fix (static named imports in the lazy collab chunk; the
134
+ optional-peer stub has no named exports). Fix: upgrade @mieweb/ui, or
135
+ externalize `/^@kerebron\/extension-yjs/` and `/^y-websocket/`.
136
+ - **Agent:** MIE UI Rich Text Agent
137
+ - **Source:** collabKit.ts header (mieweb/ui#706); tailwind4 + kerebron skill troubleshooting
138
+
139
+ ### RT-14 — Legacy RichTextEditor
140
+
141
+ - **Ask:** "Can I use RichTextEditor for a new templated-letter feature? It has `{{variables}}` and dictation."
142
+ - **Expect:** No — `RichTextEditor` (the `document.execCommand` engine) is
143
+ deprecated (mieweb/ui#692), never for new work; use Kerebron `TextAreaRich`
144
+ for HTML with `variableGroups` + dictation, or `RichEditor` for Markdown.
145
+ Note it emits raw unsanitised `innerHTML`.
146
+ - **Agent:** MIE UI Rich Text Agent
147
+ - **Source:** src/catalog/Editors.mdx — deprecated rows (mieweb/ui#692)
148
+
149
+ ### RT-15 — Textarea DOM shape
150
+
151
+ - **Ask:** "After upgrading to 0.12 my CSS `textarea { … }` rules and my test's element selectors stopped matching the Textarea."
152
+ - **Expect:** Since 0.12 `Textarea` renders the Kerebron engine: no visible
153
+ `<textarea>` — a ProseMirror `contenteditable` (`role="textbox"`, class
154
+ `kb-editor`) plus a hidden mirror `[data-slot="textarea-mirror"]` carrying
155
+ `name`/`value`. Target the `data-slot` hooks (`[data-slot^="textarea-"]`
156
+ or a concrete slot); `getByRole('textbox')`
157
+ keeps working; `TextAreaPlain` / `richText={false}` restores the native
158
+ element.
159
+ - **Agent:** MIE UI Rich Text Agent
160
+ - **Source:** MIGRATION.md — Textarea is rich text underneath (0.12.0)
161
+
162
+ ### RT-16 — maxLength not enforced
163
+
164
+ - **Ask:** "Textarea's `maxLength` no longer blocks typing past the limit — bug?"
165
+ - **Expect:** Known behaviour change (0.12): `maxLength` isn't enforced while
166
+ typing; the `showCount` counter still renders and turns red. Enforce in
167
+ `onChange` or switch to `TextAreaPlain`.
168
+ - **Agent:** MIE UI Rich Text Agent
169
+ - **Source:** MIGRATION.md — Behaviour changes to review
170
+
171
+ ### RT-17 — Email checklists vanish
172
+
173
+ - **Ask:** "Why can't users add checklists inside EmailEditor text blocks?"
174
+ - **Expect:** By design (mieweb/ui#695): email `text` blocks are
175
+ `TextAreaRich` with `omitExtensions={['task_list', 'task_item']}` —
176
+ checkbox inputs are sanitizer-forbidden and inert in mail clients, so the
177
+ feature is removed schema-first. Not a bug.
178
+ - **Agent:** MIE UI Rich Text Agent
179
+ - **Source:** EmailBlockSettings.tsx — EMAIL_OMITTED_EXTENSIONS; kerebron skill — EmailEditor
180
+
181
+ ### RT-18 — Compiling EmailEditor output
182
+
183
+ - **Ask:** "EmailEditor gives me MJML from `renderEmailMjml` — does @mieweb/ui compile it to email HTML?"
184
+ - **Expect:** No — compile with `mjml` (Node) or `mjml-browser` **host-side**;
185
+ it is not a peer. The editor's document is JSON blocks, not HTML; sending,
186
+ recipients and templates are the host's concern.
187
+ - **Agent:** MIE UI Rich Text Agent
188
+ - **Source:** src/catalog/Editors.mdx — EmailEditor row + peers table
189
+
190
+ ### RT-19 — Labelling the editor
191
+
192
+ - **Ask:** "My `<label htmlFor={editorId}>` doesn't give the RichEditor an accessible name."
193
+ - **Expect:** The host is a `div`, not a labelable control — `htmlFor` won't
194
+ associate; use `aria-label` or `aria-labelledby` (the `id` prop is the
195
+ anchor). Deeper audits go to the A11y agent.
196
+ - **Agent:** MIE UI Rich Text Agent
197
+ - **Source:** RichEditor id/aria props docs; Editors.mdx — Labelling
198
+
199
+ ### RT-20 — Displaying what RichEditor saved
200
+
201
+ - **Ask:** "What renders the markdown a RichEditor produced, in a read-only record view with mermaid diagrams?"
202
+ - **Expect:** `MarkdownRenderer` (main barrel, `@mieweb/ui/markdown.css`) —
203
+ sanitised HTML, code highlighting, `mermaid`/`csv`/`survey`/`html` fences,
204
+ `streaming` for token-by-token AI output. Conditional deps: `mermaid` for
205
+ the mermaid fence, `papaparse` for csv, `js-yaml` only for YAML-input
206
+ surveys (JSON surveys and the html fence need none). Legacy
207
+ `RichTextEditor` HTML does **not** go through it.
208
+ - **Agent:** MIE UI Rich Text Agent
209
+ - **Source:** src/catalog/Editors.mdx — Markdown row + "Markdown closes the loop"
210
+
211
+ ### RT-21 — Controlled value semantics
212
+
213
+ - **Ask:** "I set `value` and `onChange` on RichEditor but rejected edits don't revert like a native controlled input."
214
+ - **Expect:** Default is tolerant of read-once hosts (`getContent()` on
215
+ submit); opt in to native controlled semantics with `strictValue` —
216
+ converges the document to `value` on every render so un-echoed edits
217
+ revert. Also: changing `value` reloads the editor (unless `collab`).
218
+ - **Agent:** MIE UI Rich Text Agent
219
+ - **Source:** RichEditor strictValue/value prop docs
220
+
221
+ ### RT-22 — HTML-valued RichEditor
222
+
223
+ - **Ask:** "Can RichEditor speak HTML instead of Markdown without switching components?"
224
+ - **Expect:** Yes — `valueType="text/html"` governs both how `value` is
225
+ parsed and what `onChange`/`getContent()` emit (default
226
+ `'text/x-markdown'`). But if the goal is a textarea-like HTML field,
227
+ `TextAreaRich` is the intended surface.
228
+ - **Agent:** MIE UI Rich Text Agent
229
+ - **Source:** RichEditor valueType prop docs; Editors.mdx — Which one? table
@@ -0,0 +1,173 @@
1
+ ---
2
+ name: mieweb-ui-kerebron
3
+ description: Integrating @mieweb/ui rich-text editors — the Kerebron entry (RichEditor, CodeEditor, TextAreaRich), the Kerebron-backed main-barrel Textarea, EmailEditor, and MarkdownRenderer — including the exact-0.8.12 peer set, ProseMirror version overrides, WASM grammar serving, the consumer-side @kerebron patches, Yjs collaboration and its degrade path. USE WHEN installing or configuring any rich-text editor, typing/toolbar/WASM/collab misbehaves, markdown round-trip drops marks, or an editor value contract (markdown vs HTML vs plain text) is in question.
4
+ ---
5
+
6
+ # Kerebron rich text in @mieweb/ui
7
+
8
+ Sourced from `MIGRATION.md`, `src/catalog/Editors.mdx`, the RichEditor/Email
9
+ docs and `patches/` in the mieweb/ui repo. Selection guidance ("which
10
+ editor?") lives in the `mieweb-ui-catalog` skill; general install/CSS
11
+ foundation in `mieweb-ui-tailwind4`.
12
+
13
+ ## Surfaces and their value contracts
14
+
15
+ The **stored format decides the surface** — this is the first question to
16
+ settle in any integration:
17
+
18
+ | Surface | Entry | Value contract |
19
+ | --- | --- | --- |
20
+ | `RichEditor` | `@mieweb/ui/kerebron` | **Markdown** in/out (`valueType: 'text/x-markdown'` default; `'text/html'` for an HTML-valued surface) |
21
+ | `CodeEditor` | `@mieweb/ui/kerebron` | Source code (tree-sitter highlighting) |
22
+ | `TextAreaRich` | `@mieweb/ui/kerebron` | **HTML**, textarea-like chrome: one Input row tall, auto-grows, toolbar hidden until asked, markdown block shortcuts, Notion-style `+` gutter menu, `.shortcut` macros |
23
+ | `Textarea` | main barrel | **Plain text** contract over the same engine (since 0.12): `value`/`onChange(event.target.value)` are strings, `name` posts via a hidden mirror `<textarea>`. Opt out per field with `richText={false}` or `TextAreaPlain` |
24
+ | `EmailEditor` + `renderEmailMjml` | main barrel | **JSON blocks** (hero, columns, buttons, images, social, footer) compiled to MJML — not HTML; each `text` block hosts a `TextAreaRich` |
25
+ | `MarkdownRenderer` + blocks, `useMarkdown` | main barrel | **Read-only display** of Markdown (sanitised HTML, code highlighting, `mermaid`/`csv`/`survey`/`html` fences, `streaming` for token-by-token AI output) |
26
+
27
+ **Deprecated — never for new work** (mieweb/ui#692): main-barrel
28
+ `RichTextEditor` and legacy `TextAreaRich` (the `document.execCommand`
29
+ engine). Replacements: Kerebron `TextAreaRich` for HTML (+ `variableGroups` +
30
+ dictation), `RichEditor` for Markdown. `RichTextEditor` emits raw unsanitised
31
+ `innerHTML` and its output does **not** go through `MarkdownRenderer`.
32
+
33
+ ## Install — the three-legged stool
34
+
35
+ Every consumer needs all three legs since 0.12 (the main-barrel `Textarea`
36
+ rides the engine, so none of this is optional):
37
+
38
+ **1. Peers at exactly 0.8.12.** `@kerebron/editor`, `editor-kits`,
39
+ `extension-basic-editor`, `extension-menu`, `wasm` are required peers —
40
+ install with `--save-exact`: newer Kerebron (0.8.13+) pins different
41
+ ProseMirror versions, so a `^0.8.12` range drifts and splits
42
+ `prosemirror-model` (mieweb/ui#709). Collab peers stay optional:
43
+ `@kerebron/extension-yjs`, `yjs`, `y-protocols`.
44
+
45
+ ```sh
46
+ npm install --save-exact @kerebron/editor@0.8.12 @kerebron/editor-kits@0.8.12 \
47
+ @kerebron/extension-basic-editor@0.8.12 @kerebron/extension-menu@0.8.12 \
48
+ @kerebron/wasm@0.8.12
49
+ ```
50
+
51
+ **2. ProseMirror overrides in the host.** Even with matching pins,
52
+ ProseMirror's own `^`-ranged internals float to the newest release on any
53
+ fresh install — the library's own overrides do **not** propagate. Add to the
54
+ host (pnpm 10: `overrides:` in `pnpm-workspace.yaml`; npm: `"overrides"`;
55
+ Yarn: `"resolutions"` — full snippets in
56
+ [MIGRATION.md](https://github.com/mieweb/ui/blob/main/MIGRATION.md#esheet-and-encountervisit)):
57
+
58
+ ```yaml
59
+ overrides:
60
+ prosemirror-view: "1.42.3"
61
+ prosemirror-model: "1.25.9"
62
+ prosemirror-state: "1.4.3"
63
+ prosemirror-transform: "1.10.4"
64
+ ```
65
+
66
+ `prosemirror-view` is 1.42.3 (not Kerebron's pinned 1.40.0) for the protected
67
+ MDY link bridge. Verify after install: `pnpm why prosemirror-model` /
68
+ `pnpm why prosemirror-view` (or `npm ls`/`yarn why`) must each show a
69
+ **single** version. `pnpm dedupe` cannot fix a split — only overrides can.
70
+
71
+ **3. CSS + WASM assets.** Import `@mieweb/ui/kerebron.css` beside
72
+ `styles.css` (`markdown.css` too if rendering Markdown). The editor loads
73
+ tree-sitter WASM grammars at runtime from `/kerebron-wasm`: serve
74
+ `@kerebron/wasm`'s `assets/` directory at that path — e.g. copy or symlink it
75
+ into Vite's `public/kerebron-wasm`, or add a Storybook `staticDirs` mapping —
76
+ or pass a custom `assetLoad` (`createAssetLoad('/my-path')`) when it lives
77
+ elsewhere.
78
+
79
+ ## The consumer-side patches
80
+
81
+ The repo's [`patches/@kerebron__*`](https://github.com/mieweb/ui/tree/main/patches)
82
+ fixes target `@kerebron/*@0.8.12` exactly and must be applied **in the host
83
+ app** until fixed upstream — the library's own `patchedDependencies` do not
84
+ propagate. They are pnpm-format (list under `patchedDependencies` as-is);
85
+ npm/yarn hosts convert to their patch tool's format (`patch-package` expects
86
+ its own filenames and `node_modules/…` paths). What breaks without each:
87
+
88
+ | Patch | Without it |
89
+ | --- | --- |
90
+ | `extension-menu` | Toolbar **Heading/List dropdowns do not fire** in browsers (also: full toolbar re-render per transaction) |
91
+ | `extension-markdown` | **highlight/superscript/subscript marks silently dropped** when saving back to Markdown (patched: round-trip as `<mark>`/`<sup>`/`<sub>` inline HTML, mieweb/ui#536) |
92
+ | `extension-codecrock` | Code-block language `<select>` has no accessible name (axe `select-name` failure) |
93
+
94
+ ## RichEditor integration facts
95
+
96
+ - **Read on submit, not from mirrored state:** `onChange` can lag the last
97
+ keystroke — use the ref's `getContent()` (async, awaits the initial load).
98
+ - **Read-once props:** `collab`, `mediaUpload`, `modifyMenu`,
99
+ `omitExtensions` are read when the editor mounts — **remount via `key`** to
100
+ change any of them.
101
+ - **`mediaUpload.uploadHandler` is required whenever documents persist.**
102
+ Without it a pasted image embeds as base64 (`~4 MB screenshot → ~5.8 MB of
103
+ markdown`) and video as a dead-on-reload blob URL.
104
+ - **`omitExtensions` removes whole features schema-first** — toolbar, input
105
+ rules and paste handling are all schema-driven, so
106
+ `['task_list', 'task_item']` removes checklists everywhere in one move.
107
+ - **`modifyMenu`** reshapes the stock toolbar (append macros/dictation
108
+ controls, drop stock groups) before first render.
109
+ - **Controlled semantics are opt-in:** default tolerates read-once hosts; set
110
+ `strictValue` for native controlled-input behavior (un-echoed edits
111
+ revert). Changing `value` reloads the editor unless `collab` is set.
112
+ - **Labelling:** the host is a `div`, not a labelable control — `<label
113
+ htmlFor>` won't associate; use `aria-label`/`aria-labelledby` (the `id`
114
+ prop is the anchor).
115
+
116
+ ## Collaboration (Yjs)
117
+
118
+ `collab: { room, wsUrl?, params? }` joins one shared document per `room` over
119
+ the `/yjs` websocket relay (default `<ws|wss>://<location.host>/yjs`;
120
+ `params` for auth tokens). Requires the optional peers
121
+ `@kerebron/extension-yjs` + `yjs` + `y-protocols`. **Best-effort degrade:**
122
+ if the Yjs **kit fails to load** (e.g. the optional peers are absent), the
123
+ editor still mounts locally and `collab.onUnavailable` fires once, before
124
+ the editor is created — pass it when users must know they're editing
125
+ unshared. `onUnavailable` is **not for connection trouble**: a reachable
126
+ room that is currently disconnected still has the kit loaded, and the
127
+ provider retries on its own. The kit lazy-loads via dynamic `import` so plain-mode consumers
128
+ never pull Yjs code (versions before the mieweb/ui#706 fix had static named
129
+ imports in the lazy chunk — rolldown-Vite builds failed with
130
+ `MISSING_EXPORT`; fix: upgrade, or externalize
131
+ `/^@kerebron\/extension-yjs/`, `/^y-websocket/`). Pair with the
132
+ `CollabStatus` component (Feedback family) for presence/sync UI. Collab mode
133
+ is uncontrolled — remount via `key` to switch rooms.
134
+
135
+ ## Textarea-on-Kerebron behaviour changes (0.12)
136
+
137
+ - `maxLength` no longer enforced while typing (counter still renders/turns
138
+ red) — enforce in `onChange` or use `TextAreaPlain`.
139
+ - `labelVariant="floating"`, `resize`, `autoResize={false}` ignored (one-time
140
+ dev warning).
141
+ - **DOM shape:** no visible `<textarea>` — a ProseMirror `contenteditable`
142
+ (`role="textbox"`, class `kb-editor`) plus hidden mirror
143
+ `[data-slot="textarea-mirror"]` carrying `name`/`value`. `textarea { … }`
144
+ CSS and element refs no longer match; target the `data-slot` hooks
145
+ (`[data-slot^="textarea-"]` prefix selector, or a concrete slot like
146
+ `textarea-wrapper`). `getByRole('textbox')` tests keep working.
147
+ - Controlled transforms of `event.target.value` reset formatting (the
148
+ reported value is flattened plain text).
149
+
150
+ ## EmailEditor constraints
151
+
152
+ Email `text` blocks are `TextAreaRich` surfaces with
153
+ `omitExtensions={['task_list', 'task_item']}` — checkbox inputs are
154
+ sanitizer-forbidden and inert in mail clients (mieweb/ui#695), so checklists
155
+ are removed schema-first rather than filtered after the fact. Compile
156
+ `renderEmailMjml` output with `mjml`/`mjml-browser` **host-side** (not a
157
+ peer). Sending, recipients and templates are the host's concern.
158
+
159
+ ## Troubleshooting
160
+
161
+ | Symptom | Cause | Fix |
162
+ | --- | --- | --- |
163
+ | Typing throws `RangeError: Can not convert … to a Fragment (looks like multiple versions of prosemirror-model)` | Split ProseMirror resolution: Kerebron range drifted to 0.8.13+, or transitive `^`-ranges floated on a fresh install (mieweb/ui#709) | Pin `@kerebron/*` 0.8.12 exact + the four overrides; verify single version via `pnpm why prosemirror-model` |
164
+ | `vite build` fails `MISSING_EXPORT` from `@kerebron/extension-yjs` in a `collabKit-*` chunk | Optional collab peers absent + @mieweb/ui older than the #706 fix (static named imports in the lazy chunk) | Upgrade @mieweb/ui; or externalize `/^@kerebron\/extension-yjs/`, `/^y-websocket/` |
165
+ | Code blocks render without highlighting; 404s for `*.wasm` | `@kerebron/wasm/assets` not served at `/kerebron-wasm` | Serve/symlink the assets dir, or pass `assetLoad` with the actual path |
166
+ | Toolbar Heading/List dropdowns don't open | Host missing the `extension-menu` patch | Apply `patches/@kerebron__extension-menu@0.8.12.patch` in the host |
167
+ | Highlight/superscript/subscript lost after save | Host missing the `extension-markdown` patch (marks absent from the serializer table) | Apply the `extension-markdown` patch (mieweb/ui#536) |
168
+ | axe: `select-name` on code blocks | Host missing the `extension-codecrock` patch | Apply the `extension-codecrock` patch |
169
+ | Pasted screenshot balloons the document / image dies on reload | No `mediaUpload.uploadHandler` — base64/blob embedding | Provide `uploadHandler` returning a hosted URL |
170
+ | Edits revert while typing in a controlled host | Host `onChange` doesn't echo into `value` and `strictValue` is set — or the host echoes flattened text back into a rich surface | Echo the value correctly, or drop `strictValue` for read-once + `getContent()` on submit |
171
+ | `collab` set but edits don't sync, no error | Yjs kit failed to load (missing optional peers) → silent local degrade; or the relay is disconnected (kit loaded, provider retrying) | Install the collab peers and pass `collab.onUnavailable` to surface load failures; for connectivity, check the `/yjs` relay — the provider retries on its own |
172
+ | `<label htmlFor>` doesn't focus/name the editor | Editor host is a `div`, not a labelable control | `aria-label` / `aria-labelledby` via the `id` anchor |
173
+ | Checklist items vanish in EmailEditor | By design — `task_list`/`task_item` are email-unsafe (mieweb/ui#695) | Use a different block structure; not a bug |
@@ -186,12 +186,24 @@ var miewebUISafelist = [
186
186
  "[&_[data-slot=button-label]]:whitespace-normal",
187
187
  "[&>[data-slot=dropdown-item-label]]:min-w-0",
188
188
  "[&>[data-slot=dropdown-item-label]]:flex-1",
189
- // TranscriptPlayer: timeline grid, transcript/panel layout, overview window and playhead.
190
- "grid-cols-[6.5rem_minmax(0,1fr)]",
189
+ // TranscriptPlayer: timeline grid, transcript/panel layout, overview window and playhead,
190
+ // plus the narrow-host container queries (these need Tailwind 4.1).
191
+ "grid-cols-[var(--tp-label,6.5rem)_minmax(0,1fr)]",
192
+ "[--tp-label:0px]",
193
+ "[--tp-label:4.5rem]",
194
+ "@md:[--tp-label:6.5rem]",
195
+ "@md:basis-0",
196
+ "@md:block",
197
+ "@md:flex-nowrap",
198
+ "@md:inline",
199
+ "@md:p-4",
200
+ "@md:ps-0",
201
+ "@sm:inline",
202
+ "@sm:me-1.5",
191
203
  "lg:grid-cols-[minmax(0,1fr)_18rem]",
192
204
  "-top-5",
193
205
  "min-w-40",
194
- "h-80",
206
+ "max-h-80",
195
207
  "dark:bg-primary-950/40",
196
208
  "ring-inset",
197
209
  "ring-foreground",
@@ -2012,5 +2024,5 @@ var tailwind_preset_default = miewebUIPreset;
2012
2024
  exports.miewebUIPreset = miewebUIPreset;
2013
2025
  exports.miewebUISafelist = miewebUISafelist;
2014
2026
  exports.tailwind_preset_default = tailwind_preset_default;
2015
- //# sourceMappingURL=chunk-XWGPEIVB.cjs.map
2016
- //# sourceMappingURL=chunk-XWGPEIVB.cjs.map
2027
+ //# sourceMappingURL=chunk-2UGMTGH2.cjs.map
2028
+ //# sourceMappingURL=chunk-2UGMTGH2.cjs.map