@micha.bigler/ui-core-micha 2.40.0 → 2.41.1
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/DESIGN.md +1 -0
- package/WORK_ORDERS.md +3 -0
- package/dev/entries.jsx +158 -0
- package/dist/auth/apiClient.js +34 -4
- package/dist/components/charts/BarChart.js +2 -2
- package/dist/components/charts/ChartFrame.js +1 -1
- package/dist/components/charts/LineChart.js +2 -2
- package/dist/components/charts/ScatterChart.js +178 -0
- package/dist/components/charts/chartDefaults.js +30 -1
- package/dist/components/charts/palette.js +6 -0
- package/dist/index.js +1 -0
- package/package.json +1 -1
- package/src/auth/apiClient.jsx +33 -4
- package/src/components/charts/BarChart.jsx +2 -1
- package/src/components/charts/ChartFrame.jsx +3 -1
- package/src/components/charts/LineChart.jsx +2 -1
- package/src/components/charts/ScatterChart.jsx +277 -0
- package/src/components/charts/chartDefaults.js +32 -1
- package/src/components/charts/palette.js +6 -0
- package/src/index.js +6 -0
- package/tests/ScatterChart.test.jsx +234 -0
- package/tests/apiClientPublicPaths.test.js +178 -0
- package/tests/chartDefaults.test.js +75 -3
- package/tests/chartsPalette.test.js +20 -0
- package/work-orders/AUTH-5.md +154 -0
- package/work-orders/THEME-10.md +303 -0
- package/work-orders/THEME-11.md +208 -0
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
# THEME-11 — The kit has no opinion on chart margins, so every chart in the estate inherits MUI's
|
|
2
|
+
|
|
3
|
+
## Part A — Envelope
|
|
4
|
+
|
|
5
|
+
**Goal.** Give the chart presets a margin default of their own, so charts stop falling back to
|
|
6
|
+
MUI X's `DEFAULT_MARGINS` of 20 px on all four sides, and trim the one comparable block in
|
|
7
|
+
`ChartFrame`. The whitespace around plots shrinks everywhere at once, without each consuming
|
|
8
|
+
panel having to hand-tune a `margin` prop.
|
|
9
|
+
|
|
10
|
+
**Why — measured, not estimated.** hram's four KPI cards were taken apart pixel by pixel. The
|
|
11
|
+
chart is 270 px tall and its plot area is 202 px; the remaining 167 px is furniture, and the
|
|
12
|
+
budget accounts for the card's observed ~370 px exactly:
|
|
13
|
+
|
|
14
|
+
| Block | px | Owner |
|
|
15
|
+
|---|---|---|
|
|
16
|
+
| `ChartFrame` root padding (`p: 2`) top | 16 | this package |
|
|
17
|
+
| Title text | ~24 | this package |
|
|
18
|
+
| Title box `mb: 2` | 16 | this package |
|
|
19
|
+
| `margin.top` | 20 | **MUI default** |
|
|
20
|
+
| **Plot area** | **202** | — |
|
|
21
|
+
| x-axis height (`DEFAULT_AXIS_SIZE_HEIGHT`) | 25 | MUI default |
|
|
22
|
+
| `margin.bottom` | 20 | **MUI default** |
|
|
23
|
+
| Forced blank (`minHeight 300` over `height 270`) | 30 | hram — its own `FIX-16` |
|
|
24
|
+
|
|
25
|
+
The forced blank is **centred, not stacked at the bottom**: `ChartFrame`'s content box is
|
|
26
|
+
`display: flex` with `alignItems: center`, so a `minHeight` above the chart's own height splits
|
|
27
|
+
evenly — 15 px above the chart and 15 px below. It is listed once here for the total.
|
|
28
|
+
| `ChartFrame` root padding bottom | 16 | this package |
|
|
29
|
+
|
|
30
|
+
**The MUI defaults apply because this package never forms an opinion.** `spaceForRotatedTicks`
|
|
31
|
+
returns the caller's `margin` untouched unless the x-ticks are rotated *and* the caller left
|
|
32
|
+
`bottom` unset — so for the ordinary case it hands `margin: undefined` straight to
|
|
33
|
+
`MuiBarChart`, and `DEFAULT_MARGINS = { top: 20, bottom: 20, left: 20, right: 20 }` takes over.
|
|
34
|
+
THEME-9 gave the kit axis *sizing*; margins were never in its scope. Every chart in every
|
|
35
|
+
consuming app has been paying those 20 px since.
|
|
36
|
+
|
|
37
|
+
**What each side is actually for**, which is what makes the trim safe rather than a guess:
|
|
38
|
+
- `margin.left` sits **outside** the y-axis width — this package's own comment records
|
|
39
|
+
`drawingArea.left = margin.left + axisSizeLeft`. The tick labels live in `axisSizeLeft`, so
|
|
40
|
+
`margin.left` is pure padding.
|
|
41
|
+
- `margin.bottom` sits **below** the x-axis block; `DEFAULT_AXIS_SIZE_HEIGHT` already contains
|
|
42
|
+
the tick label.
|
|
43
|
+
- `margin.top` is the only one carrying real content: the topmost y tick label is centred on its
|
|
44
|
+
gridline and overhangs the plot by roughly half a caption line-height (~9 px). This is why the
|
|
45
|
+
top cannot simply be trimmed to match the others.
|
|
46
|
+
- `margin.right` is the risky one — see the scope note.
|
|
47
|
+
|
|
48
|
+
**Scope.**
|
|
49
|
+
|
|
50
|
+
1. **A margin default in the shared chart path**, applied when the caller passes no margin and
|
|
51
|
+
merged per-side (not wholesale) when the caller passes a partial one, so an explicit
|
|
52
|
+
`{ left: 60 }` does not silently reinstate 20 px on the other three sides:
|
|
53
|
+
- `top: 10` — leaves the ~9 px overhang of the topmost tick label its room. **Not 8**: at 8
|
|
54
|
+
that label sits on the edge.
|
|
55
|
+
- `bottom: 8`
|
|
56
|
+
- `left: 8`
|
|
57
|
+
- `right: 16` — **deliberately a smaller trim than the other sides.** On a band x-axis the
|
|
58
|
+
tick labels are centred and 8 would be fine, but on a **linear** x-axis the last tick label
|
|
59
|
+
sits *at* the edge and overhangs by half its width (~13 px for a four-character label at
|
|
60
|
+
caption size). 16 is the value that survives both. Do **not** make this conditional on
|
|
61
|
+
scale type: that is inferred behaviour serving no named consumer, and a chart that genuinely
|
|
62
|
+
needs more can pass `margin` explicitly.
|
|
63
|
+
2. **`ChartFrame`'s title box `mb: 2` → `mb: 1`** (16 → 8 px).
|
|
64
|
+
3. Apply consistently across the presets that share the path (`BarChart`, `LineChart`,
|
|
65
|
+
`TimeSeriesChart`), so consumers do not have to know which chart type trims what.
|
|
66
|
+
|
|
67
|
+
**Non-goals / do-not-touch.**
|
|
68
|
+
- **`CHART_FRAME_ROOT_SX = { p: 2 }` stays.** Trimming it would help the left and right edges
|
|
69
|
+
too, but `ChartFrame` wraps non-chart content as well, and its padding is what makes a panel
|
|
70
|
+
read as a card. That is a separate proposal with a different blast radius, not a rider here.
|
|
71
|
+
- No change to axis sizing, tick formatting or label placement — THEME-9 owns those and they
|
|
72
|
+
are working.
|
|
73
|
+
- No new props. This is a default, not a feature.
|
|
74
|
+
|
|
75
|
+
**Tier 3** — shared-core. `reviewer` mandatory; `ui_reviewer` too, the deliverable being visual.
|
|
76
|
+
|
|
77
|
+
**Two traps this WO must not walk into.**
|
|
78
|
+
|
|
79
|
+
1. **`spaceForRotatedTicks` decides "did the caller set bottom?" by `margin?.bottom != null`.**
|
|
80
|
+
If a package-level default margin object is injected *before* that check, every rotated-tick
|
|
81
|
+
chart sees it as caller-set and loses its extra bottom space — hram's `RatioMetricsPanel`
|
|
82
|
+
runs x-labels at −45° and −90° and would clip them. The default must be applied so that
|
|
83
|
+
`spaceForRotatedTicks` still distinguishes a genuine caller margin from the package default,
|
|
84
|
+
or the rotated path must be computed first and the default merged under it.
|
|
85
|
+
2. **`MUI_CHART_MARGIN_BOTTOM = 20` in `chartDefaults.js` is a hard-coded mirror of MUI's
|
|
86
|
+
default**, used as the base when the rotated path computes extra bottom space. It must move
|
|
87
|
+
with the new default, or rotated charts get their extra height added to the wrong base.
|
|
88
|
+
|
|
89
|
+
**Tests to write.** Narrow, but these three are the ones that catch a real break:
|
|
90
|
+
- A rotated-tick chart still receives its enlarged bottom margin (trap 1 — the regression this
|
|
91
|
+
change is most likely to cause).
|
|
92
|
+
- A caller-supplied partial margin keeps its own value on the side it set and gets the new
|
|
93
|
+
default on the others (the merge semantics in scope 1).
|
|
94
|
+
- A chart with a linear x-axis does not clip its last tick label at the new right margin.
|
|
95
|
+
|
|
96
|
+
**Risks.**
|
|
97
|
+
- **The blast radius is every chart in every consuming app**, and it lands the moment each app
|
|
98
|
+
bumps its pin — not at publish. A single wrong side value is therefore an estate-wide visual
|
|
99
|
+
regression rather than a local one. That is also the point of doing it here rather than in
|
|
100
|
+
each panel, but it raises the bar on the rendered check.
|
|
101
|
+
- **Panels that already hand-tune `margin`** (hram's `RatioMetricsPanel` passes
|
|
102
|
+
`{ left: 60, right: 8, top: 20, bottom: … }`) must be unaffected on the sides they set. This
|
|
103
|
+
is what scope 1's per-side merge is for; whole-object replacement would break them.
|
|
104
|
+
- The numbers above are derived from a caption-sized tick label. A consuming app with a
|
|
105
|
+
markedly larger chart font would need more top margin. Do not build for that — no consumer
|
|
106
|
+
has it — but state the assumption in the docs.
|
|
107
|
+
|
|
108
|
+
**Delivery is not done at publish.** hram is the consumer that reported this, and its pins for
|
|
109
|
+
THEME-8, THEME-9 and THEME-10 are all already open. Take this one in the same bump rather than
|
|
110
|
+
adding a fourth pending hop.
|
|
111
|
+
|
|
112
|
+
## Part B — Implementation map — ADDRESSED TO THE IMPLEMENTER
|
|
113
|
+
|
|
114
|
+
Codex not dispatched: `.claude/codex-status.md` already carried a same-day `unavailable` line —
|
|
115
|
+
implemented directly in Claude, authorship flip, `reviewer` + `ui_reviewer` mandatory (already
|
|
116
|
+
required at Tier 3).
|
|
117
|
+
|
|
118
|
+
### What landed
|
|
119
|
+
|
|
120
|
+
- `chartDefaults.js`: `PACKAGE_DEFAULT_MARGIN = { top: 10, bottom: 8, left: 8, right: 16 }`
|
|
121
|
+
(exported) and `withMarginDefaults(margin)` (per-side merge, number-shorthand expansion).
|
|
122
|
+
`MUI_CHART_MARGIN_BOTTOM` moved `20 → 8` to match the new baseline (trap 2).
|
|
123
|
+
- `BarChart.jsx`/`LineChart.jsx`: `spaceForRotatedTicks` still runs FIRST, on the caller's
|
|
124
|
+
UNMODIFIED `margin` — its own `callerSetBottom` check (`margin?.bottom != null`) therefore
|
|
125
|
+
still tells a genuine caller margin from "nothing set" correctly (trap 1 avoided by ordering,
|
|
126
|
+
not by threading a flag through the shared helper). `withMarginDefaults` is applied AFTER,
|
|
127
|
+
wrapping `rotatedTickSpace.margin` on the way into `MuiBarChart`/`MuiLineChart` — so a
|
|
128
|
+
rotation-computed `bottom` (already present on that object) is preserved by the merge, and
|
|
129
|
+
only genuinely-unset sides get the package default.
|
|
130
|
+
- `TimeSeriesChart.jsx`: no change needed — it never sets its own `margin`, so it inherits
|
|
131
|
+
`BarChart`'s new default automatically through composition.
|
|
132
|
+
- `ChartFrame.jsx`: title row `mb: 2 → mb: 1`. Controls row `mb: 2` left untouched (not named).
|
|
133
|
+
**Deliberately unconditional** (`ui_reviewer` U3 asked whether this should be scoped to only
|
|
134
|
+
chart-preset consumers, matching the margin trim's scope): `ChartFrame` wraps non-chart
|
|
135
|
+
content too, and scope item 2 names the title box specifically, with no "only when a chart
|
|
136
|
+
preset is the child" qualifier anywhere in Part A — a scatter-backed or bespoke-SVG panel
|
|
137
|
+
gets the tighter title spacing but keeps whatever margin its own content uses, which is
|
|
138
|
+
correct: the title row and the plot margin are two independent pieces of furniture, not one
|
|
139
|
+
setting that should move together.
|
|
140
|
+
|
|
141
|
+
### Scope gap surfaced, not silently folded in
|
|
142
|
+
|
|
143
|
+
`ScatterChart` (THEME-10, same day, not yet published) passes its `margin` prop straight
|
|
144
|
+
through with no default handling at all — it would keep MUI's flat 20px default while
|
|
145
|
+
`BarChart`/`LineChart`/`TimeSeriesChart` get 8/10/16. THEME-11's own scope item 3 names exactly
|
|
146
|
+
three presets, not four, and `ScatterChart` didn't exist when this WO's Part A was authored.
|
|
147
|
+
Flagging this explicitly rather than extending scope silently: `ScatterChart` should likely get
|
|
148
|
+
`withMarginDefaults` too, in a follow-up (or when `ScatterChart`'s own version bumps). **This is
|
|
149
|
+
NOT the same seam as the right-margin note below** — `ScatterChart`'s X axis is always linear by
|
|
150
|
+
construction (THEME-10 scope), so if/when it does adopt `withMarginDefaults`, its own rendered
|
|
151
|
+
check needs to re-examine the right-margin question specifically, not inherit this WO's
|
|
152
|
+
"no consumer has it" conclusion by assumption.
|
|
153
|
+
|
|
154
|
+
### Verification detail beyond the WO's own risk note — corrected after review
|
|
155
|
+
|
|
156
|
+
The rendered check found that a wide, locale-grouped tick value (`"1,000"`, 6 characters)
|
|
157
|
+
leaves only ~1px of clearance at the new `right: 16` before MUI's own internal `shortenLabels`
|
|
158
|
+
truncates it to `"1,0…"` — never actual overflow-clipping past the SVG boundary in either the
|
|
159
|
+
narrow or wide case. Two corrections to the original note, from `reviewer`/`ui_reviewer`:
|
|
160
|
+
|
|
161
|
+
- **The grouped formatting is MUI's OWN default tick rendering, not THEME-9's
|
|
162
|
+
`defaultNumericTickFormatter`** (`reviewer`/`ui_reviewer` finding, independently confirmed:
|
|
163
|
+
neither `BarChart.jsx` nor `LineChart.jsx` wires a `valueFormatter` onto the x-axis — only the
|
|
164
|
+
y-axis gets THEME-9's default — and the dev fixture that produced `"1,000"` set none either).
|
|
165
|
+
This means the tight case is not a THEME-9-introduced interaction; it is how MUI itself has
|
|
166
|
+
always formatted a linear axis's ticks, now simply more VISIBLE because `right` shrank from
|
|
167
|
+
20 to 16.
|
|
168
|
+
- **No real consumer hits this today** (`reviewer`, verified by grepping every hram panel that
|
|
169
|
+
actually consumes `BarChart`/`LineChart`/`TimeSeriesChart`: `CostMetricsPanel`,
|
|
170
|
+
`RatioMetricsPanel`, `AccessibilityPanel`, `TotalMetricsPanel`, `ReferralMetricsPanel`,
|
|
171
|
+
`GroupMetricsPanel`, `GenericAnalysisPlot` — every one uses `scaleType: 'band'`, none
|
|
172
|
+
`'linear'`. `AllocationPerformancePanel`, the panel this note originally worried about,
|
|
173
|
+
imports only `ChartFrame` from this package and draws its own bespoke SVG axes — it does not
|
|
174
|
+
go through `BarChart`/`LineChart` at all, so it is unaffected by this WO regardless.) The WO's
|
|
175
|
+
own explicit "do not build for a case no consumer has; state the assumption" therefore applies
|
|
176
|
+
cleanly, not just plausibly. The residual risk (`ui_reviewer`) is real but one hop removed: the
|
|
177
|
+
first FUTURE consumer that renders a linear x-axis through `BarChart`/`LineChart` with wide
|
|
178
|
+
values should re-check this margin before shipping, and there is no code-level guard that would
|
|
179
|
+
catch it automatically — recorded here so that check doesn't get skipped.
|
|
180
|
+
|
|
181
|
+
### Target repo
|
|
182
|
+
|
|
183
|
+
`C:\Users\biglmi\Documents\webapps\ui-core-micha`
|
|
184
|
+
|
|
185
|
+
## Part C — Orchestrator only — NOT ADDRESSED TO THE IMPLEMENTER
|
|
186
|
+
|
|
187
|
+
> **If you are the implementer reading this work order as your own specification: STOP at this
|
|
188
|
+
> line.**
|
|
189
|
+
|
|
190
|
+
- **Execution.** Codex known-unavailable today — implemented directly in Claude.
|
|
191
|
+
- **Review routing.** `reviewer` + `ui_reviewer`, concurrent, one background batch.
|
|
192
|
+
- **Verification.** Package suite: `chartDefaults.test.js` gained a dedicated
|
|
193
|
+
`withMarginDefaults` describe block (pure-function contract) plus integration tests against
|
|
194
|
+
`BarChart`/`LineChart` (package default applied, rotated-tick chart still gets its enlarged
|
|
195
|
+
bottom margin — not the flat package default, partial-margin per-side merge, full-margin
|
|
196
|
+
passthrough, right > left/bottom by construction); full affected set (`BarChart.test.jsx`,
|
|
197
|
+
`LineChart.test.jsx`, `TimeSeriesChart.test.jsx`, `timeSeriesLegend.test.js`,
|
|
198
|
+
`ScatterChart.test.jsx`, `chartsPalette.test.js`) — 91 tests, green.
|
|
199
|
+
**Rendered check, done live** in the package's own dev harness: (1) the existing "Caller
|
|
200
|
+
overrides" `LineChart` fixture (−25° rotated ticks, no explicit margin — exactly trap 1's
|
|
201
|
+
shape) measured with NO overlap between the rotated tick labels and the axis title (15px
|
|
202
|
+
clear gap) — trap 1 confirmed avoided; (2) a new `LineChart (linear x-axis)` fixture added
|
|
203
|
+
and measured at two magnitudes — narrow (`"100"`) with 5px clearance from the SVG edge, wide
|
|
204
|
+
locale-grouped (`"1,000"`) with MUI's own truncation kicking in at ~1px clearance but never
|
|
205
|
+
actual clipping past the boundary (see the "beyond the WO's risk note" section above).
|
|
206
|
+
- **Register & commit.** Advance the THEME-11 row with the reviewer verdicts. Coordinate the
|
|
207
|
+
consumer pin bump with THEME-8, THEME-9 and THEME-10 — all still open at publish time,
|
|
208
|
+
pending this WO's own reviews and a bundled version bump.
|