@mieweb/ui 0.11.0-dev.31 → 0.11.0-dev.32
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 +7 -7
- package/agent/agents/mieweb-ui-design.agent.md +8 -3
- package/agent/agents/mieweb-ui-i18n.agent.md +91 -0
- package/agent/agents/mieweb-ui-styling.agent.md +1 -1
- package/agent/skills/mieweb-ui-catalog/SKILL.md +15 -10
- package/agent/skills/mieweb-ui-catalog/selection-guidance.md +14 -7
- package/agent/skills/mieweb-ui-i18n-checklist/SKILL.md +133 -0
- package/package.json +1 -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 (
|
|
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
|
|
70
|
-
|
|
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
|
|
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
|
-
|
|
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`.
|
|
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 →
|
|
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?**
|
|
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
|
|
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`.
|
|
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 →
|
|
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,
|
|
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?**
|
|
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
|
|
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
|
|
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
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mieweb/ui",
|
|
3
|
-
"version": "0.11.0-dev.
|
|
3
|
+
"version": "0.11.0-dev.32",
|
|
4
4
|
"description": "A themeable, accessible React component library built with Tailwind CSS",
|
|
5
5
|
"author": "Medical Informatics Engineering, Inc.",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|