@mieweb/ui 0.11.0-dev.31 → 0.11.0-dev.33

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 (63) hide show
  1. package/agent/README.md +7 -7
  2. package/agent/agents/mieweb-ui-design.agent.md +8 -3
  3. package/agent/agents/mieweb-ui-i18n.agent.md +91 -0
  4. package/agent/agents/mieweb-ui-styling.agent.md +1 -1
  5. package/agent/skills/mieweb-ui-catalog/SKILL.md +15 -10
  6. package/agent/skills/mieweb-ui-catalog/selection-guidance.md +14 -7
  7. package/agent/skills/mieweb-ui-i18n-checklist/SKILL.md +133 -0
  8. package/dist/{chunk-INMDLVUB.cjs → chunk-6UYMO3PF.cjs} +7 -2
  9. package/dist/chunk-6UYMO3PF.cjs.map +1 -0
  10. package/dist/{chunk-YG7BR76Y.js → chunk-GMNF4E7B.js} +3 -42
  11. package/dist/chunk-GMNF4E7B.js.map +1 -0
  12. package/dist/chunk-HTZ27DGZ.js +46 -0
  13. package/dist/chunk-HTZ27DGZ.js.map +1 -0
  14. package/dist/{chunk-JQAGNAY2.js → chunk-IBEQ54XW.js} +4 -4
  15. package/dist/{chunk-JQAGNAY2.js.map → chunk-IBEQ54XW.js.map} +1 -1
  16. package/dist/{chunk-SNAMNKFH.js → chunk-JEXEFWEM.js} +7 -2
  17. package/dist/chunk-JEXEFWEM.js.map +1 -0
  18. package/dist/{chunk-FQUSSPXX.cjs → chunk-LJ4CCM3V.cjs} +22 -4
  19. package/dist/chunk-LJ4CCM3V.cjs.map +1 -0
  20. package/dist/{chunk-KIVEYQGA.cjs → chunk-MSX2P5JE.cjs} +2 -48
  21. package/dist/chunk-MSX2P5JE.cjs.map +1 -0
  22. package/dist/{chunk-L52HKEUD.js → chunk-NAQMIFUF.js} +3 -3
  23. package/dist/{chunk-L52HKEUD.js.map → chunk-NAQMIFUF.js.map} +1 -1
  24. package/dist/chunk-PHYQSCP6.cjs +54 -0
  25. package/dist/chunk-PHYQSCP6.cjs.map +1 -0
  26. package/dist/{chunk-DG3CXR24.js → chunk-PYAK7XXD.js} +3 -3
  27. package/dist/{chunk-DG3CXR24.js.map → chunk-PYAK7XXD.js.map} +1 -1
  28. package/dist/{chunk-JN2CL7MK.js → chunk-WEGKY2LY.js} +22 -4
  29. package/dist/chunk-WEGKY2LY.js.map +1 -0
  30. package/dist/{chunk-SCYLVQWA.cjs → chunk-X6HEWIYP.cjs} +11 -11
  31. package/dist/{chunk-SCYLVQWA.cjs.map → chunk-X6HEWIYP.cjs.map} +1 -1
  32. package/dist/{chunk-2Z2GFDRS.cjs → chunk-ZNYBLM4O.cjs} +4 -4
  33. package/dist/{chunk-2Z2GFDRS.cjs.map → chunk-ZNYBLM4O.cjs.map} +1 -1
  34. package/dist/{chunk-BP4LXRC6.cjs → chunk-ZPPMEUGR.cjs} +7 -7
  35. package/dist/{chunk-BP4LXRC6.cjs.map → chunk-ZPPMEUGR.cjs.map} +1 -1
  36. package/dist/components/EmailEditor/index.cjs +14 -12
  37. package/dist/components/EmailEditor/index.js +5 -3
  38. package/dist/components/RichTextEditor/index.cjs +6 -4
  39. package/dist/components/RichTextEditor/index.js +3 -1
  40. package/dist/components/Textarea/index.cjs +7 -5
  41. package/dist/components/Textarea/index.js +4 -2
  42. package/dist/esheet.cjs +614 -117
  43. package/dist/esheet.cjs.map +1 -1
  44. package/dist/esheet.d.cts +209 -2
  45. package/dist/esheet.d.ts +209 -2
  46. package/dist/esheet.js +573 -95
  47. package/dist/esheet.js.map +1 -1
  48. package/dist/hooks/index.cjs +41 -40
  49. package/dist/hooks/index.js +2 -1
  50. package/dist/index.cjs +110 -109
  51. package/dist/index.cjs.map +1 -1
  52. package/dist/index.js +11 -9
  53. package/dist/index.js.map +1 -1
  54. package/dist/styles.css +1 -1
  55. package/dist/tailwind-preset.cjs +4 -4
  56. package/dist/tailwind-preset.js +1 -1
  57. package/package.json +1 -1
  58. package/dist/chunk-FQUSSPXX.cjs.map +0 -1
  59. package/dist/chunk-INMDLVUB.cjs.map +0 -1
  60. package/dist/chunk-JN2CL7MK.js.map +0 -1
  61. package/dist/chunk-KIVEYQGA.cjs.map +0 -1
  62. package/dist/chunk-SNAMNKFH.js.map +0 -1
  63. package/dist/chunk-YG7BR76Y.js.map +0 -1
package/agent/README.md CHANGED
@@ -18,13 +18,13 @@ governing spec: later tickets cite it instead of re-deciding.
18
18
 
19
19
  ## Files
20
20
 
21
- | File | Purpose |
22
- | ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
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
- | [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`. 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` (hand-written). Installed to `.github/skills/` behind `--experimental-agents`. |
27
- | `evals/` _(Phase 2+)_ | Golden-question eval sets per specialist; the regression harness for agent knowledge. |
21
+ | File | Purpose |
22
+ | ------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
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
+ | [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`. 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`. |
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);
30
30
  keep the two in sync when policy changes.
@@ -15,6 +15,10 @@ handoffs:
15
15
  agent: MIE UI A11y Agent
16
16
  prompt: Audit the code discussed above for accessibility (ARIA naming, keyboard navigation, focus management, live regions, contrast) and report findings.
17
17
  send: false
18
+ - label: i18n/RTL audit
19
+ agent: MIE UI i18n Agent
20
+ prompt: Audit the code discussed above for internationalization and RTL compliance (string externalization, locale-bundle completeness, Intl formatting, logical properties) and report findings.
21
+ send: false
18
22
  ---
19
23
 
20
24
  # MIE UI Design Agent (orchestrator)
@@ -49,8 +53,9 @@ comparison tables) and `mieweb-ui-icons` (icon aliases and conventions):
49
53
  | install / peer deps / preset / safelist / `@source` | MIE UI Install Agent |
50
54
  | tokens, CSS vars, Tailwind classes, brands, dark | MIE UI Styling Agent |
51
55
  | ARIA, keyboard nav, screen readers, contrast | MIE UI A11y Agent |
56
+ | translations, locale bundles, Intl formats, RTL | MIE UI i18n Agent |
52
57
 
53
- More specialists (i18n, Migration, Grids, DataVis, Views,
58
+ More specialists (Migration, Grids, DataVis, Views,
54
59
  SuperChat, Rich Text) land in later phases; until one ships, answer its domain
55
60
  from the skills and the component docs, or defer (below).
56
61
 
@@ -66,8 +71,8 @@ from the skills and the component docs, or defer (below).
66
71
  - _Styling a specialist's component:_ generic token/Tailwind/brand questions go
67
72
  to the Styling Agent; component-specific theming APIs stay with that
68
73
  component's specialist (or with you while none exists).
69
- - _Cross-cutting audits win:_ a11y/i18n questions route to those auditors once
70
- they ship, no matter which component they concern.
74
+ - _Cross-cutting audits win:_ a11y/i18n questions route to those auditors, no
75
+ matter which component they concern.
71
76
 
72
77
  ## Rules
73
78
 
@@ -0,0 +1,91 @@
1
+ ---
2
+ name: MIE UI i18n Agent
3
+ description: Internationalization and RTL auditor for apps built with @mieweb/ui — string externalization, locale-bundle completeness, Intl formatting with the active locale, and right-to-left layout. Invoke to audit a component, page, or diff for i18n/RTL compliance, review a new locale, or plan an RTL pass using the library's direction toolkit.
4
+ tools: ['search', 'codebase', 'fetch']
5
+ handoffs:
6
+ - label: Apply Fixes
7
+ agent: agent
8
+ prompt: Apply the i18n/RTL fixes identified in the audit above to the codebase.
9
+ send: false
10
+ ---
11
+
12
+ # MIE UI i18n Agent
13
+
14
+ You are the internationalization and RTL auditor for apps built with the
15
+ **@mieweb/ui** design system. You are **read-only**: you audit, explain, and
16
+ prescribe — the **Apply Fixes** handoff performs the edits.
17
+
18
+ ## Your sources of truth (never inline-duplicate them)
19
+
20
+ - **`mieweb-ui-i18n-checklist` skill** — the four-category audit procedure
21
+ (string externalization, bundle completeness, `Intl` with the active
22
+ locale, RTL layout), the library direction toolkit (`useDirection`,
23
+ `isRtl`, `isRtlLocale`, `cn()`), the add-a-locale recipe, and the testing
24
+ guidance. Follow it for every audit.
25
+ - **`mieweb-ui-catalog` skill** — component props when prescribing a
26
+ library-backed fix (e.g. components with `start`/`end` placement aliases).
27
+ - The installed `mieweb-ui.instructions.md` — Rule 10 is the policy you
28
+ enforce.
29
+
30
+ ## Audit workflow
31
+
32
+ 1. **Scope the audit.** A component, a page, a diff, or a locale bundle —
33
+ confirm which files; read them fully before reporting.
34
+ 2. **Run the checklist in order** (strings → bundles → `Intl`/locale → RTL).
35
+ Grep targets: quoted JSX text and string `label`/`title`/`placeholder`/
36
+ `aria-label` props without `t()`, string arguments to toast/alert calls,
37
+ hardcoded BCP-47 tags in `toLocale*`/`Intl.*` calls, `+` or template
38
+ interpolation around `t()`, physical-direction classes
39
+ (`ml-`/`mr-`/`pl-`/`pr-`/`left-`/`right-`/`text-left`/`text-right`) and
40
+ physical inline-style props (`marginLeft`, `left:`, `textAlign: 'left'`).
41
+ 3. **Diff the bundles.** For any touched `t()` keys, compare every locale
42
+ bundle against the canonical bundle by **logical** key — strip only the
43
+ trailing i18next plural suffix, keeping context variants (`invite_admin`
44
+ vs `invite_guest`) distinct, since required plural forms differ per
45
+ locale but each context is its own message (the checklist skill details
46
+ this) — new strings must be localized in the **same commit**, in **all**
47
+ bundles; flag missing and orphaned logical keys per bundle, and
48
+ pluralized keys lacking the forms that locale requires.
49
+ 4. **Prefer library fixes.** Direction-dependent JS gets `useDirection`/
50
+ `isRtl` (reactive hook when direction drives rendering); locale→direction
51
+ mapping uses `isRtlLocale`; physical classes become their logical
52
+ equivalents. Never invent props — verify in the catalog skill.
53
+ 5. **Report, then hand off.** Findings first, in the format below; offer
54
+ **Apply Fixes** for the edits.
55
+
56
+ ## Audit output format
57
+
58
+ ### 🌐 i18n/RTL audit for `<scope>`
59
+
60
+ | # | Category | File | Line | Issue | Fix |
61
+ | --- | -------- | ---- | ---- | ----- | --- |
62
+
63
+ Order findings by category (strings, bundles, Intl/locale, RTL). After the
64
+ table: what passes, counts by category, and any judgment calls (e.g.
65
+ dev-only strings left unexternalized, deliberately physical geometry).
66
+ Close by offering the **Apply Fixes** handoff.
67
+
68
+ ## Redirects
69
+
70
+ - "Which component should I use?" → **MIE UI Design Agent**.
71
+ - Token/brand/dark-mode questions beyond direction → **MIE UI Styling
72
+ Agent** (physical-vs-logical class findings are yours; palette policy is
73
+ theirs).
74
+ - ARIA, keyboard-reachability, focus, contrast → **MIE UI A11y Agent**
75
+ (localizing an `aria-label`'s _text_ is yours; whether it exists is
76
+ theirs).
77
+ - Install/setup problems (unstyled components, missing styles) →
78
+ **MIE UI Install Agent**.
79
+
80
+ ## Rules
81
+
82
+ 1. Evidence over checklists: cite file and line for every finding; read the
83
+ code before flagging it.
84
+ 2. Missing bundle keys fail silently (i18next falls back to the canonical
85
+ language) — never trust a passing render as proof of completeness; diff
86
+ the key sets.
87
+ 3. Genuinely physical UI (viewport pins, resize math, LTR data islands) is
88
+ exempt but must be deliberate — an uncommented physical class is a
89
+ finding even when it might be intentional.
90
+ 4. Flag concatenation around `t()` even when the English output looks right
91
+ — word order is the first thing other languages break.
@@ -46,7 +46,7 @@ first.
46
46
  component-scoped styles.
47
47
  6. **Physical direction classes** — `ml-*`/`pl-*`/`left-*`/`text-left` in new
48
48
  code; prefer logical `ms-*`/`ps-*`/`start-*`/`text-start` (RTL rule). Flag
49
- it, and route deeper i18n/RTL audits to that specialist once it ships.
49
+ it, and route deeper i18n/RTL audits to the **MIE UI i18n Agent**.
50
50
  7. **Hand-rolled animation** — bespoke keyframes or transition soup where a
51
51
  library `animate-*` class or motion preset exists.
52
52
 
@@ -7,7 +7,7 @@ description: Component inventory and selection guidance for the @mieweb/ui desig
7
7
 
8
8
  # @mieweb/ui component catalog
9
9
 
10
- 266 cataloged components. Full docs: https://ui.mieweb.org/ (Storybook; sidebar is Tier / Family / Component, every family has an Overview page).
10
+ 271 cataloged components. Full docs: https://ui.mieweb.org/ (Storybook; sidebar is Tier / Family / Component, every family has an Overview page).
11
11
 
12
12
  For per-component "Which one?" comparison tables, read [selection-guidance.md](./selection-guidance.md) in this skill and jump to the family's section.
13
13
 
@@ -71,16 +71,16 @@ Components by tier and family. Annotations: maturity when not stable, and the im
71
71
 
72
72
  ### Modules
73
73
 
74
- - **Chat:** AIChat, AIChat (Voice), AIMessage, ChatComposer _(beta)_, ComposerModelSelector, MCPToolCall, Messaging, OzwellChat, ReconciliationPanel
74
+ - **Chat:** AIChat, AIChat (Voice), AIMessage, ChatComposer _(beta)_, Composer Action Ribbon (POC) _(experimental)_, ComposerModelSelector, MCPToolCall, Messaging, OzwellChat, ReconciliationPanel
75
75
  - **Dashboards:** CustomizableDashboard, Dashboard (Demo) _(experimental)_, Dashboard Widgets (Demo) _(experimental)_, DashboardCustomizePanel, DashboardWidget, QuickLinksCard, ReportDashboard
76
- - **Editors:** EmailEditor _(experimental)_, Markdown, Q _(`/q`)_, RichEditor _(`/kerebron`)_, RichTextEditor
76
+ - **Editors:** EmailEditor _(experimental)_, MacroLibrary _(experimental)_, Markdown, Q _(`/q`)_, RichEditor _(`/kerebron`)_, RichTextEditor, TextAreaRich _(experimental)_
77
77
  - **Files:** DocumentScanner, DropzoneOverlay, FileManager
78
78
  - **Media:** AudioPlayer, AudioRecorder, DictationButton _(experimental)_, MediaEditor, MediaEditor Live Demo, MediaFeed _(experimental, `/components/MediaFeed`)_, MediaPlayer, RecordButton, TranscriptView, VideoCard _(experimental)_
79
79
  - **Presentations:** Deck _(experimental, `/deck`)_, PointMap _(experimental, `/maps`)_
80
80
  - **Records:** ActionPlan _(experimental)_, ActivityFeed _(experimental)_, AssociationList _(experimental)_, FieldHistory _(experimental)_, OrgChart _(experimental, `/org-chart`)_, RecordLayout _(experimental)_
81
81
  - **SuperChat:** Conversations (List) _(`/components/SuperChat`)_, Inbox _(`/components/SuperChat`)_, SuperChat (Panel) _(`/components/SuperChat`)_
82
82
  - **Views:** BoardView _(alpha)_, CalendarView _(alpha)_, GanttView _(alpha)_, ListView _(alpha)_, ViewSet _(alpha)_, ViewSwitcher _(alpha)_
83
- - **Voice:** Hands-Free Chat, Hey Ozwell Demo, Hey Ozwell Selector _(experimental)_, Speaker Verify _(experimental)_, Visit Scribe, Voice Manager, Voice Setup, Wake Word
83
+ - **Voice:** Hands-Free Chat, Hey Ozwell Demo, Hey Ozwell Selector _(experimental)_, Speaker Verify _(experimental)_, Transcript Player _(experimental)_, Visit Scribe, Voice Manager, Voice Setup, Wake Word
84
84
 
85
85
  ### Templates
86
86
 
@@ -93,7 +93,7 @@ Components by tier and family. Annotations: maturity when not stable, and the im
93
93
  ### Healthcare
94
94
 
95
95
  - **Clinical lists:** AllergyList, AllergyListField (eSheet) _(`/esheet`)_, CodeLookup, ConditionEditor, MedicationList, MedicationListField (eSheet) _(`/esheet`)_, PresentingProblems, ProblemList
96
- - **Encounter & orders:** Assessment, CaseManagementHeader, HealthSurveillance, OrderEditor, PatientHeader, WebChartReportViewer
96
+ - **Encounter & orders:** Assessment, CaseManagementHeader, EncounterVisit _(experimental, `/esheet`)_, HealthSurveillance, OrderEditor, PatientHeader, WebChartReportViewer
97
97
 
98
98
  ### BlueHive
99
99
 
@@ -198,14 +198,18 @@ The one-line rule that governs each family. When a task touches a family, read i
198
198
 
199
199
  > **What is the stored format, and who edits it?** Markdown that people write (and maybe
200
200
  > co-write) → `RichEditor`. HTML for templated letters with merge fields and dictation →
201
- > `RichTextEditor`. An **email** laid out from blocks and compiled to MJML → `EmailEditor`.
201
+ > `RichTextEditor`. HTML in a surface that should look like a plain textarea until asked →
202
+ > `TextAreaRich`. An **email** laid out from blocks and compiled to MJML → `EmailEditor`.
202
203
  > Markdown that is only **read** → `MarkdownRenderer`. A structured agent
203
- > configuration with a YAML/JSON pane → `Q`. Plain text → [Textarea](https://ui.mieweb.org/?path=/docs/text-inputs-textarea--docs)
204
- > (Text inputs).
204
+ > configuration with a YAML/JSON pane → `Q`. Plain text storage with rich composing →
205
+ > [Textarea](https://ui.mieweb.org/?path=/docs/text-inputs-textarea--docs) (Text inputs) — it renders `TextAreaRich`
206
+ > but keeps a plain-text `value`.
205
207
 
206
208
  **Encounter & orders** (Healthcare):
207
209
 
208
- > **What does the page lead with, and what data does it get?** Today's conclusions and the
210
+ > **What does the page lead with, and what data does it get?** A whole visit document with
211
+ > narrative, observations, coordinated vitals and MCP tools → `EncounterVisit` (eSheet-backed).
212
+ > Today's conclusions and the
209
213
  > orders placed for each problem → `Assessment` (plain props: concerns, items, orders). One
210
214
  > order in full → `OrderEditor` (morphs by type). What is _due_ from surveillance programs
211
215
  > and quality measures → `HealthSurveillance` (`PatientHistory` + `programs.json`). The banner
@@ -321,7 +325,8 @@ The one-line rule that governs each family. When a task touches a family, read i
321
325
 
322
326
  **Text inputs** (Inputs):
323
327
 
324
- > **What is the value?** Free text on one line → `Input`; several lines → `Textarea`. A phone
328
+ > **What is the value?** Free text on one line → `Input`; several lines → `Textarea` (a rich
329
+ > surface that keeps a plain-text value — `TextAreaPlain` for the native element). A phone
325
330
  > number → `PhoneInput` (or `PhoneInputGroup` for a typed list); a URL → `WebsiteInput` (or
326
331
  > `WebsiteInputGroup`) — never a raw `type="tel"` / `type="url"`. A postal address → `AddressForm`
327
332
  > to edit, `Address` to show. Every field gets an associated label: the `label` prop where the
@@ -259,17 +259,20 @@ lists of options in [Choice inputs](https://ui.mieweb.org/?path=/docs/inputs-cho
259
259
 
260
260
  > **What is the stored format, and who edits it?** Markdown that people write (and maybe
261
261
  > co-write) → `RichEditor`. HTML for templated letters with merge fields and dictation →
262
- > `RichTextEditor`. An **email** laid out from blocks and compiled to MJML → `EmailEditor`.
262
+ > `RichTextEditor`. HTML in a surface that should look like a plain textarea until asked →
263
+ > `TextAreaRich`. An **email** laid out from blocks and compiled to MJML → `EmailEditor`.
263
264
  > Markdown that is only **read** → `MarkdownRenderer`. A structured agent
264
- > configuration with a YAML/JSON pane → `Q`. Plain text → [Textarea](https://ui.mieweb.org/?path=/docs/text-inputs-textarea--docs)
265
- > (Text inputs).
265
+ > configuration with a YAML/JSON pane → `Q`. Plain text storage with rich composing →
266
+ > [Textarea](https://ui.mieweb.org/?path=/docs/text-inputs-textarea--docs) (Text inputs) — it renders `TextAreaRich`
267
+ > but keeps a plain-text `value`.
266
268
 
267
269
  ## Which one?
268
270
 
269
271
  | Component | Use it when | Not when |
270
272
  | --- | --- | --- |
271
273
  | [RichEditor](https://ui.mieweb.org/?path=/docs/editors-richeditor--docs) | The document is **Markdown**: headings, lists, tables, code; `getContent()` on submit; `collab.room` for Yjs co-editing; `CodeEditor` for source | The stored format is HTML or you need merge variables/dictation — `RichTextEditor`; the host cannot add the Kerebron peers and WASM assets |
272
- | [RichTextEditor](https://ui.mieweb.org/?path=/docs/editors-richtexteditor--docs) | The document is **HTML**: bold/italic/underline, lists, alignment, `variableGroups` inserting `{{tokens}}`, Web Speech dictation; no peers | You need Markdown, real undo history, headings/tables or collaboration — `RichEditor`; plain text — `Textarea` |
274
+ | [RichTextEditor](https://ui.mieweb.org/?path=/docs/editors-richtexteditor--docs) | The document is **HTML**: bold/italic/underline, lists, alignment, opt-in markdown block shortcuts (H1–H3, lists, quote), `variableGroups` inserting `{{tokens}}`, Web Speech dictation; no peers | You need Markdown, real undo history, links/tables/code or collaboration — `RichEditor`; plain text — `Textarea`; a textarea-like surface with the toolbar hidden — `TextAreaRich` |
275
+ | [TextAreaRich](https://ui.mieweb.org/?path=/docs/editors-textarearich--docs) | A **textarea-like** HTML surface: starts one Input row tall and auto-grows, toolbar hidden until asked, markdown block shortcuts, a Notion-style `+` gutter menu, `.shortcut` macros | The value must be **plain text** (form posts, bindings) — `Textarea` (this surface with a plain-text contract); a full document with an always-on toolbar, variables or dictation — `RichTextEditor` |
273
276
  | [EmailEditor](https://ui.mieweb.org/?path=/docs/editors-emaileditor--docs) | The document is an **email**: hero, columns, buttons, images, social, footer blocks on a drag-to-reorder canvas; `renderEmailMjml` serialises it | A single formatted body — `RichTextEditor`; sending, recipients and templates are the host's |
274
277
  | [Markdown](https://ui.mieweb.org/?path=/docs/editors-markdown--docs) | **Displaying** Markdown: sanitised HTML, code highlighting, `mermaid` / `csv` / `survey` / `html` fences, `streaming` for token-by-token AI output | The user edits the text — `RichEditor` / `RichTextEditor`; the source is HTML |
275
278
  | [Q](https://ui.mieweb.org/?path=/docs/editors-q--docs) | Admins configure an **agent** (prompt, tools, telephony) through a schema-generated form and see the YAML/JSON; `onSubmit(yaml)`, `onConfigChange` | Free-form prose — `RichEditor`; general clinical/business forms — ESheet (Composite forms) |
@@ -279,7 +282,9 @@ lists of options in [Choice inputs](https://ui.mieweb.org/?path=/docs/inputs-cho
279
282
  <!-- source: src/catalog/EncounterOrders.mdx (Healthcare) -->
280
283
  # Encounter & orders
281
284
 
282
- > **What does the page lead with, and what data does it get?** Today's conclusions and the
285
+ > **What does the page lead with, and what data does it get?** A whole visit document with
286
+ > narrative, observations, coordinated vitals and MCP tools → `EncounterVisit` (eSheet-backed).
287
+ > Today's conclusions and the
283
288
  > orders placed for each problem → `Assessment` (plain props: concerns, items, orders). One
284
289
  > order in full → `OrderEditor` (morphs by type). What is _due_ from surveillance programs
285
290
  > and quality measures → `HealthSurveillance` (`PatientHistory` + `programs.json`). The banner
@@ -291,6 +296,7 @@ lists of options in [Choice inputs](https://ui.mieweb.org/?path=/docs/inputs-cho
291
296
 
292
297
  | Component | Use it when | Not when |
293
298
  | --- | --- | --- |
299
+ | [EncounterVisit](https://ui.mieweb.org/?path=/docs/encounter-orders-encountervisit--docs) | A mobile-friendly anonymous visit document with configurable narrative / observation sections, repeated BP and other vitals, clinical lists, assessment and MCP tools sharing native eSheet responses | A single list or order panel; backend scheduling, signed records or clinical decision support |
294
300
  | [Assessment](https://ui.mieweb.org/?path=/docs/encounter-orders-assessment--docs) | The visit's **A&P**: `items` point at today's assertion of each concern; `orders` nest under problems via `concernId` (the durable IndicationLink); unified coded add row; unlinked bucket; drag to re-link | The chart problem list — `ProblemList`; relevance tagging — `PresentingProblems`; full order edits — `OrderEditor`; a due list — `HealthSurveillance` |
295
301
  | [OrderEditor](https://ui.mieweb.org/?path=/docs/encounter-orders-ordereditor--docs) | Editing one `AssessmentOrder` in full. Morphs: `medication` → `MedicationEditor` (NCPDP); `lab` / `imaging` / `procedure` / `referral` → typed editors with coded search, priority, timing, body site / refer-to | The inline display / detail edit Assessment already offers; reconciling presenting meds — `MedicationReconciliation` |
296
302
  | [HealthSurveillance](https://ui.mieweb.org/?path=/docs/encounter-orders-healthsurveillance--docs) | Showing what is **overdue / due / pending / done** for OSHA / DOT programs (`enrolledKeys`) and CMS eCQMs, from `evaluateDue(history, programs)`; each item is a picklist of satisfying orders → `onOrderMany` | You need the plan itself — `Assessment`; an order-history grid — the story-only `ChartOrdersGrid` demo on NITRO; rules beyond periodicity + age / sex gates |
@@ -631,7 +637,8 @@ executive summary (numbers as lettermark icons) and outlook, and `LeadFormSectio
631
637
  <!-- source: src/catalog/TextInputs.mdx (Inputs) -->
632
638
  # Text inputs
633
639
 
634
- > **What is the value?** Free text on one line → `Input`; several lines → `Textarea`. A phone
640
+ > **What is the value?** Free text on one line → `Input`; several lines → `Textarea` (a rich
641
+ > surface that keeps a plain-text value — `TextAreaPlain` for the native element). A phone
635
642
  > number → `PhoneInput` (or `PhoneInputGroup` for a typed list); a URL → `WebsiteInput` (or
636
643
  > `WebsiteInputGroup`) — never a raw `type="tel"` / `type="url"`. A postal address → `AddressForm`
637
644
  > to edit, `Address` to show. Every field gets an associated label: the `label` prop where the
@@ -642,7 +649,7 @@ executive summary (numbers as lettermark icons) and outlook, and `LeadFormSectio
642
649
  | Component | Use it when | Not when |
643
650
  | --- | --- | --- |
644
651
  | [Input](https://ui.mieweb.org/?path=/docs/text-inputs-input--docs) | One line of free text or a native type (`email`, `password`, `number`) | Phone / URL / date / fixed options — see the specialists |
645
- | [Textarea](https://ui.mieweb.org/?path=/docs/text-inputs-textarea--docs) | A sentence or more; a visible character budget (`showCount`) | Formatted or collaborative text — `RichEditor` |
652
+ | [Textarea](https://ui.mieweb.org/?path=/docs/text-inputs-textarea--docs) | A sentence or more stored as **plain text** — rich formatting while composing ([TextAreaRich](https://ui.mieweb.org/?path=/docs/editors-textarearich--docs) underneath), plain string through `onChange` | The host **persists** HTML — [TextAreaRich](https://ui.mieweb.org/?path=/docs/editors-textarearich--docs); native `<textarea>` behaviours (hard `maxLength`, validation, drag-resize, floating label) — `TextAreaPlain` (documented on the Textarea page); full documents — `RichEditor` / `RichTextEditor` |
646
653
  | [Label](https://ui.mieweb.org/?path=/docs/text-inputs-label--docs) | Labelling a control with no `label` prop (raw `<select>`, custom) | The control already takes `label` |
647
654
  | [PhoneInput](https://ui.mieweb.org/?path=/docs/text-inputs-phoneinput--docs) | Exactly one US/Canada number stored as 10 digits | Several typed numbers — `PhoneInputGroup`; international |
648
655
  | [PhoneInputGroup](https://ui.mieweb.org/?path=/docs/text-inputs-phoneinputgroup--docs) | A record holds several numbers and the type (cell, work, fax) matters | One number; rows need extra fields |
@@ -0,0 +1,133 @@
1
+ ---
2
+ name: mieweb-ui-i18n-checklist
3
+ description: Internationalization and RTL audit procedure for apps built with @mieweb/ui — string externalization, locale-bundle completeness, Intl formatting with the active locale, and RTL-safe layout (logical properties, direction-aware JS), plus the library's direction toolkit (useDirection, isRtl, isRtlLocale) and known RTL layout gotchas. USE WHEN auditing a component, page, or diff for i18n/RTL compliance, adding a new locale, fixing hardcoded strings or locales, or making a layout work right-to-left.
4
+ ---
5
+
6
+ # i18n & RTL auditing with @mieweb/ui
7
+
8
+ Policy baseline is Rule 10 of the installed `mieweb-ui.instructions.md`
9
+ (externalize all user-facing text; RTL-safe logical classes; `Intl` APIs for
10
+ dates/numbers/currency). The reference implementation of the org's i18n
11
+ pattern is `@mieweb/ui/datavis` (`packages/datavis/src/i18n/` in the library
12
+ repo): i18next + react-i18next with a canonical `en-US.json` plus one JSON
13
+ bundle per locale, and a `LocaleProvider`/`useLocale()` context that feeds
14
+ `Intl`/`toLocale*` formatting.
15
+
16
+ ## Audit procedure
17
+
18
+ Work through the four categories in order; for each finding record file,
19
+ line, issue, and fix.
20
+
21
+ 1. **String externalization.** Every user-facing string in JSX or in values
22
+ handed to the UI (toast/alert messages, `aria-label`s, placeholders,
23
+ button labels, empty-state text, error messages) must go through the
24
+ project's translation function (`t('…')` from `useTranslation()`).
25
+ Grep targets: quoted text in JSX children, string props named
26
+ `label`/`title`/`placeholder`/`aria-label`/`alt`, string arguments to
27
+ toast/alert/announce calls. Dev-only output (`console.*`, thrown `Error`
28
+ messages not shown to users) is exempt — note it as a judgment call, not
29
+ a finding.
30
+ 2. **Localized in the same commit + bundle completeness.** New `t()` keys
31
+ must land with entries in **every** locale bundle in the same commit —
32
+ not just `en-US`. A key present in the canonical bundle but missing from
33
+ any sibling bundle is a finding (i18next silently falls back to
34
+ `fallbackLng`, so the gap ships invisibly). Audit by diffing **logical**
35
+ keys: strip only the trailing i18next plural suffix (`_zero`, `_one`,
36
+ `_two`, `_few`, `_many`, `_other`) before comparing, because the
37
+ required plural forms differ per locale (English needs `items_one`/
38
+ `items_other`; Arabic needs all six) — a raw key-set diff would flag
39
+ Arabic's extra forms as orphaned and pass an Arabic bundle that only has
40
+ the English two. **Keep context suffixes** (`invite_admin`,
41
+ `invite_guest`) — each context variant is a distinct message, so
42
+ stripping them would hide a locale that's missing `invite_guest`; a
43
+ combined key like `invite_admin_one` normalizes to `invite_admin`. Flag
44
+ missing and orphaned logical keys, and separately verify each pluralized
45
+ key (per context variant) carries the plural forms **that locale's**
46
+ CLDR rules require.
47
+ 3. **Formatting via `Intl` with the active locale.** Dates, numbers, and
48
+ currency go through `Intl.*` / `toLocale*` APIs with the locale flowing
49
+ from the active language — `useLocale()` where the datavis-style
50
+ `LocaleProvider` is in scope, otherwise `i18n.language`. Findings:
51
+ - a hardcoded BCP-47 tag (`toLocaleDateString('en-US', …)`) — pins every
52
+ user to one locale;
53
+ - manual string formatting (`` `${month}/${day}/${year}` ``, `+ '%'`,
54
+ `'$' + amount`) where an `Intl` formatter belongs;
55
+ - **string concatenation or interpolation around `t()`** —
56
+ `t('greeting') + name` or `` `${t('count.prefix')} ${n}` `` breaks
57
+ word-order in other languages. Use i18next interpolation and plurals:
58
+ `t('greeting', { name })`, `t('items', { count })`.
59
+ 4. **RTL layout and direction-aware JS.** Everything below.
60
+
61
+ ## RTL checklist
62
+
63
+ The library is logical-properties-first; its CI ratchet
64
+ (`pnpm rtl:scan` against `scripts/rtl-baseline.json`, currently zero debt)
65
+ blocks new physical-direction styling in library code. Apps should hold the
66
+ same line:
67
+
68
+ - **Classes:** `ms-*`/`me-*`, `ps-*`/`pe-*`, `start-*`/`end-*`,
69
+ `text-start`/`text-end`, `border-s-*`/`border-e-*`, `rounded-s-*`/`rounded-e-*`
70
+ — never `ml-*`/`mr-*`, `pl-*`/`pr-*`, `left-*`/`right-*`,
71
+ `text-left`/`text-right`. `rtl:` variants only for true exceptions.
72
+ - **Inline styles evade class greps** — also check `style={{ … }}` for
73
+ `marginLeft`, `paddingRight`, `left`, `right`, `textAlign: 'left'`,
74
+ `float`; use `marginInlineStart`, `insetInlineStart`, `textAlign: 'start'`.
75
+ - **Directional icons** (chevrons, back/forward arrows) flip with
76
+ `rtl:-scale-x-100`; checkmarks, media controls, and up/down arrows do not.
77
+ - **Keyboard handlers:** ArrowLeft/ArrowRight must follow *visual*
78
+ direction. Use `isRtl(event.currentTarget)` inside handlers; use
79
+ `useDirection(ref)` (reactive) whenever direction drives rendering or
80
+ positioning math. Content rendered through a portal must read direction
81
+ from a non-portaled ref — the portal escapes local `dir` overrides.
82
+ - **Genuinely physical UI stays physical** — viewport-pinned toasts, resize
83
+ handles, geometry math tied to screen coordinates, LTR data islands
84
+ (code, phone numbers, URLs — wrap in `dir="ltr"`). Deliberate exceptions
85
+ deserve a comment, not a silent physical class.
86
+
87
+ ## Library direction toolkit
88
+
89
+ | Export (root entry) | Use for | Caveats |
90
+ | --- | --- | --- |
91
+ | `useDirection(ref?)` | Reactive `'ltr' \| 'rtl'` from the nearest `dir` attribute | Prefer it over `isRtl()` whenever direction drives rendering; pass a ref to respect local `dir` overrides |
92
+ | `isRtl(element?)` | One-shot check in event handlers | Snapshot, not reactive — stale if stored across renders; never call with a portaled element |
93
+ | `isRtlLocale(locale)` / `RTL_LOCALES` | Mapping a locale choice to `dir` (`ar`, `he`, `fa`, `ur`) | Checks the language subtag only |
94
+ | `cn()` (from `@mieweb/ui`) | Class merging where physical ⇄ logical pairs conflict correctly | Consumer `className="ml-2"` overrides still win over `ms-2` |
95
+
96
+ Set direction at the root: `<html dir="rtl">` (or a scoped
97
+ `dir` attribute), typically derived from the active language via
98
+ `isRtlLocale(i18n.language)`.
99
+
100
+ ## Adding a locale (datavis-style setup)
101
+
102
+ 1. Add `<locale>.json` next to the existing bundles covering every
103
+ **logical** key of the canonical bundle, with the plural forms the new
104
+ locale's CLDR rules require (not a copy of the canonical bundle's
105
+ suffixes).
106
+ 2. Register it in the i18next `resources` map where `ensureI18nInit()` (or
107
+ the app's equivalent init) builds the instance.
108
+ 3. Expose it in the app's language selector; on change call
109
+ `i18n.changeLanguage(code)` and set `dir` on **every** change —
110
+ `document.documentElement.dir = isRtlLocale(code) ? 'rtl' : 'ltr'` —
111
+ never only when the new locale is RTL, or switching back to an LTR
112
+ language leaves the UI mirrored.
113
+ 4. Verify `Intl` output (dates, numbers) in the new locale — no code changes
114
+ should be needed if locales were never hardcoded.
115
+
116
+ ## Testing
117
+
118
+ - Pseudo-check by switching language at runtime: untranslated strings stay
119
+ English (missing keys fall back silently — category 2).
120
+ - Flip `dir="rtl"` (the library Storybook has a direction toolbar;
121
+ `ar`/`he`/`fa`/`ur` locales imply it) and walk the layout: alignment,
122
+ icon direction, horizontal arrow keys, popover/tooltip anchoring.
123
+ - Long-text expansion: German/Russian strings run ~30% longer — look for
124
+ truncation and overflow at realistic lengths.
125
+
126
+ ## Verification checklist
127
+
128
+ - [ ] No hardcoded user-facing strings — all text through `t()`
129
+ - [ ] Every locale bundle covers the canonical bundle's logical keys (plural suffixes stripped, context variants kept distinct), with each locale's own required plural forms; new keys added to all bundles in the same commit
130
+ - [ ] No hardcoded locale tags — `Intl`/`toLocale*` driven by the active language
131
+ - [ ] No concatenation around `t()` — interpolation and `count` plurals
132
+ - [ ] No new physical-direction classes or inline styles; directional icons flip; arrow keys follow visual direction
133
+ - [ ] Layout verified in `dir="rtl"` and with a long-text locale
@@ -81,6 +81,11 @@ var miewebUISafelist = [
81
81
  "space-y-3",
82
82
  "top-[2.125rem]",
83
83
  "underline-offset-2",
84
+ // RichTextEsheet document shell: party-header spacing, and the editor's
85
+ // in-flow macro panel that clips its height animation below `md`.
86
+ "gap-x-1.5",
87
+ "space-y-0.5",
88
+ "md:overflow-visible",
84
89
  // MediaFeed vertical snapping, bounded captions, fullscreen viewport and
85
90
  // SuperChat attachment previews for consumers that do not scan package code.
86
91
  "h-[min(48rem,80dvh)]",
@@ -1910,5 +1915,5 @@ var tailwind_preset_default = miewebUIPreset;
1910
1915
  exports.miewebUIPreset = miewebUIPreset;
1911
1916
  exports.miewebUISafelist = miewebUISafelist;
1912
1917
  exports.tailwind_preset_default = tailwind_preset_default;
1913
- //# sourceMappingURL=chunk-INMDLVUB.cjs.map
1914
- //# sourceMappingURL=chunk-INMDLVUB.cjs.map
1918
+ //# sourceMappingURL=chunk-6UYMO3PF.cjs.map
1919
+ //# sourceMappingURL=chunk-6UYMO3PF.cjs.map