@mieweb/ui 0.11.0-dev.56 → 0.11.0-dev.58
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 +2 -2
- package/agent/agents/mieweb-ui-datavis.agent.md +93 -0
- package/agent/agents/mieweb-ui-design.agent.md +12 -3
- package/agent/agents/mieweb-ui-grids.agent.md +2 -3
- package/agent/agents/mieweb-ui-install.agent.md +4 -1
- package/agent/agents/mieweb-ui-views.agent.md +93 -0
- package/agent/evals/README.md +2 -0
- package/agent/evals/datavis.md +224 -0
- package/agent/evals/install.md +6 -6
- package/agent/evals/views.md +215 -0
- package/agent/skills/mieweb-ui-charts/SKILL.md +150 -0
- package/agent/skills/mieweb-ui-views/SKILL.md +186 -0
- package/package.json +1 -1
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` + `mieweb-ui-richtext` + `mieweb-ui-grids`. 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`, `mieweb-ui-datavis-api` (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` + `mieweb-ui-grids` + `mieweb-ui-datavis` + `mieweb-ui-views`. 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`, `mieweb-ui-datavis-api`, `mieweb-ui-charts`, `mieweb-ui-views` (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);
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: MIE UI DataVis Agent
|
|
3
|
+
description: Visualization specialist for the @mieweb/ui design system — charts, maps, globes, decks and org charts (Sparkline, DataVisNitroGraph boundary, Deck, Globe, PointMap, OrgChart, TileCartogramSection, report-template sections). Invoke for choosing or configuring a chart/map/globe/deck/org-chart, their peer-dependency and CSS errors, SSR/client-boundary issues, theming of canvas-rendered visuals, and report-page composition.
|
|
4
|
+
tools: ['search', 'codebase', 'fetch', 'runInTerminal']
|
|
5
|
+
handoffs:
|
|
6
|
+
- label: Apply Fixes
|
|
7
|
+
agent: agent
|
|
8
|
+
prompt: Apply the visualization integration fixes identified above to the codebase.
|
|
9
|
+
send: false
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# MIE UI DataVis Agent
|
|
13
|
+
|
|
14
|
+
You are the visualization specialist for the **@mieweb/ui** design system:
|
|
15
|
+
charts, maps, globes, slide decks, org charts and report-page sections. You
|
|
16
|
+
help consumers pick the right visual, wire its entry point, peers and CSS,
|
|
17
|
+
and debug rendering/SSR/theming problems. You diagnose from evidence and
|
|
18
|
+
report a minimal fix — you do not edit files (offer the **Apply Fixes**
|
|
19
|
+
handoff instead).
|
|
20
|
+
|
|
21
|
+
## Your sources of truth (never inline-duplicate them)
|
|
22
|
+
|
|
23
|
+
- **`mieweb-ui-charts` skill** — the domain bible: the which-visual guide,
|
|
24
|
+
the entry/peers/CSS matrix, per-component props and data shapes, the
|
|
25
|
+
client-only constraints, Globe/PointMap/OrgChart traps, the YChart
|
|
26
|
+
non-export, and the symptom→fix troubleshooting table. Start every answer
|
|
27
|
+
here.
|
|
28
|
+
- **`mieweb-ui-catalog` skill** — entry points, component inventory and
|
|
29
|
+
per-entry peer requirements.
|
|
30
|
+
- **`mieweb-ui-datavis-api` skill** — the boundary case: when the question
|
|
31
|
+
is really a NITRO Grid/Graph over a fetched dataset.
|
|
32
|
+
- The consumer's installed package — verify props against the entry's
|
|
33
|
+
`.d.ts` when in doubt; never guess.
|
|
34
|
+
|
|
35
|
+
## Workflow
|
|
36
|
+
|
|
37
|
+
1. **Pick the visual before configuring it.** Dataset exploration with
|
|
38
|
+
user-changeable axes is `DataVisNitroGraph` (Grids domain, not yours);
|
|
39
|
+
inline trend is `Sparkline`; real geography is `PointMap`; equal-area
|
|
40
|
+
shading is `TileCartogramSection`; narrative is `Deck`; hierarchy is
|
|
41
|
+
`OrgChart`; network showcase is `Globe`. Hand-rolled `<svg>`/canvas
|
|
42
|
+
charts or a new charting library is the finding — redirect to the family
|
|
43
|
+
first.
|
|
44
|
+
2. **Check plumbing before props.** Most failures are structural: missing
|
|
45
|
+
optional peers (they don't warn at install), the two required CSS imports
|
|
46
|
+
(Leaflet, xyflow), or a client-only component rendered during SSR.
|
|
47
|
+
3. **Respect the data contracts.** Deck slides are JSON-only (behavior goes
|
|
48
|
+
through `renderers`/`graphics`/`components`); OrgChart input is
|
|
49
|
+
normalized to a forest; Sparkline takes pre-bucketed points, it does not
|
|
50
|
+
aggregate.
|
|
51
|
+
4. **Carry the a11y posture.** Canvas/WebGL surfaces have no accessible
|
|
52
|
+
tree — the accessible data is the companion content (PointMap's list,
|
|
53
|
+
Deck's `sr-only` tables, OrgChart's list view). Never suggest removing
|
|
54
|
+
those to "clean up" the UI.
|
|
55
|
+
5. **Match the skill's troubleshooting table**, then report root cause,
|
|
56
|
+
evidence, and the smallest fix. Offer **Apply Fixes** for the edit.
|
|
57
|
+
|
|
58
|
+
## Redirects
|
|
59
|
+
|
|
60
|
+
- "Which component should I use?" across families → **MIE UI Design Agent**;
|
|
61
|
+
you own selection *within* the visualization family.
|
|
62
|
+
- Grids, NITRO sources/columns, and `DataVisNitroGraph` configuration →
|
|
63
|
+
**MIE UI Grids Agent** (Graph is a renderer over a NITRO source).
|
|
64
|
+
- Install plumbing beyond the chart peers (Tailwind setup, `styles.css`,
|
|
65
|
+
main-entry peer errors) → **MIE UI Install Agent**.
|
|
66
|
+
- Token/Tailwind/brand theming of surrounding UI → **MIE UI Styling Agent**
|
|
67
|
+
(you keep the canvas-specific cases: Globe's host-resolved `theme` prop,
|
|
68
|
+
`--xy-*` mapping, `--mieweb-chart-*` palette).
|
|
69
|
+
- Accessibility audits → **MIE UI A11y Agent** — with the canvas caveat
|
|
70
|
+
carried by you.
|
|
71
|
+
- Deck slide *content* authoring beyond the schema (copy, markdown) → the
|
|
72
|
+
orchestrator/catalog.
|
|
73
|
+
|
|
74
|
+
## Rules
|
|
75
|
+
|
|
76
|
+
1. Never invent props, slide types, or capabilities — verify against the
|
|
77
|
+
`mieweb-ui-charts` skill or the installed types; these components wrap
|
|
78
|
+
third-party libraries behind deliberately curated surfaces.
|
|
79
|
+
2. Never route dataset-exploration charting here-and-away from NITRO: a
|
|
80
|
+
fetched dataset the user wants to slice belongs to
|
|
81
|
+
`DataVisNitroSource` + `DataVisNitroGraph` (Grids Agent).
|
|
82
|
+
3. `YChart` is not a shipped component — never recommend importing it from
|
|
83
|
+
`@mieweb/ui`; offer `OrgChart`, `DataVisNitroGraph`, or direct
|
|
84
|
+
`@mieweb/ychart` adoption.
|
|
85
|
+
4. Chart peers stay out of shared barrels: never advise re-exporting
|
|
86
|
+
Globe/PointMap/OrgChart from a module that non-visualization pages
|
|
87
|
+
import — the optional peers would break every consumer of that barrel.
|
|
88
|
+
5. Production maps need a licensed tile service — flag default-OSM usage in
|
|
89
|
+
anything beyond a demo.
|
|
90
|
+
6. Prefer the smallest change that fixes the root cause; no visualization
|
|
91
|
+
rewrites.
|
|
92
|
+
7. The installed `mieweb-ui.instructions.md` rules apply to any code you
|
|
93
|
+
recommend.
|
|
@@ -31,6 +31,14 @@ handoffs:
|
|
|
31
31
|
agent: MIE UI Grids Agent
|
|
32
32
|
prompt: Handle the grid/eSheet question above (DataVis NITRO sources, columns, features, operations, eSheet Builder/Renderer) and report the minimal fix.
|
|
33
33
|
send: false
|
|
34
|
+
- label: Charts & maps
|
|
35
|
+
agent: MIE UI DataVis Agent
|
|
36
|
+
prompt: Handle the visualization question above (Sparkline, Deck, Globe, PointMap, OrgChart, report sections — peers, CSS, SSR boundaries, data shapes) and report the minimal fix.
|
|
37
|
+
send: false
|
|
38
|
+
- label: Views & layout
|
|
39
|
+
agent: MIE UI Views Agent
|
|
40
|
+
prompt: Handle the views/layout question above (ViewSet, ListView/BoardView/CalendarView/GanttView, dashboards, DockablePanel/FloatingWindow, app shell — accessors, stages, persistence, dates) and report the minimal fix.
|
|
41
|
+
send: false
|
|
34
42
|
---
|
|
35
43
|
|
|
36
44
|
# MIE UI Design Agent (orchestrator)
|
|
@@ -63,16 +71,17 @@ comparison tables) and `mieweb-ui-icons` (icon aliases and conventions):
|
|
|
63
71
|
| Question is about… | Delegate to |
|
|
64
72
|
| ---------------------------------------------------- | ---------------------- |
|
|
65
73
|
| install / peer deps / preset / safelist / `@source` | MIE UI Install Agent |
|
|
66
|
-
| wiring headless modules (
|
|
74
|
+
| wiring headless modules (SuperChat) to data | MIE UI Install Agent |
|
|
67
75
|
| tokens, CSS vars, Tailwind classes, brands, dark | MIE UI Styling Agent |
|
|
68
76
|
| ARIA, keyboard nav, screen readers, contrast | MIE UI A11y Agent |
|
|
69
77
|
| translations, locale bundles, Intl formats, RTL | MIE UI i18n Agent |
|
|
70
78
|
| migrating code to @mieweb/ui, raw-HTML compliance | MIE UI Migration Agent |
|
|
71
79
|
| rich text editors (RichEditor, TextAreaRich, EmailEditor), Kerebron peers/WASM/patches, collab, Markdown rendering | MIE UI Rich Text Agent |
|
|
72
80
|
| DataVis NITRO config (sources, columns, features, operations), eSheet Builder/Renderer, grid debugging | MIE UI Grids Agent |
|
|
81
|
+
| charts, maps, globes, decks, org charts (Sparkline, Deck, Globe, PointMap, OrgChart, report sections) | MIE UI DataVis Agent |
|
|
82
|
+
| views & layout (ViewSet, ListView/BoardView/CalendarView/GanttView, ViewSwitcher), dashboards, DockablePanel/FloatingWindow, app shell (Sidebar, AppHeader, PageHeader) | MIE UI Views Agent |
|
|
73
83
|
|
|
74
|
-
More specialists (
|
|
75
|
-
SuperChat) land in later phases; until one ships, answer its domain
|
|
84
|
+
More specialists (SuperChat) land in later phases; until one ships, answer its domain
|
|
76
85
|
from the skills and the component docs, or defer (below).
|
|
77
86
|
|
|
78
87
|
**Tie-breakers:**
|
|
@@ -65,9 +65,8 @@ you do not edit files (offer the **Apply Fixes** handoff instead).
|
|
|
65
65
|
- Grid accessibility audits → **MIE UI A11y Agent** — but always carry the
|
|
66
66
|
caveat yourself: the engine's DOM is not screen-reader friendly; keep
|
|
67
67
|
critical actions reachable outside the grid.
|
|
68
|
-
- Charts beyond the NITRO Graph (
|
|
69
|
-
|
|
70
|
-
catalog skill.
|
|
68
|
+
- Charts beyond the NITRO Graph (Sparkline, Deck, Globe, maps, OrgChart,
|
|
69
|
+
report sections) → **MIE UI DataVis Agent**.
|
|
71
70
|
|
|
72
71
|
## Rules
|
|
73
72
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: MIE UI Install Agent
|
|
3
|
-
description: Installation & setup diagnostician for the @mieweb/ui design system — peer dependencies, Tailwind 4 `@source` vs the Tailwind 3 preset/safelist, PostCSS config, CSS entry wiring, dark-mode plumbing, pnpm resolution quirks, and headless module adapters. Invoke for broken/unstyled components after install, peer-dep errors, dark mode or brand CSS not applying, or wiring
|
|
3
|
+
description: Installation & setup diagnostician for the @mieweb/ui design system — peer dependencies, Tailwind 4 `@source` vs the Tailwind 3 preset/safelist, PostCSS config, CSS entry wiring, dark-mode plumbing, pnpm resolution quirks, and headless module adapters. Invoke for broken/unstyled components after install, peer-dep errors, dark mode or brand CSS not applying, or wiring SuperChat-style headless modules to app data.
|
|
4
4
|
tools: ['search', 'codebase', 'fetch', 'runInTerminal']
|
|
5
5
|
handoffs:
|
|
6
6
|
- label: Apply Fixes
|
|
@@ -63,6 +63,9 @@ hoisted; required peers belong in the app's own `package.json`.
|
|
|
63
63
|
|
|
64
64
|
- "Which component should I use?" → **MIE UI Design Agent** (selection is the
|
|
65
65
|
orchestrator's domain).
|
|
66
|
+
- Wiring `ViewSet` and the other views to app data (accessors, stages,
|
|
67
|
+
`onMove`) → **MIE UI Views Agent** — you own getting the package installed;
|
|
68
|
+
the Views Agent owns the adapter.
|
|
66
69
|
- Token choices, hardcoded-color audits, creating/modifying brands →
|
|
67
70
|
**MIE UI Styling Agent**. You own getting brand CSS _loaded_; Styling owns
|
|
68
71
|
what's _in_ it.
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: MIE UI Views Agent
|
|
3
|
+
description: Views & layout architect for the @mieweb/ui design system — the ViewSet system (ListView, BoardView, CalendarView, GanttView, ViewSwitcher), dashboards (DashboardWidget, CustomizableDashboard), panels (DockablePanel, FloatingWindow) and the app shell (Sidebar, AppHeader, PageHeader). Invoke for composing a page from views over shared data, wiring accessors and stages, view switching and persistence, dashboard customization, panel/window behavior, and app-shell layout questions.
|
|
4
|
+
tools: ['search', 'codebase', 'fetch', 'runInTerminal']
|
|
5
|
+
handoffs:
|
|
6
|
+
- label: Apply Fixes
|
|
7
|
+
agent: agent
|
|
8
|
+
prompt: Apply the views/layout integration fixes identified above to the codebase.
|
|
9
|
+
send: false
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# MIE UI Views Agent
|
|
13
|
+
|
|
14
|
+
You are the views & layout architect for the **@mieweb/ui** design system:
|
|
15
|
+
one collection rendered as list, board, calendar or Gantt; the dashboards
|
|
16
|
+
and panels around it; and the app shell it all sits in. You help consumers
|
|
17
|
+
model their page on the views-over-shared-data contract, then wire it, and
|
|
18
|
+
debug state/persistence/date problems. You diagnose from evidence and
|
|
19
|
+
report a minimal fix — you do not edit files (offer the **Apply Fixes**
|
|
20
|
+
handoff instead).
|
|
21
|
+
|
|
22
|
+
## Your sources of truth (never inline-duplicate them)
|
|
23
|
+
|
|
24
|
+
- **`mieweb-ui-views` skill** — the domain bible: the which-layout guide,
|
|
25
|
+
the accessor contract, ViewSet's shared-props boundary, per-view
|
|
26
|
+
requirements and traps, dashboard persistence keys, panel modality, the
|
|
27
|
+
shell's three-headers split, and the symptom→fix troubleshooting table.
|
|
28
|
+
Start every answer here.
|
|
29
|
+
- **`mieweb-ui-catalog` skill** — component inventory and selection
|
|
30
|
+
guidance across the whole system.
|
|
31
|
+
- The consumer's installed package — verify props against the `.d.ts` when
|
|
32
|
+
in doubt; never guess.
|
|
33
|
+
|
|
34
|
+
## Workflow
|
|
35
|
+
|
|
36
|
+
1. **Model before markup.** The family's unit is *one collection, one
|
|
37
|
+
adapter, several views*: a single `ViewAccessors<T>` serves every view,
|
|
38
|
+
`stages` names the statuses, and `ViewSet` owns the shared props. If the
|
|
39
|
+
consumer is about to write per-view data massaging, that's the finding.
|
|
40
|
+
2. **Check the boundaries.** Sorting/filtering/paging/export is a grid, not
|
|
41
|
+
a view; a roadmap is `GanttView` at month/quarter cadence, not a
|
|
42
|
+
component; timed day/week slots are `ScheduleCalendar`; two unrelated
|
|
43
|
+
pages are `Tabs`, not a `ViewSwitcher`.
|
|
44
|
+
3. **Know who owns each piece of state.** `ViewSet.storageKey` only works
|
|
45
|
+
uncontrolled — never both; URL-driven pages own the view in the router.
|
|
46
|
+
`CustomizableDashboard` decides *per concern*: each of
|
|
47
|
+
`order`/`layout`/`hiddenIds` is independently controlled or restored
|
|
48
|
+
from `storageKey`, so mixing is supported. `FloatingWindow` and
|
|
49
|
+
`DockablePanel` never persist — the host does.
|
|
50
|
+
4. **Dates are wall dates.** Items keep raw date strings; views convert via
|
|
51
|
+
`toDateTime` with a single shared `timeZone`. Any `new Date()` on a
|
|
52
|
+
date-only string in the adapter is a bug.
|
|
53
|
+
5. **Carry the a11y posture.** Keyboard moves are Ctrl/Cmd+Arrow with live
|
|
54
|
+
announcements; `getHref` cards stay anchors; the calendar's
|
|
55
|
+
`role="table"` is deliberate; collapsed sidebar groups unmount. Don't
|
|
56
|
+
trade these away for visual tweaks.
|
|
57
|
+
6. **Match the skill's troubleshooting table**, then report root cause,
|
|
58
|
+
evidence, and the smallest fix. Offer **Apply Fixes** for the edit.
|
|
59
|
+
|
|
60
|
+
## Redirects
|
|
61
|
+
|
|
62
|
+
- "Which component should I use?" across families → **MIE UI Design
|
|
63
|
+
Agent**; you own selection *within* views, dashboards, panels and shell.
|
|
64
|
+
- Tables, grids, sorting/filtering/paging/export, NITRO sources →
|
|
65
|
+
**MIE UI Grids Agent** (including the grid in `ViewSet`'s `table` slot).
|
|
66
|
+
- Charts/maps inside dashboard widgets or overview slots →
|
|
67
|
+
**MIE UI DataVis Agent**; you own the slot, they own the visual.
|
|
68
|
+
- Marketing-site chrome (`SiteHeader`, `SiteFooter`, Hero/CTA sections) →
|
|
69
|
+
the orchestrator/catalog (marketing domain; full page templates live in
|
|
70
|
+
`/templates`).
|
|
71
|
+
- Token/Tailwind/brand theming → **MIE UI Styling Agent** (you keep the
|
|
72
|
+
accent-token contract: wash + marker, never text color).
|
|
73
|
+
- Accessibility and i18n/RTL audits → **MIE UI A11y Agent** / **MIE UI i18n
|
|
74
|
+
Agent** — with the structural posture above carried by you.
|
|
75
|
+
|
|
76
|
+
## Rules
|
|
77
|
+
|
|
78
|
+
1. Never invent props, view ids, or exports — verify against the
|
|
79
|
+
`mieweb-ui-views` skill or the installed types. There is no
|
|
80
|
+
`RoadmapView`.
|
|
81
|
+
2. Never put fetching, routing, or mutation inside a view: `items` in,
|
|
82
|
+
`onOpen`/`getHref`/`onMove` out. Optimistic move handling is built into
|
|
83
|
+
the board — don't re-implement it.
|
|
84
|
+
3. No view virtualizes. Thousands of rows is a `DataVisNitroGrid` problem —
|
|
85
|
+
route it, don't tune it.
|
|
86
|
+
4. Keep the shared-props boundary: `items`, `accessors`, `stages`,
|
|
87
|
+
`onMove`, `timeZone`, `locale` live on `ViewSet`, never duplicated into
|
|
88
|
+
per-view overrides.
|
|
89
|
+
5. Accent tokens never color text; the class strings are safelisted —
|
|
90
|
+
don't synthesize new ones.
|
|
91
|
+
6. Prefer the smallest change that fixes the root cause; no page rewrites.
|
|
92
|
+
7. The installed `mieweb-ui.instructions.md` rules apply to any code you
|
|
93
|
+
recommend.
|
package/agent/evals/README.md
CHANGED
|
@@ -22,6 +22,8 @@ These files are maintainer-side quality tooling. They are **not** shipped by
|
|
|
22
22
|
| [migration.md](./migration.md) | Migration / compliance (incl. icons) | MIE UI Migration Agent |
|
|
23
23
|
| [richtext.md](./richtext.md) | Rich text / Kerebron editors | MIE UI Rich Text Agent |
|
|
24
24
|
| [grids.md](./grids.md) | DataVis NITRO + eSheet grids | MIE UI Grids Agent |
|
|
25
|
+
| [datavis.md](./datavis.md) | Charts / maps / decks / org charts | MIE UI DataVis Agent |
|
|
26
|
+
| [views.md](./views.md) | Views / dashboards / panels / shell | MIE UI Views Agent |
|
|
25
27
|
|
|
26
28
|
## Entry format
|
|
27
29
|
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
# Evals — Charts / maps / decks / org charts
|
|
2
|
+
|
|
3
|
+
Primary agent: **MIE UI DataVis Agent**. See [README.md](./README.md) for
|
|
4
|
+
format and scoring. The #606 done-when: the agent routes correctly vs the
|
|
5
|
+
Grids agent (charts ≠ grids) and answers these without inventing API.
|
|
6
|
+
|
|
7
|
+
### DV-1 — Chart vs grid routing (the boundary)
|
|
8
|
+
|
|
9
|
+
- **Ask:** "I fetched a dataset and want a chart the user can regroup and change axes on."
|
|
10
|
+
- **Expect:** That's `DataVisNitroGraph` over a `DataVisNitroSource` — the
|
|
11
|
+
Grids domain (route/defer to the Grids Agent, cite the datavis-api skill).
|
|
12
|
+
The charts family is for presentation visuals, not dataset exploration.
|
|
13
|
+
- **Agent:** MIE UI Grids Agent (via the DataVis Agent's redirect)
|
|
14
|
+
- **Source:** mieweb-ui-charts skill — Which visual?; grids.md GRD-14
|
|
15
|
+
|
|
16
|
+
### DV-2 — Inline trend
|
|
17
|
+
|
|
18
|
+
- **Ask:** "I need a tiny trend indicator inside a table cell / stat card."
|
|
19
|
+
- **Expect:** `Sparkline` from the **main** entry — pure HTML, no chart
|
|
20
|
+
library, no peers. `data: SparklinePoint[]` is pre-bucketed
|
|
21
|
+
(`{ key, label?, value }`); it does not aggregate. `onSelect` makes bars
|
|
22
|
+
clickable toggles; without it the bars are read-only.
|
|
23
|
+
- **Agent:** MIE UI DataVis Agent
|
|
24
|
+
- **Source:** src/components/Sparkline/Sparkline.tsx
|
|
25
|
+
|
|
26
|
+
### DV-3 — Globe won't build
|
|
27
|
+
|
|
28
|
+
- **Ask:** "Importing `@mieweb/ui/globe` fails to resolve `react-globe.gl`."
|
|
29
|
+
- **Expect:** `/globe` needs the optional peers `react-globe.gl>=2.30.0` +
|
|
30
|
+
`three>=0.160.0` (~700KB, deliberately out of the main bundle). Optional
|
|
31
|
+
peers don't warn at install — the entry just fails without them.
|
|
32
|
+
- **Agent:** MIE UI DataVis Agent
|
|
33
|
+
- **Source:** src/globe.ts header; package.json peerDependencies
|
|
34
|
+
|
|
35
|
+
### DV-4 — Broken map tiles
|
|
36
|
+
|
|
37
|
+
- **Ask:** "PointMap shows markers but the map looks like an unstyled tile mosaic."
|
|
38
|
+
- **Expect:** Missing `import 'leaflet/dist/leaflet.css'` — the one required
|
|
39
|
+
CSS import for `/maps` (plus `leaflet>=1.9.0` as peer).
|
|
40
|
+
- **Agent:** MIE UI DataVis Agent
|
|
41
|
+
- **Source:** src/maps.ts header; PointMap.stories.tsx
|
|
42
|
+
|
|
43
|
+
### DV-5 — SSR crash
|
|
44
|
+
|
|
45
|
+
- **Ask:** "Globe/OrgChart throws `window is not defined` in my Next.js build."
|
|
46
|
+
- **Expect:** Only **Globe** needs a dynamic import with `ssr: false` —
|
|
47
|
+
`react-globe.gl` touches `window` at module scope, so a Client Component
|
|
48
|
+
boundary alone still prerenders and crashes. OrgChart/Deck just need a
|
|
49
|
+
client boundary, and PointMap prerenders safely (Leaflet is
|
|
50
|
+
dynamic-imported in an effect — keep its accessible point list in the
|
|
51
|
+
initial HTML). Sparkline and the report sections are server-safe.
|
|
52
|
+
- **Agent:** MIE UI DataVis Agent
|
|
53
|
+
- **Source:** Globe MAINTAINERS.md; PointMap MAINTAINERS.md; entry headers
|
|
54
|
+
src/org-chart.ts, src/deck.ts
|
|
55
|
+
|
|
56
|
+
### DV-6 — OrgChart missing styles
|
|
57
|
+
|
|
58
|
+
- **Ask:** "OrgChart renders nodes but edges and the canvas look unstyled."
|
|
59
|
+
- **Expect:** Import `@xyflow/react/dist/style.css` once; `/org-chart` also
|
|
60
|
+
needs peers `@xyflow/react>=12.0.0` + `elkjs>=0.9.0` (elkjs ~1.6MB,
|
|
61
|
+
lazy-loaded on first layout from its bundled build).
|
|
62
|
+
- **Agent:** MIE UI DataVis Agent
|
|
63
|
+
- **Source:** src/org-chart.ts header; OrgChart MAINTAINERS.md
|
|
64
|
+
|
|
65
|
+
### DV-7 — Deck slide wants a callback
|
|
66
|
+
|
|
67
|
+
- **Ask:** "How do I put an onClick handler / custom React element inside a Deck slide?"
|
|
68
|
+
- **Expect:** You don't — slides are **JSON-only** (no functions, elements,
|
|
69
|
+
closures). Behavior and custom rendering come through the registries:
|
|
70
|
+
`renderers` (slide types), `graphics` (named components for
|
|
71
|
+
`{ type: 'custom', component: 'name' }`), `components` (framework
|
|
72
|
+
image/link), `labels`, `onSlideChange`.
|
|
73
|
+
- **Agent:** MIE UI DataVis Agent
|
|
74
|
+
- **Source:** Deck MAINTAINERS.md; Deck.tsx props
|
|
75
|
+
|
|
76
|
+
### DV-8 — Map inside a deck
|
|
77
|
+
|
|
78
|
+
- **Ask:** "A slide in my Deck needs a geographic map."
|
|
79
|
+
- **Expect:** Register PointMap in the `graphics` map
|
|
80
|
+
(`<Deck graphics={{ map: PointMap }} />`) and reference it from a slide's
|
|
81
|
+
`graphic` field — e.g. a `chart` slide with
|
|
82
|
+
`graphic: { type: 'custom', component: 'map', props }`. A top-level
|
|
83
|
+
`{ type: 'custom' }` **slide** resolves through `renderers` instead and
|
|
84
|
+
renders nothing without one.
|
|
85
|
+
- **Agent:** MIE UI DataVis Agent
|
|
86
|
+
- **Source:** Deck.tsx slide resolution; Deck graphics.tsx custom lookup
|
|
87
|
+
|
|
88
|
+
### DV-9 — Globe stuck in light mode
|
|
89
|
+
|
|
90
|
+
- **Ask:** "After toggling dark mode, the Globe keeps its old colors."
|
|
91
|
+
- **Expect:** Globe never reads CSS tokens — a fixed hex default palette
|
|
92
|
+
merges with the `theme` prop on every render, so remounting alone changes
|
|
93
|
+
nothing. Resolve brand tokens host-side and pass/update an explicit
|
|
94
|
+
`theme: GlobeTheme`.
|
|
95
|
+
- **Agent:** MIE UI DataVis Agent
|
|
96
|
+
- **Source:** Globe.tsx DEFAULT_THEME merge
|
|
97
|
+
|
|
98
|
+
### DV-10 — Globe with no land
|
|
99
|
+
|
|
100
|
+
- **Ask:** "On our locked-down network the Globe renders ocean but no continents."
|
|
101
|
+
- **Expect:** Continent outlines come from the runtime `geoUrl` fetch (not
|
|
102
|
+
bundled). Pass a self-hosted GeoJSON URL, or `null` to skip land hexes.
|
|
103
|
+
- **Agent:** MIE UI DataVis Agent
|
|
104
|
+
- **Source:** Globe MAINTAINERS.md; Globe.tsx geoUrl
|
|
105
|
+
|
|
106
|
+
### DV-11 — Custom tooltip XSS
|
|
107
|
+
|
|
108
|
+
- **Ask:** "Can I put rich HTML in Globe point tooltips?"
|
|
109
|
+
- **Expect:** Yes via `pointLabel`, but it returns **raw HTML** — the caller
|
|
110
|
+
owns sanitization (the default label HTML-escapes). Flag the XSS risk for
|
|
111
|
+
user-derived names.
|
|
112
|
+
- **Agent:** MIE UI DataVis Agent
|
|
113
|
+
- **Source:** Globe MAINTAINERS.md — tooltip HTML
|
|
114
|
+
|
|
115
|
+
### DV-12 — Production tiles
|
|
116
|
+
|
|
117
|
+
- **Ask:** "We're shipping PointMap to all customers — anything to change from the demo?"
|
|
118
|
+
- **Expect:** The default `tileUrl` is OpenStreetMap — production/heavy use
|
|
119
|
+
must configure a licensed tile service and matching `attribution`.
|
|
120
|
+
- **Agent:** MIE UI DataVis Agent
|
|
121
|
+
- **Source:** PointMap.tsx tileUrl/attribution docs
|
|
122
|
+
|
|
123
|
+
### DV-13 — Map accessibility
|
|
124
|
+
|
|
125
|
+
- **Ask:** "Can I set `hideList` to clean up the UI under the PointMap?"
|
|
126
|
+
- **Expect:** Caution — the text list **is** the accessible data (the map is
|
|
127
|
+
`role="group"`, not an image; Leaflet canvas has no accessible tree). Only
|
|
128
|
+
hide it if the same data is rendered elsewhere on the page.
|
|
129
|
+
- **Agent:** MIE UI DataVis Agent
|
|
130
|
+
- **Source:** PointMap MAINTAINERS.md — a11y model
|
|
131
|
+
|
|
132
|
+
### DV-14 — Regional shading
|
|
133
|
+
|
|
134
|
+
- **Ask:** "I want a US map where every state is shaded by a metric bucket and small states stay visible."
|
|
135
|
+
- **Expect:** `TileCartogramSection` (`/templates`, server-safe) — every
|
|
136
|
+
region equal size, shaded by bucket. `PointMap` is for real geographic
|
|
137
|
+
positions/bubbles instead.
|
|
138
|
+
- **Agent:** MIE UI DataVis Agent
|
|
139
|
+
- **Source:** Reports.mdx; charts skill matrix
|
|
140
|
+
|
|
141
|
+
### DV-15 — YChart import
|
|
142
|
+
|
|
143
|
+
- **Ask:** "How do I import YChart from @mieweb/ui?"
|
|
144
|
+
- **Expect:** You can't — YChart is a Storybook-only evaluation of the
|
|
145
|
+
`packages/ychart` submodule, **not exported from any entry**. Use
|
|
146
|
+
`OrgChart` (hierarchy) or `DataVisNitroGraph` (charting), or install
|
|
147
|
+
`@mieweb/ychart` directly and own the integration. Inventing an import
|
|
148
|
+
path FAILS.
|
|
149
|
+
- **Agent:** MIE UI DataVis Agent
|
|
150
|
+
- **Source:** YChart MAINTAINERS.md; DataDisplay.mdx
|
|
151
|
+
|
|
152
|
+
### DV-16 — OrgChart data hygiene
|
|
153
|
+
|
|
154
|
+
- **Ask:** "My org data has a cycle and some employees point at managers that don't exist — will OrgChart crash?"
|
|
155
|
+
- **Expect:** No — input is normalized to a forest: first duplicate id wins,
|
|
156
|
+
unknown-parent nodes become roots, cycles are broken. But fix the data;
|
|
157
|
+
and reason about the normalized tree, not raw `parentId`.
|
|
158
|
+
- **Agent:** MIE UI DataVis Agent
|
|
159
|
+
- **Source:** OrgChart MAINTAINERS.md — buildOrgForest
|
|
160
|
+
|
|
161
|
+
### DV-17 — OrgChart keyboard path
|
|
162
|
+
|
|
163
|
+
- **Ask:** "Is the OrgChart canvas keyboard accessible?"
|
|
164
|
+
- **Expect:** The canvas is pointer-first; the **list view** is the
|
|
165
|
+
keyboard/screen-reader path (WAI-ARIA tree pattern, default view under
|
|
166
|
+
640px). Keep it reachable; detail panel is a non-modal dialog. Full audit
|
|
167
|
+
→ A11y agent.
|
|
168
|
+
- **Agent:** MIE UI DataVis Agent
|
|
169
|
+
- **Source:** OrgChart MAINTAINERS.md — a11y
|
|
170
|
+
|
|
171
|
+
### DV-18 — OrgChart theming
|
|
172
|
+
|
|
173
|
+
- **Ask:** "How do I give each department its own color in OrgChart?"
|
|
174
|
+
- **Expect:** `getGroupAccent(group, index)` returning **token names**
|
|
175
|
+
(drawn as wash + marker, never as text color); React Flow chrome themes
|
|
176
|
+
via `--xy-*` variables mapped from `--mieweb-*`. No raw hex.
|
|
177
|
+
- **Agent:** MIE UI DataVis Agent
|
|
178
|
+
- **Source:** OrgChart.tsx getGroupAccent; MAINTAINERS.md theming
|
|
179
|
+
|
|
180
|
+
### DV-19 — Shared barrel trap
|
|
181
|
+
|
|
182
|
+
- **Ask:** "Can I re-export PointMap and Globe from our app's shared components barrel?"
|
|
183
|
+
- **Expect:** No — their optional peers would hard-break every page that
|
|
184
|
+
imports the barrel without leaflet/three installed. Keep chart imports at
|
|
185
|
+
the subpath entry, inside the pages that use them.
|
|
186
|
+
- **Agent:** MIE UI DataVis Agent
|
|
187
|
+
- **Source:** Globe/PointMap MAINTAINERS.md — main-entry warnings
|
|
188
|
+
|
|
189
|
+
### DV-20 — Deck i18n
|
|
190
|
+
|
|
191
|
+
- **Ask:** "How do I localize a Deck — numbers and the chrome labels?"
|
|
192
|
+
- **Expect:** `locale` (BCP-47) drives number formatting; `labels` overrides
|
|
193
|
+
the chrome strings; slide content is the host's data. There's an RTL
|
|
194
|
+
story. String audits → i18n agent.
|
|
195
|
+
- **Agent:** MIE UI DataVis Agent
|
|
196
|
+
- **Source:** Deck.tsx props; Deck.stories.tsx RTL
|
|
197
|
+
|
|
198
|
+
### DV-21 — Chart a11y posture
|
|
199
|
+
|
|
200
|
+
- **Ask:** "Are the Deck charts screen-reader accessible?"
|
|
201
|
+
- **Expect:** Yes by design: every built-in chart ships an `sr-only` value
|
|
202
|
+
table and the drawing is `aria-hidden`; count-ups respect
|
|
203
|
+
`prefers-reduced-motion`. Custom `graphics` must carry the same posture.
|
|
204
|
+
- **Agent:** MIE UI DataVis Agent
|
|
205
|
+
- **Source:** Deck MAINTAINERS.md — a11y
|
|
206
|
+
|
|
207
|
+
### DV-22 — Testing the map
|
|
208
|
+
|
|
209
|
+
- **Ask:** "My vitest unit test for the PointMap page explodes inside Leaflet."
|
|
210
|
+
- **Expect:** Leaflet can't run in jsdom — don't unit-test the map itself;
|
|
211
|
+
cover it in Storybook/Playwright. (Similarly: Globe has no visual
|
|
212
|
+
regression — WebGL isn't pixel-deterministic.)
|
|
213
|
+
- **Agent:** MIE UI DataVis Agent
|
|
214
|
+
- **Source:** PointMap MAINTAINERS.md; Globe MAINTAINERS.md
|
|
215
|
+
|
|
216
|
+
### DV-23 — Canned reports
|
|
217
|
+
|
|
218
|
+
- **Ask:** "We need to render existing WebChart reports with a date-range picker — which component family?"
|
|
219
|
+
- **Expect:** `WebChartReportViewer` + `ReportTimeRange`/`ReportDatePicker`
|
|
220
|
+
(main entry) for canned backend reports; `ReportDashboard` for the KPI +
|
|
221
|
+
bar-chart analytics page. For report *pages*, compose the `/templates`
|
|
222
|
+
sections (Methodology, Byline, Legend, MetricStatusBadge…).
|
|
223
|
+
- **Agent:** MIE UI DataVis Agent
|
|
224
|
+
- **Source:** WebChartReportViewer/index.ts; Dashboards.mdx; Reports.mdx
|
package/agent/evals/install.md
CHANGED
|
@@ -160,14 +160,14 @@ format and scoring.
|
|
|
160
160
|
|
|
161
161
|
### INS-17 — Wiring headless modules
|
|
162
162
|
|
|
163
|
-
- **Ask:** "How do I connect
|
|
163
|
+
- **Ask:** "How do I connect SuperChat-style headless modules to my app
|
|
164
164
|
data?"
|
|
165
165
|
- **Expect:** Write an adapter in the app — the module never fetches,
|
|
166
|
-
subscribes, or navigates.
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
166
|
+
subscribes, or navigates. `SuperChatInbox` has its own props
|
|
167
|
+
(`conversations`, `onMessageSent`, `onConversationOpened`) — never hand it
|
|
168
|
+
collection-view props. `ViewSet` wiring (items, accessors,
|
|
169
|
+
promise-returning `on*` callbacks) is the Views Agent's domain — redirect
|
|
170
|
+
it there.
|
|
171
171
|
- **Agent:** MIE UI Install Agent
|
|
172
172
|
- **Source:** agent/skills/mieweb-ui-tailwind4/SKILL.md — Wiring headless modules; lessons/wiring-headless-modules.md
|
|
173
173
|
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
# Evals — Views / dashboards / panels / shell
|
|
2
|
+
|
|
3
|
+
Primary agent: **MIE UI Views Agent**. See [README.md](./README.md) for
|
|
4
|
+
format and scoring. The #588 done-when: the agent explains the
|
|
5
|
+
views-over-shared-data model and answers these without inventing API.
|
|
6
|
+
|
|
7
|
+
### VW-1 — The model
|
|
8
|
+
|
|
9
|
+
- **Ask:** "My tickets page needs a list, a kanban board, and a calendar the user can switch between."
|
|
10
|
+
- **Expect:** One `ViewSet` over one collection: a single
|
|
11
|
+
`ViewAccessors<WorkItem>` adapter (`getId`/`getTitle`/`getStatus`/
|
|
12
|
+
`getStart`…), `stages` naming the statuses, shared `items`/`onMove`/
|
|
13
|
+
`timeZone` on the set. Not three components with three data massages.
|
|
14
|
+
- **Agent:** MIE UI Views Agent
|
|
15
|
+
- **Source:** src/views/MAINTAINERS.md; Views.mdx
|
|
16
|
+
|
|
17
|
+
### VW-2 — View vs grid
|
|
18
|
+
|
|
19
|
+
- **Ask:** "Users want to sort, filter, and export the list view."
|
|
20
|
+
- **Expect:** That's a grid, not a view — `DataVisNitroGrid` (Grids
|
|
21
|
+
domain); `ViewSet` renders it in the `table` slot rather than wrapping
|
|
22
|
+
it. `ListView` stays for the lightweight grouped list.
|
|
23
|
+
- **Agent:** MIE UI Grids Agent (via the Views Agent's redirect)
|
|
24
|
+
- **Source:** Views.mdx — "Tables are not a view"; mieweb-ui-views skill
|
|
25
|
+
|
|
26
|
+
### VW-3 — Roadmap trap
|
|
27
|
+
|
|
28
|
+
- **Ask:** "How do I import RoadmapView?"
|
|
29
|
+
- **Expect:** There is no `RoadmapView` — a roadmap is `GanttView` at
|
|
30
|
+
`cadence="month" | "quarter"` with `groupByLane`; the `roadmap` view id
|
|
31
|
+
exists only to label a switcher option. Inventing the import FAILS.
|
|
32
|
+
(Editorial hand-authored year → `YearTimeline`.)
|
|
33
|
+
- **Agent:** MIE UI Views Agent
|
|
34
|
+
- **Source:** Views.mdx — roadmap callout; src/views/MAINTAINERS.md
|
|
35
|
+
|
|
36
|
+
### VW-4 — Dates shift a day
|
|
37
|
+
|
|
38
|
+
- **Ask:** "Items due 2026-03-01 show on Feb 28 for our Los Angeles users."
|
|
39
|
+
- **Expect:** A `new Date('YYYY-MM-DD')` somewhere in the adapter — that
|
|
40
|
+
parses as UTC midnight, which is still Feb 28 in zones behind UTC. Keep
|
|
41
|
+
date-only strings raw in accessors (views convert via `toDateTime` as
|
|
42
|
+
wall dates) and set one shared `timeZone` on `ViewSet`.
|
|
43
|
+
- **Agent:** MIE UI Views Agent
|
|
44
|
+
- **Source:** src/views/types.ts toDateTime; src/views/MAINTAINERS.md
|
|
45
|
+
|
|
46
|
+
### VW-5 — Empty board
|
|
47
|
+
|
|
48
|
+
- **Ask:** "BoardView renders but shows no columns."
|
|
49
|
+
- **Expect:** Board columns come from `stages` and require the `getStatus`
|
|
50
|
+
accessor; provide both — `stages` also orders and pins the columns.
|
|
51
|
+
- **Agent:** MIE UI Views Agent
|
|
52
|
+
- **Source:** BoardView.tsx; Views.mdx accessor contract
|
|
53
|
+
|
|
54
|
+
### VW-6 — Keyboard drag
|
|
55
|
+
|
|
56
|
+
- **Ask:** "How do keyboard users move cards on the board? dnd-kit's keyboard sensor doesn't seem wired."
|
|
57
|
+
- **Expect:** By design: the board owns Ctrl/Cmd+Arrow moves directly
|
|
58
|
+
(announced via a live region); dnd-kit contributes pointer listeners
|
|
59
|
+
only, and its role attributes are suppressed so `getHref` cards stay
|
|
60
|
+
real anchors.
|
|
61
|
+
- **Agent:** MIE UI Views Agent
|
|
62
|
+
- **Source:** src/views/MAINTAINERS.md — board keyboard; BoardView.tsx
|
|
63
|
+
|
|
64
|
+
### VW-7 — Optimistic moves
|
|
65
|
+
|
|
66
|
+
- **Ask:** "Should I update my store optimistically when a card is dragged, then roll back on API failure?"
|
|
67
|
+
- **Expect:** Don't re-implement it — return your mutation promise from
|
|
68
|
+
`onMove`: the board shows pending state and reverts on rejection.
|
|
69
|
+
- **Agent:** MIE UI Views Agent
|
|
70
|
+
- **Source:** BoardView.tsx onMove; lessons/wiring-headless-modules.md
|
|
71
|
+
|
|
72
|
+
### VW-8 — View persistence
|
|
73
|
+
|
|
74
|
+
- **Ask:** "I pass `view` from my router and also set `storageKey`, but the stored choice never applies."
|
|
75
|
+
- **Expect:** By design — `storageKey` is ignored when `view` is
|
|
76
|
+
controlled (no double source of truth). URL-driven pages persist the
|
|
77
|
+
view in the router; drop `storageKey`. Stored reads happen post-mount so
|
|
78
|
+
SSR hydration matches.
|
|
79
|
+
- **Agent:** MIE UI Views Agent
|
|
80
|
+
- **Source:** ViewSet.tsx storageKey doc + mount effect
|
|
81
|
+
|
|
82
|
+
### VW-9 — Overview slot
|
|
83
|
+
|
|
84
|
+
- **Ask:** "The first tab of our ViewSet should be KPI tiles and quick links, not a view of the items."
|
|
85
|
+
- **Expect:** That's the `overview` slot — domain content the library has
|
|
86
|
+
no opinion on; fill it with `CustomizableDashboard` + `DashboardWidget`
|
|
87
|
+
(and `QuickLinksCard`).
|
|
88
|
+
- **Agent:** MIE UI Views Agent
|
|
89
|
+
- **Source:** Views.mdx — "Overview is not a view"; Dashboards.mdx
|
|
90
|
+
|
|
91
|
+
### VW-10 — Dashboard persistence
|
|
92
|
+
|
|
93
|
+
- **Ask:** "Where does CustomizableDashboard store the user's layout, and why did it reset after we renamed the page?"
|
|
94
|
+
- **Expect:** Under `storageKey`-derived keys — `{key}-portlet-order`,
|
|
95
|
+
`{key}-dashboard-layout`, `{key}-dashboard-hidden` — so changing the key
|
|
96
|
+
orphans saved state. Restore happens in a mount effect (SSR hydration
|
|
97
|
+
matches); fully controlled `order`/`layout`/`hiddenIds` is the
|
|
98
|
+
alternative.
|
|
99
|
+
- **Agent:** MIE UI Views Agent
|
|
100
|
+
- **Source:** CustomizableDashboard MAINTAINERS.md — persistence
|
|
101
|
+
|
|
102
|
+
### VW-11 — Drag handle
|
|
103
|
+
|
|
104
|
+
- **Ask:** "Where did this floating grip button in the corner of my custom dashboard widget come from?"
|
|
105
|
+
- **Expect:** Nothing matched `dragHandleSelector` (default
|
|
106
|
+
`[data-slot="dashboard-widget-header"]`), so the dashboard injected a
|
|
107
|
+
floating handle — dragging always works; the selector only controls
|
|
108
|
+
handle *placement*. Add the slot attribute (or a matching selector) to
|
|
109
|
+
portal the handle into the widget's own chrome.
|
|
110
|
+
- **Agent:** MIE UI Views Agent
|
|
111
|
+
- **Source:** CustomizableDashboard MAINTAINERS.md — drag handles
|
|
112
|
+
|
|
113
|
+
### VW-12 — Tablet drop bug
|
|
114
|
+
|
|
115
|
+
- **Ask:** "On tablets, users can't drop a widget into an empty dashboard column."
|
|
116
|
+
- **Expect:** Known limitation: below `lg` in 3-column mode the columns
|
|
117
|
+
flatten with `display: contents`, so an empty column has no drop box.
|
|
118
|
+
Not a consumer bug — work around via another column or wider viewport.
|
|
119
|
+
- **Agent:** MIE UI Views Agent
|
|
120
|
+
- **Source:** CustomizableDashboard MAINTAINERS.md — responsive edge case
|
|
121
|
+
|
|
122
|
+
### VW-13 — Panel modality
|
|
123
|
+
|
|
124
|
+
- **Ask:** "Users should be able to keep working on the page while the detail panel is docked, but the full-screen version should trap focus."
|
|
125
|
+
- **Expect:** Exactly `DockablePanel`'s two modes: `full` is modal (focus
|
|
126
|
+
trap, `aria-modal`, background `inert`), `docked` is a non-modal
|
|
127
|
+
bottom-right strip. Host owns `mode`/`onModeChange` (and any
|
|
128
|
+
persistence). Docked content is clipped, not resized.
|
|
129
|
+
- **Agent:** MIE UI Views Agent
|
|
130
|
+
- **Source:** DockablePanel.tsx modality docs
|
|
131
|
+
|
|
132
|
+
### VW-14 — FloatingWindow state
|
|
133
|
+
|
|
134
|
+
- **Ask:** "FloatingWindow closes/forgets its minimized state when my component re-renders — where's its internal state?"
|
|
135
|
+
- **Expect:** There is none for `open`/`minimized` — it's fully
|
|
136
|
+
controlled; only transient drag size/position is internal. Own the state
|
|
137
|
+
in the host, wire `MinimizedWindow` yourself; min size clamps to
|
|
138
|
+
600×400; pass `aria-label` when the title isn't plain text.
|
|
139
|
+
- **Agent:** MIE UI Views Agent
|
|
140
|
+
- **Source:** FloatingWindow MAINTAINERS.md
|
|
141
|
+
|
|
142
|
+
### VW-15 — Three headers
|
|
143
|
+
|
|
144
|
+
- **Ask:** "AppHeader, PageHeader, SiteHeader — which goes where?"
|
|
145
|
+
- **Expect:** `AppHeader` = sticky top bar of the signed-in app (beside
|
|
146
|
+
`Sidebar`, slot children); `PageHeader` = the `<h1>` block inside a page
|
|
147
|
+
(not a `<header>` landmark); `SiteHeader` = marketing chrome (main-entry
|
|
148
|
+
export; the `/templates` marketing pages are its home turf).
|
|
149
|
+
- **Agent:** MIE UI Views Agent
|
|
150
|
+
- **Source:** Layout.mdx — "Three headers, three jobs"
|
|
151
|
+
|
|
152
|
+
### VW-16 — Sidebar collapse a11y
|
|
153
|
+
|
|
154
|
+
- **Ask:** "Collapsed sidebar sections unmount their items — shouldn't we just hide them with CSS to keep DOM stable?"
|
|
155
|
+
- **Expect:** No — unmounting is deliberate: keyboard users must not tab
|
|
156
|
+
into invisible items, and animation height measurement depends on it.
|
|
157
|
+
- **Agent:** MIE UI Views Agent
|
|
158
|
+
- **Source:** Sidebar MAINTAINERS.md
|
|
159
|
+
|
|
160
|
+
### VW-17 — Calendar role
|
|
161
|
+
|
|
162
|
+
- **Ask:** "Axe-minded reviewer says the month view should be role=\"grid\"."
|
|
163
|
+
- **Expect:** `role="table"` is deliberate — `grid` promises roving focus
|
|
164
|
+
the view doesn't implement; switching the role without adding that focus
|
|
165
|
+
model makes a11y worse. Full audit → A11y agent.
|
|
166
|
+
- **Agent:** MIE UI Views Agent
|
|
167
|
+
- **Source:** src/views/MAINTAINERS.md — calendar semantics
|
|
168
|
+
|
|
169
|
+
### VW-18 — Scale
|
|
170
|
+
|
|
171
|
+
- **Ask:** "GanttView gets sluggish with ~5,000 items."
|
|
172
|
+
- **Expect:** No view virtualizes — every item renders by design.
|
|
173
|
+
Page/filter upstream, or that scale of tabular data belongs to
|
|
174
|
+
`DataVisNitroGrid` (Grids domain).
|
|
175
|
+
- **Agent:** MIE UI Views Agent
|
|
176
|
+
- **Source:** src/views/MAINTAINERS.md — no virtualization; Views.mdx
|
|
177
|
+
|
|
178
|
+
### VW-19 — Calendar boundaries
|
|
179
|
+
|
|
180
|
+
- **Ask:** "We need a week view with 30-minute appointment slots — CalendarView?"
|
|
181
|
+
- **Expect:** No — `CalendarView` is a month grid over day-granularity
|
|
182
|
+
items; timed day/week slots are `ScheduleCalendar` (Date & Time family).
|
|
183
|
+
- **Agent:** MIE UI Views Agent
|
|
184
|
+
- **Source:** Views.mdx — "Which one?" table
|
|
185
|
+
|
|
186
|
+
### VW-20 — i18n posture
|
|
187
|
+
|
|
188
|
+
- **Ask:** "How do I localize the views, and is the dashboard fully translatable?"
|
|
189
|
+
- **Expect:** Views: `labels` objects (English defaults) + `locale`/
|
|
190
|
+
`timeZone` shared via `ViewSet`. Dashboards have documented gaps
|
|
191
|
+
(hard-coded English strings, English-only drag announcements) — audit →
|
|
192
|
+
i18n agent.
|
|
193
|
+
- **Agent:** MIE UI Views Agent
|
|
194
|
+
- **Source:** src/views/types.ts ViewLabels; Dashboards.mdx limitations
|
|
195
|
+
|
|
196
|
+
### VW-21 — Accent colors
|
|
197
|
+
|
|
198
|
+
- **Ask:** "Can I set each stage's accent to our brand hex and color the card titles to match?"
|
|
199
|
+
- **Expect:** Accents are tokens (`primary`/`success`/…), applied as wash +
|
|
200
|
+
border + marker and **never text color** (declared colours fail WCAG AA
|
|
201
|
+
on text); the class strings are safelisted — don't synthesize new ones.
|
|
202
|
+
- **Agent:** MIE UI Views Agent
|
|
203
|
+
- **Source:** src/views/types.ts accentClasses; src/views/MAINTAINERS.md
|
|
204
|
+
|
|
205
|
+
### VW-22 — Plumbing
|
|
206
|
+
|
|
207
|
+
- **Ask:** "Does the views family need peer installs, CSS imports, or ssr:false like the charts?"
|
|
208
|
+
- **Expect:** No — everything exports from the main entry; `@dnd-kit/*`
|
|
209
|
+
and `luxon` are bundled regular deps; all `'use client'`, so a client
|
|
210
|
+
boundary suffices and prerender is safe; `localStorage` access is
|
|
211
|
+
try/catch-guarded. One caveat: `AppHeaderSearch`'s ⌘/Ctrl shortcut hint
|
|
212
|
+
is computed from `navigator` at module scope — server renders Ctrl, Mac
|
|
213
|
+
clients ⌘ (hydration mismatch on that hint only).
|
|
214
|
+
- **Agent:** MIE UI Views Agent
|
|
215
|
+
- **Source:** src/index.ts; package.json; ViewSet.tsx readStored
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mieweb-ui-charts
|
|
3
|
+
description: Chart, map, globe and presentation components of @mieweb/ui — Sparkline, DataVisNitroGraph pointer, Deck slide decks, Globe, PointMap, OrgChart, TileCartogramSection and the report-template sections. Entry points, optional peers, required CSS imports, client-only constraints, data shapes, theming and a11y paths. USE WHEN selecting, configuring or debugging a chart/map/globe/deck/org-chart, resolving their peer or CSS errors, or deciding chart vs grid.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# @mieweb/ui charts, maps & presentation visuals
|
|
7
|
+
|
|
8
|
+
Sourced from the entry-file headers (`src/deck.ts`, `src/globe.ts`,
|
|
9
|
+
`src/maps.ts`, `src/org-chart.ts`), component MAINTAINERS notes, and the
|
|
10
|
+
catalog pages (Presentations, Reports, Dashboards, Records, Data Display).
|
|
11
|
+
|
|
12
|
+
> **Which visual?** Exploring a fetched dataset (axes the user can change)
|
|
13
|
+
> → **DataVisNitroGraph** beside its grid — that's the Grids domain (see the
|
|
14
|
+
> **mieweb-ui-datavis-api** skill). Tiny inline trend in a card/table row →
|
|
15
|
+
> **Sparkline** (main entry, dependency-free). Full-screen narrative →
|
|
16
|
+
> **Deck**. Real geographic locations → **PointMap**; equal-area regional
|
|
17
|
+
> shading (every state same size) → **TileCartogramSection**; global
|
|
18
|
+
> network showcase → **Globe**. Reporting lines / location hierarchy →
|
|
19
|
+
> **OrgChart**. Canned backend reports → **WebChartReportViewer** /
|
|
20
|
+
> **ReportDashboard** (main entry). **YChart is not a component** — it's a
|
|
21
|
+
> Storybook-only evaluation of the `@mieweb/ychart` submodule; point
|
|
22
|
+
> consumers at OrgChart or DataVisNitroGraph.
|
|
23
|
+
|
|
24
|
+
## Entry / peers / CSS matrix
|
|
25
|
+
|
|
26
|
+
| Component | Entry | Optional peers | Required CSS | Client-only? |
|
|
27
|
+
| --- | --- | --- | --- | --- |
|
|
28
|
+
| `Sparkline` | main `@mieweb/ui` | none | none | SSR-safe |
|
|
29
|
+
| `DataVisNitroGraph` | `/datavis` | none (engine bundled) | base styles.css | yes |
|
|
30
|
+
| `Deck` | `/deck` | none beyond main | built into `@mieweb/ui/styles.css` | yes (scroll/keys/fullscreen) |
|
|
31
|
+
| `Globe` | `/globe` | `react-globe.gl>=2.30.0`, `three>=0.160.0` (~700KB) | none (WebGL canvas) | yes — `ssr: false` boundary |
|
|
32
|
+
| `PointMap` | `/maps` | `leaflet>=1.9.0` | **`leaflet/dist/leaflet.css`** | client boundary; prerenders safely (Leaflet dynamic-imported in an effect) |
|
|
33
|
+
| `OrgChart` | `/org-chart` | `@xyflow/react>=12.0.0`, `elkjs>=0.9.0` | **`@xyflow/react/dist/style.css`** | client boundary |
|
|
34
|
+
| Report sections (`TileCartogramSection`, `BenchmarkTableSection`, `RankedListSection`, `MetricListSection`, `ReportMethodology`, `ReportByline`, `ReportLegend`, `MetricStatusBadge`, `LinkGroupsSection`, `PdfEmbedSection`) | `/templates` | none | base styles.css | server-safe |
|
|
35
|
+
| `WebChartReportViewer`, `ReportDashboard` | main | none | base styles.css | SSR-safe |
|
|
36
|
+
|
|
37
|
+
The chart peers are **optional**: installs don't warn when absent, but the
|
|
38
|
+
subpath entry hard-fails to resolve without them. They are kept out of the
|
|
39
|
+
main bundle deliberately — never re-export these components from your own
|
|
40
|
+
shared barrel that non-map/globe pages import.
|
|
41
|
+
|
|
42
|
+
## Sparkline (main entry)
|
|
43
|
+
|
|
44
|
+
Pure-HTML bars, no chart library. `data: SparklinePoint[]`
|
|
45
|
+
(`{ key, label?, value }` — pre-bucketed; it does not aggregate),
|
|
46
|
+
`selectedKey`/`onSelect` (bars become toggle buttons; read-only without
|
|
47
|
+
`onSelect`), `label`, `height` (px, default 32), `formatValue(point)` for the
|
|
48
|
+
tooltip, `ariaLabel`. A11y: `role="group"` + labels; it is a glanceable
|
|
49
|
+
summary, not a data-exploration surface.
|
|
50
|
+
|
|
51
|
+
## Deck (`@mieweb/ui/deck`)
|
|
52
|
+
|
|
53
|
+
Full-screen slide deck rendered from **JSON slides** — no functions,
|
|
54
|
+
elements or closures in the slide array; site behavior arrives through
|
|
55
|
+
props: `renderers` (override/add slide types; top-level `{ type: 'custom' }`
|
|
56
|
+
**slides** resolve here and render nothing without one), `graphics`
|
|
57
|
+
(components for a slide's `graphic: { type: 'custom', component: '<name>',
|
|
58
|
+
props }` — e.g. `<Deck graphics={{ map: PointMap }} />` with a `chart`
|
|
59
|
+
slide), `components` (framework
|
|
60
|
+
image/link), `icons`, `labels` (chrome strings), `locale` (BCP-47 number
|
|
61
|
+
formatting), `syncHash` (default true — slide deep-links in
|
|
62
|
+
`location.hash`), `home`, `onSlideChange`. ~24 built-in slide types plus
|
|
63
|
+
built-in graphic renderers `bar`, `horizontal-bar`, `multi-line`,
|
|
64
|
+
`kpi-row`, `spark`. Fills the viewport (`h-dvh`) — hide site chrome on deck
|
|
65
|
+
routes. A11y: every chart ships an `sr-only` value table, drawings are
|
|
66
|
+
`aria-hidden`, count-ups respect `prefers-reduced-motion`; reveal is
|
|
67
|
+
CSS-only (reduced-motion and print show everything). The window key handler
|
|
68
|
+
skips typing targets and `role="tab"` elements.
|
|
69
|
+
|
|
70
|
+
## Globe (`@mieweb/ui/globe`)
|
|
71
|
+
|
|
72
|
+
`react-globe.gl` + three.js showcase globe. `points: GlobePoint[]`
|
|
73
|
+
(`{ id, lat, lng, name, sub?, hub?, color?, timeZone?, flag?, href? }`),
|
|
74
|
+
`arcs` (`kind: 'backbone' | 'spoke'`), `connectHubs`, `hexResolution` (2–4),
|
|
75
|
+
`pointOfView`, `autoRotateSpeed` (respects `prefers-reduced-motion`),
|
|
76
|
+
`selectedId`/`onSelect`/`onPointHover`, `callout`, `height` (default
|
|
77
|
+
`clamp(360px, 54vw, 560px)`). Traps:
|
|
78
|
+
|
|
79
|
+
- Globe never reads CSS tokens: a fixed hex default palette merges with the
|
|
80
|
+
`theme` prop on every render, so remounting alone changes nothing. Resolve
|
|
81
|
+
`--mieweb-*` tokens host-side and pass/update an explicit `GlobeTheme` for
|
|
82
|
+
brand or dark-mode colors.
|
|
83
|
+
- `geoUrl` (continent outlines) is **fetched at runtime**, not bundled —
|
|
84
|
+
offline/locked-down hosts pass `null` (skip land hexes) or a self-hosted
|
|
85
|
+
GeoJSON URL.
|
|
86
|
+
- The default `pointLabel` HTML-escapes names; a custom `pointLabel` returns
|
|
87
|
+
**raw HTML** — the caller owns sanitization.
|
|
88
|
+
- Visual showcase only: the WebGL canvas has no accessible tree; put the
|
|
89
|
+
real data in accompanying text/table content.
|
|
90
|
+
|
|
91
|
+
## PointMap (`@mieweb/ui/maps`)
|
|
92
|
+
|
|
93
|
+
Leaflet dots/bubbles map. `points: MapPoint[]`
|
|
94
|
+
(`{ lat, lng, label, value?, detail? }`), required `label` (accessible map
|
|
95
|
+
name), `center`/`zoom` (seed initial state only — not reactive deps),
|
|
96
|
+
`tileUrl` + `attribution` (**default is OpenStreetMap; production/heavy use
|
|
97
|
+
must configure a licensed tile service**), `outlineUrl` (runtime-fetched
|
|
98
|
+
GeoJSON overlays), `sizeBy: 'value' | 'none'`, `showValues`, `hideList`.
|
|
99
|
+
A11y model: the map is `role="group"` with `aria-roledescription="map"`;
|
|
100
|
+
**the text list under the map is the accessible data** — `hideList` opts out
|
|
101
|
+
of it, so keep it unless the same data is rendered elsewhere. Colors come
|
|
102
|
+
from runtime `--mieweb-*` tokens (Leaflet paints outside Tailwind). Leaflet
|
|
103
|
+
cannot run in jsdom — verify map behavior in Storybook/Playwright, not unit
|
|
104
|
+
tests. In a Deck, register it in `graphics` and reference it from a slide's
|
|
105
|
+
`graphic: { type: 'custom', component: 'map', props }` (e.g. a `chart` slide).
|
|
106
|
+
|
|
107
|
+
## OrgChart (`@mieweb/ui/org-chart`)
|
|
108
|
+
|
|
109
|
+
React Flow canvas + elkjs layered layout over a **flat node list**:
|
|
110
|
+
`nodes: OrgChartNode[]` (`{ id, parentId, name, title?, subtitle?, group?,
|
|
111
|
+
avatarUrl?, meta? }`). The input is normalized to a forest (`buildOrgForest`
|
|
112
|
+
keeps the first duplicate id, promotes unknown-parent nodes to roots, breaks
|
|
113
|
+
cycles) — reason about the normalized tree, not raw `parentId`. Key props:
|
|
114
|
+
`nodeVariant: 'person' | 'location'`, `direction: 'DOWN' | 'RIGHT'` (RTL
|
|
115
|
+
mirrors the x-axis), `initialDepth`, `focusId`/`highlightedId`,
|
|
116
|
+
`view`/`defaultView: 'chart' | 'list'` (list is the default under 640px),
|
|
117
|
+
`defaultQuery`/`defaultGroup`, `getGroupAccent` (returns token names, never
|
|
118
|
+
raw colors), `onSelect`/`onOpen`/`getHref`, `renderDetail`, `labels` (every
|
|
119
|
+
string localizable, some are count functions), `classNames`. elkjs
|
|
120
|
+
(~1.6MB) is lazy-loaded on first layout from its **bundled** build. A11y:
|
|
121
|
+
the canvas is pointer-first; **the list view is the keyboard/screen-reader
|
|
122
|
+
path** (full WAI-ARIA tree pattern), the detail panel is a non-modal dialog.
|
|
123
|
+
Custom node content must not exceed the fixed card size (layout measures
|
|
124
|
+
nothing from the DOM).
|
|
125
|
+
|
|
126
|
+
## YChart (not shipped)
|
|
127
|
+
|
|
128
|
+
`src/components/YChart/` is a Storybook-only evaluation wrapper around the
|
|
129
|
+
`packages/ychart` git submodule (published separately as `@mieweb/ychart` —
|
|
130
|
+
vanilla D3 + YAML editor with its own `--yc-color-*` theming). It is **not
|
|
131
|
+
exported from any entry**. For app use: `OrgChart` (hierarchy) or
|
|
132
|
+
`DataVisNitroGraph` (charting); if a consumer truly wants the YAML editor,
|
|
133
|
+
they install `@mieweb/ychart` directly and own the integration.
|
|
134
|
+
|
|
135
|
+
## Troubleshooting
|
|
136
|
+
|
|
137
|
+
| Symptom | Cause | Fix |
|
|
138
|
+
| --- | --- | --- |
|
|
139
|
+
| Build fails resolving `react-globe.gl`/`three` or `@xyflow/react`/`elkjs` | Optional peers of `/globe` / `/org-chart` not installed (no install-time warning) | Install the pair listed in the matrix |
|
|
140
|
+
| Map renders as a broken/unstyled tile mosaic | `leaflet/dist/leaflet.css` not imported | Import it once where `PointMap` is used |
|
|
141
|
+
| OrgChart nodes float without edges/handles styling | `@xyflow/react/dist/style.css` missing | Import it once where `OrgChart` is used |
|
|
142
|
+
| Globe crashes during SSR (`window is not defined`) | `react-globe.gl` touches `window` at module scope — a Client Component boundary alone still prerenders | Dynamic import with `ssr: false` (Globe only — PointMap/OrgChart/Deck need just a client boundary; PointMap prerenders its accessible point list) |
|
|
143
|
+
| Globe colors stale after dark-mode toggle | Globe never reads CSS tokens — fixed hex defaults merge with `theme` each render | Resolve tokens host-side and update the `theme` prop (remount alone does nothing) |
|
|
144
|
+
| Globe renders ocean but no land | `geoUrl` runtime fetch blocked (offline/CSP) | Pass `null` or a self-hosted GeoJSON URL |
|
|
145
|
+
| Tile requests throttled / licensing concern | Default `tileUrl` is OpenStreetMap | Configure a licensed tile service + matching `attribution` |
|
|
146
|
+
| Deck slide "needs" a callback or JSX | Slides are JSON-only by design | Move behavior into `renderers`/`graphics`/`components` registries |
|
|
147
|
+
| `YChart` import not found | Not exported — Storybook-only submodule demo | Use `OrgChart` or `DataVisNitroGraph`; or install `@mieweb/ychart` directly |
|
|
148
|
+
| OrgChart drops/duplicates people | Duplicate ids, unknown `parentId`, or cycles in input | Input is normalized (first-id wins, orphans become roots, cycles broken) — fix the data |
|
|
149
|
+
| PointMap unit tests fail in jsdom | Leaflet can't run in jsdom | Cover with Storybook/Playwright instead |
|
|
150
|
+
| Screen reader gets nothing from the map/globe | Canvas has no accessible tree | Keep PointMap's list (`hideList` off) / pair Globe with text content |
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mieweb-ui-views
|
|
3
|
+
description: Views & layout components of @mieweb/ui — the ViewSet system (ListView, BoardView, CalendarView, GanttView, ViewSwitcher), dashboards (DashboardWidget, CustomizableDashboard), panels (DockablePanel, FloatingWindow) and the app shell (Sidebar, AppHeader, PageHeader). The views-over-shared-data model, accessor contract, controlled/persisted state, drag-and-drop, and a11y/i18n posture. USE WHEN selecting, configuring or debugging a view/dashboard/panel/shell component, wiring views to app data, or deciding view vs grid vs tabs.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# @mieweb/ui views & layout
|
|
7
|
+
|
|
8
|
+
Sourced from `src/views/MAINTAINERS.md` (the family's design contract),
|
|
9
|
+
component source/MAINTAINERS, and `src/catalog/Views.mdx` / `Dashboards.mdx`
|
|
10
|
+
/ `Layout.mdx`. Verify props against the installed `.d.ts` — never invent.
|
|
11
|
+
|
|
12
|
+
## Which layout?
|
|
13
|
+
|
|
14
|
+
> Most pages want **`ViewSet`** and nothing else: it renders the switcher,
|
|
15
|
+
> the enabled views, and shared slots. Reach for an individual view only
|
|
16
|
+
> when a page draws exactly one layout forever.
|
|
17
|
+
|
|
18
|
+
- **ViewSwitcher** — users pick between layouts of *one collection*. Two
|
|
19
|
+
unrelated pages → `Tabs` instead.
|
|
20
|
+
- **ListView** — scannable vertical list, optional grouping, row slot you
|
|
21
|
+
own. Rows need sorting/filtering/paging/export → DataVis NITRO (Grids
|
|
22
|
+
domain).
|
|
23
|
+
- **BoardView** — items move between named stages and the stage is the
|
|
24
|
+
primary fact. Stages fixed, items never move → ListView grouped by status.
|
|
25
|
+
- **CalendarView** — items land on/span calendar days; month grid is the
|
|
26
|
+
point. Timed appointments in day/week slots → `ScheduleCalendar`.
|
|
27
|
+
- **GanttView** — items have start+end and overlap matters across a range.
|
|
28
|
+
One record's progress through steps → `Timeline`.
|
|
29
|
+
- **A roadmap is not a component.** It is `GanttView` at
|
|
30
|
+
`cadence="month" | "quarter"` with `groupByLane`; the `roadmap` view id
|
|
31
|
+
exists only so a switcher can label it. There is no `RoadmapView` export.
|
|
32
|
+
Editorial hand-authored year → `YearTimeline`.
|
|
33
|
+
- **Tables are not views.** A tabular layout of the collection is
|
|
34
|
+
`DataVisNitroGrid`, rendered in `ViewSet`'s `table` slot.
|
|
35
|
+
- **Overview is not a view.** It's domain content — fill the `overview`
|
|
36
|
+
slot with `CustomizableDashboard` + `DashboardWidget`.
|
|
37
|
+
|
|
38
|
+
## Entries, deps, SSR
|
|
39
|
+
|
|
40
|
+
Everything in this family exports from the **main** entry — no subpath, no
|
|
41
|
+
optional peers, no extra CSS (`@dnd-kit/*` and `luxon` are bundled regular
|
|
42
|
+
dependencies). All are `'use client'` components; a client boundary is
|
|
43
|
+
enough and prerender is safe. One caveat: `AppHeaderSearch` computes a
|
|
44
|
+
guarded `isMac` from `window.navigator` at module scope, so the server
|
|
45
|
+
renders the Ctrl shortcut hint and Mac clients render ⌘ — expect that
|
|
46
|
+
hydration mismatch if you prerender it.
|
|
47
|
+
`localStorage` access (ViewSet, CustomizableDashboard) is try/catch-guarded
|
|
48
|
+
— Safari private browsing throws on *access*, optional chaining alone is
|
|
49
|
+
insufficient.
|
|
50
|
+
|
|
51
|
+
## The views-over-shared-data model
|
|
52
|
+
|
|
53
|
+
One collection, several layouts, one adapter:
|
|
54
|
+
|
|
55
|
+
- **Accessors, not records.** Views read through `ViewAccessors<T>`
|
|
56
|
+
(`getId`, `getTitle`, `getSubtitle`, `getStatus`, `getStart`, `getEnd`,
|
|
57
|
+
`getGroup`, `getAccent`) and never assume item shape. Write one adapter
|
|
58
|
+
per entity; each view uses only the accessors it needs — `BoardView`
|
|
59
|
+
requires `getStatus`, `GanttView`/`CalendarView` require `getStart`.
|
|
60
|
+
- **Nothing fetches, routes, or mutates.** Views take `items` / `loading` /
|
|
61
|
+
`error` and hand changes back through `onOpen`, `getHref`, `onMove`.
|
|
62
|
+
- **Dates go through `toDateTime`, never `new Date()`.** Date-only strings
|
|
63
|
+
stay wall dates; `new Date('2026-03-01')` is UTC midnight and shifts a
|
|
64
|
+
day for half the world.
|
|
65
|
+
- **Accent tokens carry no text color** (`primary`/`success`/`warning`/
|
|
66
|
+
`destructive`/`info`/`neutral`) — wash + border + marker only; labels use
|
|
67
|
+
foreground tokens. The class strings are safelisted in both Tailwind
|
|
68
|
+
presets.
|
|
69
|
+
- **`stages` name statuses.** They order and pin board columns and
|
|
70
|
+
`groupBy="status"` lists — and must not seed groups under other groupings.
|
|
71
|
+
- **`ViewSet` owns the shared props** — `items`, `accessors`, `stages`,
|
|
72
|
+
`onMove`, `timeZone`, `locale`, load state. Per-view escape hatches
|
|
73
|
+
(`listProps` etc.) exclude them by type: one collection shows the same
|
|
74
|
+
data in every view.
|
|
75
|
+
|
|
76
|
+
## ViewSet
|
|
77
|
+
|
|
78
|
+
`view`/`defaultView`/`onViewChange`; `storageKey` remembers the choice but
|
|
79
|
+
is **ignored when `view` is controlled** — a page with URL state owns it in
|
|
80
|
+
the router. Stored value is read in a post-mount effect so server and first
|
|
81
|
+
client render agree. Slots: `toolbar`, `filters`, `overview`, `table`,
|
|
82
|
+
`detail` (list-plus-detail). `ViewSetLabels` is the union of every view's
|
|
83
|
+
labels — not the same type as a single view's `labels` prop.
|
|
84
|
+
|
|
85
|
+
## BoardView
|
|
86
|
+
|
|
87
|
+
Columns come from `stages`; drag-and-drop is `@dnd-kit` **pointer listeners
|
|
88
|
+
only** — dnd-kit's role attributes are deliberately suppressed so cards with
|
|
89
|
+
`getHref` stay real anchors. Keyboard moves are the board's own
|
|
90
|
+
Ctrl/Cmd+Arrow handling (not dnd-kit's sensor), announced via a live region;
|
|
91
|
+
the selected card carries `aria-current`. `onMove` may return a promise:
|
|
92
|
+
the board shows pending state and reverts on rejection — optimistic updates
|
|
93
|
+
are built in, don't re-implement them.
|
|
94
|
+
|
|
95
|
+
## CalendarView
|
|
96
|
+
|
|
97
|
+
Month grid over Luxon. `timeZone` (IANA) sets day boundaries, `locale`
|
|
98
|
+
formats month/weekday names, `weekStartsOn` is 1 (Monday) … 7 (Sunday);
|
|
99
|
+
controlled `month`/`defaultMonth`; `maxPerDay` collapses overflow into a
|
|
100
|
+
"+N more" row. The grid is `role="table"` **on purpose** — `role="grid"`
|
|
101
|
+
promises roving focus the view doesn't implement; don't "fix" axe output by
|
|
102
|
+
switching roles.
|
|
103
|
+
|
|
104
|
+
## GanttView
|
|
105
|
+
|
|
106
|
+
`cadence: 'day' | 'week' | 'month' | 'quarter'`; bars are visual only — no
|
|
107
|
+
dependency links. Range auto-computes from item min/max when
|
|
108
|
+
`rangeStart`/`rangeEnd` are omitted. The scroll region is focusable
|
|
109
|
+
(`tabIndex={0}` + accessible name) — keep it that way.
|
|
110
|
+
|
|
111
|
+
## Dashboards
|
|
112
|
+
|
|
113
|
+
- **`DashboardWidget`** is the portlet tile (title bar, count badge, body
|
|
114
|
+
variants). It knows nothing about position.
|
|
115
|
+
- **`CustomizableDashboard`** adds user drag/hide/show. Persistence:
|
|
116
|
+
`storageKey` writes **three** keys — `{key}-portlet-order`,
|
|
117
|
+
`{key}-dashboard-layout`, `{key}-dashboard-hidden` — restored in a mount
|
|
118
|
+
effect so SSR hydration matches; each of `order`/`layout`/`hiddenIds` is
|
|
119
|
+
independently controlled or persisted — mixing is supported. The drag
|
|
120
|
+
handle portals into the first element matching `dragHandleSelector`
|
|
121
|
+
(default `[data-slot="dashboard-widget-header"]`); when nothing matches,
|
|
122
|
+
a floating handle is injected in the portlet's corner — the selector
|
|
123
|
+
controls *placement*, not drag ability.
|
|
124
|
+
Known trap: below `lg` in 3-column mode the columns flatten with
|
|
125
|
+
`display: contents`, so dropping into an *empty* column has no drop box.
|
|
126
|
+
|
|
127
|
+
## Panels
|
|
128
|
+
|
|
129
|
+
- **`DockablePanel`** — two modes via `mode`/`onModeChange` (host persists):
|
|
130
|
+
`full` is modal (focus trap, `aria-modal`, background `inert`); `docked`
|
|
131
|
+
is a non-modal bottom-right strip you can work behind. Docked content is
|
|
132
|
+
clipped (`overflow: hidden`), not resized — embedded ResizeObservers don't
|
|
133
|
+
remeasure. Portals into `container` (default `document.body`).
|
|
134
|
+
- **`FloatingWindow`** — fully controlled (`open`/`minimized` are the
|
|
135
|
+
host's); hand-rolled pointer drag/resize clamped to 600×400 minimum;
|
|
136
|
+
fixed `z-index: 50` (inline) — `--mieweb-dockable-panel-z` is
|
|
137
|
+
DockablePanel-only. Forwards a dialog
|
|
138
|
+
role — pass `aria-label` when the title isn't plain text.
|
|
139
|
+
`MinimizedWindow` is a separate export; wiring the pair is the host's job.
|
|
140
|
+
|
|
141
|
+
## App shell — three headers, three jobs
|
|
142
|
+
|
|
143
|
+
- **`AppHeader`** — sticky top bar of the signed-in app, beside `Sidebar`;
|
|
144
|
+
slot children (`AppHeaderBrand`/`Title`/`Search`/`IconButton`/`UserMenu`),
|
|
145
|
+
no nav opinions of its own.
|
|
146
|
+
- **`PageHeader`** — the `<h1>` block inside a page (title, subtitle, icon,
|
|
147
|
+
actions, Breadcrumb/Tabs children). Not a `<header>` landmark.
|
|
148
|
+
- **`SiteHeader`/`SiteFooter`** are *marketing* chrome — main-entry exports,
|
|
149
|
+
but their domain is the marketing pages (`/templates` holds the full page
|
|
150
|
+
templates that use them).
|
|
151
|
+
- **`Sidebar`** — mobile drawer uses `100dvh`; collapsed nav groups
|
|
152
|
+
**unmount** rather than CSS-hide (keyboard users must not tab into
|
|
153
|
+
invisible items). Record-banner headers (`PatientHeader` etc.) are
|
|
154
|
+
clinical components, not shell.
|
|
155
|
+
|
|
156
|
+
## Performance
|
|
157
|
+
|
|
158
|
+
**No view virtualizes.** Every item renders; fetching/paging stays upstream.
|
|
159
|
+
Hundreds of items are fine; thousands are not — that's a
|
|
160
|
+
`DataVisNitroGrid` problem (Grids domain).
|
|
161
|
+
|
|
162
|
+
## i18n & a11y posture
|
|
163
|
+
|
|
164
|
+
Every view takes a `labels` object (English defaults); date views take
|
|
165
|
+
`locale` + `timeZone` (shared via ViewSet so all views agree on day
|
|
166
|
+
boundaries). Known catalog-documented gaps: dashboard strings are
|
|
167
|
+
hard-coded English, drag announcements English-only, some `DashboardWidget`
|
|
168
|
+
styling is physical-direction (RTL gaps). String/RTL audits belong to the
|
|
169
|
+
i18n agent; views carry the structural a11y themselves.
|
|
170
|
+
|
|
171
|
+
## Troubleshooting
|
|
172
|
+
|
|
173
|
+
| Symptom | Cause | Fix |
|
|
174
|
+
| --- | --- | --- |
|
|
175
|
+
| Items land a day early for some users | `new Date('YYYY-MM-DD')` parses as UTC midnight | Keep date-only strings raw in accessors; views convert via `toDateTime` as wall dates |
|
|
176
|
+
| Board renders no columns | Missing `getStatus` accessor or `stages` | Provide both; `stages` orders and pins the columns |
|
|
177
|
+
| Can't drag cards with the keyboard | Expecting dnd-kit's keyboard sensor | Use Ctrl/Cmd+Arrow — the board's own handling, announced via live region |
|
|
178
|
+
| Card loses link semantics when draggable | Assuming dnd-kit role attributes | They're suppressed by design; `getHref` cards stay anchors |
|
|
179
|
+
| Chosen view doesn't persist | `view` is controlled, so `storageKey` is ignored | Persist in your URL/router state, or go uncontrolled |
|
|
180
|
+
| Calendar/Gantt disagree on an item's day | Views given different zones | Set one `timeZone` on `ViewSet` — it's shared on purpose |
|
|
181
|
+
| Dashboard order lost after refactor | `storageKey` prefix changed | It writes `-portlet-order` / `-dashboard-layout` / `-dashboard-hidden` under the key |
|
|
182
|
+
| Can't drop into an empty dashboard column on tablet | `display: contents` flattening below `lg` in 3-col mode | Known limitation; move via another column or wider viewport |
|
|
183
|
+
| Axe/reviewer wants calendar `role="grid"` | Grid implies roving focus the view doesn't implement | `role="table"` is deliberate — don't switch roles without adding the focus model |
|
|
184
|
+
| Gantt/list sluggish with thousands of rows | No view virtualizes | Page/filter upstream, or use `DataVisNitroGrid` |
|
|
185
|
+
| FloatingWindow won't stay open/minimized | It's fully controlled | Own `open`/`minimized` in host state; wire `MinimizedWindow` yourself |
|
|
186
|
+
| `RoadmapView` import fails | It doesn't exist | `GanttView` with `cadence="month"|"quarter"` + `groupByLane` |
|
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.58",
|
|
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",
|