@micha.bigler/ui-core-micha 3.6.0 → 3.7.0
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 -1
- package/README.md +2 -0
- package/WORK_ORDERS.md +7 -0
- package/dist/auth/UserMenu.js +23 -1
- package/dist/components/EmptyState.js +17 -0
- package/dist/components/UserListComponent.js +2 -1
- package/dist/i18n/authTranslations.js +196 -0
- package/dist/i18n/uiCoreTranslations.js +19 -0
- package/dist/index.js +2 -1
- package/dist/messaging/Composer.js +4 -2
- package/dist/messaging/MessageBubble.js +2 -1
- package/dist/messaging/ReadTicks.js +5 -3
- package/dist/messaging/linkifyText.js +39 -0
- package/dist/pages/PasswordInvitePage.js +23 -8
- package/dist/pages/SignUpPage.js +4 -4
- package/dist/theme/kitSxRegistry.js +5 -1
- package/package.json +1 -1
- package/src/auth/UserMenu.jsx +26 -1
- package/src/components/EmptyState.jsx +38 -0
- package/src/components/UserListComponent.jsx +2 -0
- package/src/i18n/authTranslations.ts +197 -0
- package/src/i18n/uiCoreTranslations.js +10 -0
- package/src/index.js +2 -1
- package/src/messaging/Composer.jsx +7 -3
- package/src/messaging/MessageBubble.jsx +2 -1
- package/src/messaging/ReadTicks.jsx +4 -3
- package/src/messaging/linkifyText.jsx +37 -0
- package/src/pages/PasswordInvitePage.jsx +36 -7
- package/src/pages/SignUpPage.jsx +79 -68
- package/src/theme/kitSxRegistry.js +9 -1
- package/tests/EmptyState.test.jsx +62 -0
- package/tests/PasswordInvitePage.test.jsx +135 -0
- package/tests/SignUpPage.test.jsx +15 -2
- package/tests/UserListComponent.test.jsx +85 -0
- package/tests/UserMenu.test.jsx +40 -4
- package/tests/i18nGermanVariant.test.js +65 -0
- package/tests/messagingComposer.test.jsx +25 -0
- package/tests/messagingLinkify.test.jsx +51 -0
- package/tests/messagingReadTicksTooltip.test.jsx +36 -0
- package/tests/userScreenTranslations.test.jsx +165 -0
- package/work-orders/UCM-AUTH-9.md +207 -0
- package/work-orders/UCM-I18N-4.md +226 -0
- package/work-orders/UCM-MSG-20.md +192 -0
- package/work-orders/UCM-PRIM-2.md +114 -0
- package/work-orders/UCM-SHELL-7.md +134 -0
- package/work-orders/UCM-THEME-13.md +69 -0
- package/work-orders/UCM-THEME-14.md +140 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# UCM-SHELL-7 — User-menu avatar initials fail contrast
|
|
2
|
+
|
|
3
|
+
# A. Envelope — authored by the Expertenchat
|
|
4
|
+
|
|
5
|
+
## Goal & expected outcome
|
|
6
|
+
|
|
7
|
+
- Goal: the initials in the header avatar are readable.
|
|
8
|
+
- Expected outcome: initials reach at least 4.5:1 against the avatar background, using the consuming
|
|
9
|
+
app's theme tokens rather than MUI's default grey.
|
|
10
|
+
|
|
11
|
+
## Context — measured 2026-09-29 in jg-ferien's local browser test (ucm 3.5.0 installed there)
|
|
12
|
+
|
|
13
|
+
- `UserMenu` (imported in jg-ferien's `Header.jsx`) renders the MUI default avatar: white initials on
|
|
14
|
+
light grey, **1.83:1**, on every page of the app.
|
|
15
|
+
|
|
16
|
+
## Scope + non-goals
|
|
17
|
+
|
|
18
|
+
- In scope: avatar colours in `UserMenu` from theme tokens (e.g. primary surface with its
|
|
19
|
+
contrastText), with a fallback that passes when a consumer defines nothing.
|
|
20
|
+
- Explicit non-goals / do-not-touch: no layout change of the user menu.
|
|
21
|
+
|
|
22
|
+
## Tier · gates
|
|
23
|
+
|
|
24
|
+
- **Tier 3** — shared-core component (small).
|
|
25
|
+
- Reviewer: `ui_reviewer` (no new logic beyond the colour choice).
|
|
26
|
+
- **Done means released and jg-ferien's pin bumped.**
|
|
27
|
+
|
|
28
|
+
## Risks
|
|
29
|
+
|
|
30
|
+
- `createAppTheme` baseline: if the chosen token is optional, `assertThemeComplete` must require it or
|
|
31
|
+
the fallback must pass on its own.
|
|
32
|
+
|
|
33
|
+
## Required tests to WRITE (you write them and run YOUR OWN new ones; the orchestrator's run is the gate)
|
|
34
|
+
|
|
35
|
+
1. With jg-ferien's theme values the avatar pair is at least 4.5:1.
|
|
36
|
+
2. With a theme defining nothing extra the fallback pair is at least 4.5:1.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
# B. Implementation map — filled by the Orchestrator — ADDRESSED TO THE IMPLEMENTER
|
|
41
|
+
|
|
42
|
+
## Context package
|
|
43
|
+
|
|
44
|
+
- File: `src/auth/UserMenu.jsx`. The avatar is rendered at line 60:
|
|
45
|
+
`<Avatar src={avatarSrc} sx={{ width: 32, height: 32, fontSize: '0.8rem' }}>` — no `bgcolor`/`color`
|
|
46
|
+
is set today, so it falls through to MUI's default grey Avatar styling (1.83:1, the measured
|
|
47
|
+
defect). Only this one JSX element changes; nothing else in the file.
|
|
48
|
+
- **Pitfall — do not just reach for `theme.palette.primary.contrastText`.** MUI's own
|
|
49
|
+
`createTheme`/`augmentColor` computes `contrastText` with `contrastThreshold: 3` (tuned for large
|
|
50
|
+
text/graphics, AA), not the 4.5:1 this WO requires for normal-size initials text. A consumer's
|
|
51
|
+
`primary.main` that legitimately passes MUI's own 3:1 threshold can still fail 4.5:1, and nothing
|
|
52
|
+
here re-validates it — so `contrastText` alone is not a fallback that "passes when a consumer
|
|
53
|
+
defines nothing", it is a fallback that USUALLY passes.
|
|
54
|
+
- **Design to implement instead** (uses the kit's own exported contrast helper, satisfies both
|
|
55
|
+
required tests meaningfully since both actually depend on the consumer's `primary.main`):
|
|
56
|
+
1. Import `{ calculateContrastRatio }` from `'../theme'` (already exported from
|
|
57
|
+
`src/theme/index.js` → re-exported at `src/index.js`) and `useTheme` from
|
|
58
|
+
`'@mui/material/styles'`.
|
|
59
|
+
2. Inside `UserMenu`, read `const theme = useTheme();`.
|
|
60
|
+
3. Background: `theme.palette.primary.main` (the "primary surface" the Envelope names).
|
|
61
|
+
4. Text colour: compute
|
|
62
|
+
`calculateContrastRatio(theme.palette.background.paper, theme.palette.primary.main) >= 4.5
|
|
63
|
+
? theme.palette.background.paper : theme.palette.ink.primary`.
|
|
64
|
+
This is not an arbitrary heuristic: for any background colour, the higher of
|
|
65
|
+
(contrast against white) and (contrast against near-black) is mathematically always ≥ √21 ≈
|
|
66
|
+
4.58 — i.e. picking whichever of the kit's own light (`background.paper`, white) or dark
|
|
67
|
+
(`ink.primary`, near-black) ink token has the higher measured contrast against
|
|
68
|
+
`primary.main` is GUARANTEED to clear 4.5:1 for every possible `primary.main`, including one
|
|
69
|
+
a consumer hasn't customised at all (the untouched baseline `primary.main` MUI ships). That is
|
|
70
|
+
what makes this "a fallback that passes when a consumer defines nothing" instead of "usually
|
|
71
|
+
passes".
|
|
72
|
+
5. Apply as `sx={{ ..., bgcolor: theme.palette.primary.main, color: <computed> }}` on the same
|
|
73
|
+
`Avatar` element — keep the existing `width`/`height`/`fontSize` untouched.
|
|
74
|
+
6. Do NOT introduce a new literal hex/rgb anywhere — `theme.palette.background.paper` and
|
|
75
|
+
`theme.palette.ink.primary` are both resolved theme values, and referencing them via
|
|
76
|
+
`theme.palette.<path>` (not writing their hex value as a string literal) keeps
|
|
77
|
+
`reportOffPaletteColours` clean, same as every other component in the kit.
|
|
78
|
+
- Test file: new `tests/UserMenu.test.jsx` (none exists yet — check with `Glob` before assuming;
|
|
79
|
+
if a `UserMenu` test already exists under a different name, extend it instead of creating a
|
|
80
|
+
duplicate). Pattern after `tests/StatTile.test.jsx`: `@vitest-environment jsdom`,
|
|
81
|
+
`createAppTheme(...)`, wrap `UserMenu` in the theme provider AND `AuthContext.Provider` (it reads
|
|
82
|
+
`user`/`logout` via `useContext(AuthContext)` at line 32 — a minimal `{ user: { username: 'ab' },
|
|
83
|
+
logout: () => {} }` value is enough to render the avatar).
|
|
84
|
+
1. With a theme built from jg-ferien's actual `primary.main` — `#367964` (measured directly from
|
|
85
|
+
`jg-ferien/frontend/src/theme.js:25`, a mid-brightness teal-green), assert
|
|
86
|
+
`calculateContrastRatio(<resolved avatar text colour>, <resolved avatar bg colour>) >= 4.5`
|
|
87
|
+
by reading the rendered `Avatar`'s computed `backgroundColor`/`color` via
|
|
88
|
+
`window.getComputedStyle` (see `tests/StatTile.test.jsx`'s `accent` border test for the
|
|
89
|
+
`getComputedStyle` pattern) and feeding both into `calculateContrastRatio` directly — do not
|
|
90
|
+
hardcode an expected hex, assert the ratio.
|
|
91
|
+
2. With `createAppTheme({})` (no consumer overrides — MUI's own baseline `primary.main`), assert
|
|
92
|
+
the same ≥4.5 computed-style contrast check.
|
|
93
|
+
|
|
94
|
+
## Do-not-touch / invariants
|
|
95
|
+
|
|
96
|
+
- No layout change to the user menu (Envelope non-goal) — only the two `sx` colour values change.
|
|
97
|
+
- Do not touch `assertThemeComplete`/`THEME_COMPLETENESS_SURFACES` — this fix reads existing
|
|
98
|
+
required surfaces (`primary.main`, `background.paper`, `ink.primary`), it does not need a new one.
|
|
99
|
+
|
|
100
|
+
## Target repo working directory (absolute)
|
|
101
|
+
|
|
102
|
+
`C:\Users\biglmi\Documents\webapps\ui-core-micha` (branch `main`)
|
|
103
|
+
|
|
104
|
+
## Preamble — a REQUIRED block IN this file, not something appended at invocation
|
|
105
|
+
|
|
106
|
+
> The text above is the COMPLETE spec — the committed WO file's content, not a plan to refine; there
|
|
107
|
+
> is no separate plan file. Read the nearest `AGENTS.md`, the relevant `.codex/skills/<role>/SKILL.md`, and the
|
|
108
|
+
> app `MEMORY.md` ONLY for conventions. Stay in scope; do not touch auth/permissions/deps/schema/CI
|
|
109
|
+
> unless the spec says so; do not update `MEMORY.md`. **Do NOT edit `WORK_ORDERS.md` — the register
|
|
110
|
+
> row and the review verdicts are the orchestrator's alone.** **Your tools are for editing source
|
|
111
|
+
> and test files and for running the tests you wrote — nothing else.** Do NOT install dependencies,
|
|
112
|
+
> touch a lockfile, run a package manager, or tidy up stray files; if something in the repo state
|
|
113
|
+
> blocks you, stop and report it as `RESULT: BLOCKED <reason>` instead of fixing it. Do NOT
|
|
114
|
+
> `git add`/`commit`/`push` — leave every
|
|
115
|
+
> change uncommitted in the working tree for the orchestrator's independent review. WRITE the tests
|
|
116
|
+
> the `Required tests` section calls for AND **RUN the tests you just wrote** to confirm they execute
|
|
117
|
+
> and pass — that is the ONLY test run you do (NOT the app's affected/full suite, NOT any review).
|
|
118
|
+
> The orchestrator re-runs the authoritative set + does the independent review after you finish —
|
|
119
|
+
> those are the gate; your own run does not count as the gate.
|
|
120
|
+
>
|
|
121
|
+
> Narrate continuously: a `PLAN: <step1> | <step2> | …` line up front, then a single-line
|
|
122
|
+
> `PROGRESS: [<n>/<total>] <present-tense action>` before every relevant action (and `… done` on
|
|
123
|
+
> completion), spaced so no gap exceeds ~2 min, stdout unbuffered, plus exactly one final
|
|
124
|
+
> `RESULT: DONE|BLOCKED <reason>`.
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
# C. Orchestrator only — NOT ADDRESSED TO THE IMPLEMENTER
|
|
129
|
+
|
|
130
|
+
> **If you are the implementer reading this work order as your own specification: STOP at this line.
|
|
131
|
+
> Everything below describes what the Orchestrator does AFTER you finish. You do none of it — no
|
|
132
|
+
> reviewers, no verification run, no register edit, no commit.**
|
|
133
|
+
|
|
134
|
+
*(to be filled by the Orchestrator: execution directive; `ui_reviewer`; release; jg-ferien pin bump; register rows here and in jg (`JG-DL-12`).)*
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# UCM-THEME-13: Freeze a dark-mode baseline token set
|
|
2
|
+
|
|
3
|
+
# A. Envelope, authored by the Expertenchat
|
|
4
|
+
|
|
5
|
+
## Goal & expected outcome
|
|
6
|
+
|
|
7
|
+
The central token file `src/theme/tokens.js` has one light baseline palette and no dark one. This order
|
|
8
|
+
produces the **decided** dark token set as a committed reference sheet, `docs/DARK-TOKENS.md`. The
|
|
9
|
+
operator freezes it before `UCM-THEME-14` puts those values into code. The output is a document. No
|
|
10
|
+
source file changes here.
|
|
11
|
+
|
|
12
|
+
Operator decision (2026-09-29): dark mode gets its own work order in the kit, rather than one app keeping
|
|
13
|
+
a raw `createTheme` for it.
|
|
14
|
+
|
|
15
|
+
## Context the operator established
|
|
16
|
+
|
|
17
|
+
- **One consumer today: `webshop-guenter`.** It has a light/dark switch (`frontend/src/App.jsx:96`)
|
|
18
|
+
and a hand-built `darkTheme` from its operator design handoff (background `#0E0B08`, paper
|
|
19
|
+
`#171209`, primary `#D49040`, secondary `#A88868`). Its adoption, `WSG-THEME-1`, is blocked on this
|
|
20
|
+
order and on `UCM-THEME-14`. No other app in the estate renders a dark theme (measured 2026-09-29).
|
|
21
|
+
- The light baseline covers: the palette (primary is app identity; secondary, the status family
|
|
22
|
+
`success/warning/error/info/stale` with `main/light/dark/contrastText` plus `text/fill/bg`,
|
|
23
|
+
`background.default/subtle/paper`, the text inks, `divider`, `controlBorder`), `dataSeries` (six
|
|
24
|
+
categorical colours) and `shadow.rest/overlay`. Typography, radii, spacing, density and motion do not
|
|
25
|
+
depend on the mode.
|
|
26
|
+
|
|
27
|
+
## Scope + non-goals
|
|
28
|
+
|
|
29
|
+
In scope: `docs/DARK-TOKENS.md` with a value for every **mode-dependent** light token class listed
|
|
30
|
+
above, each with a one-line reason, and a contrast table: every text/fill pair and every
|
|
31
|
+
`main`-on-surface pair at 3:1 or better against the dark `background.default` and `background.paper`.
|
|
32
|
+
Follow the `design-language` skill's process: inventory first, then a structural round, then values
|
|
33
|
+
decided in an instrument, then the freeze.
|
|
34
|
+
|
|
35
|
+
Non-goals:
|
|
36
|
+
- No change to any light value.
|
|
37
|
+
- No code, no tests. `UCM-THEME-14` implements.
|
|
38
|
+
- No per-app dark identity. An app's dark primary stays that app's own, just as its light one does.
|
|
39
|
+
- No automatic switching (`prefers-color-scheme`) and no toggle component. Apps own their switch.
|
|
40
|
+
|
|
41
|
+
## Tier · precondition / gate
|
|
42
|
+
|
|
43
|
+
- **Tier 2 · tests: none (document only).** It decides the future content of shared-core, but it does
|
|
44
|
+
not change shared-core. The code change is `UCM-THEME-14`, which is Tier 3.
|
|
45
|
+
- Precondition: none.
|
|
46
|
+
- Gate: **the operator freezes the sheet**, and the sheet itself says so with a dated section. Until
|
|
47
|
+
then `UCM-THEME-14` does not start.
|
|
48
|
+
|
|
49
|
+
## Risks
|
|
50
|
+
|
|
51
|
+
- **A dark palette drawn from a single app's handoff becomes that app's palette for everyone.**
|
|
52
|
+
webshop-guenter's values are one input to the inventory, not the answer. It keeps its own values as
|
|
53
|
+
identity in any case (`WSG-THEME-1`).
|
|
54
|
+
- **Status tints (`bg`) are the class that breaks first on dark.** A light tint over a dark page fails
|
|
55
|
+
contrast in the other direction.
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
# B. Implementation map
|
|
60
|
+
|
|
61
|
+
*Not applicable. This is an Expertenchat document order, authored in-session with the operator.*
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
# C. Orchestrator only, NOT ADDRESSED TO THE IMPLEMENTER
|
|
66
|
+
|
|
67
|
+
> **If you are the implementer reading this: STOP.** There is no implementer for this order.
|
|
68
|
+
|
|
69
|
+
Register: row -> `done` with the commit of the frozen sheet. Downstream: `UCM-THEME-14` unblocks.
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# UCM-THEME-14: Dark mode in `createAppTheme`, from the central token file
|
|
2
|
+
|
|
3
|
+
# A. Envelope, authored by the Expertenchat
|
|
4
|
+
|
|
5
|
+
## Goal & expected outcome
|
|
6
|
+
|
|
7
|
+
`createAppTheme({ palette: { mode: 'dark', primary }, ... })` builds a complete dark theme whose
|
|
8
|
+
mode-dependent values come from a dark baseline palette in `src/theme/tokens.js`, next to the light
|
|
9
|
+
one. `assertThemeComplete` judges a dark theme against its own surfaces. **The light output does not
|
|
10
|
+
change by a single value.**
|
|
11
|
+
|
|
12
|
+
Afterwards an app with a light/dark switch (today only `webshop-guenter`, `WSG-THEME-1`) can compose
|
|
13
|
+
both of its themes through the factory.
|
|
14
|
+
|
|
15
|
+
## Value source
|
|
16
|
+
|
|
17
|
+
**`docs/DARK-TOKENS.md`, frozen by the operator in `UCM-THEME-13`.** Every dark value in code comes
|
|
18
|
+
from that sheet. A value the implementation needs that the sheet does not carry is a stop-and-report.
|
|
19
|
+
Do not improvise it.
|
|
20
|
+
|
|
21
|
+
## Context the operator established
|
|
22
|
+
|
|
23
|
+
- `createAppTheme` (`src/theme/createAppTheme.js`) resolves the palette in three layers: the app's
|
|
24
|
+
palette, then `BASELINE_PALETTE`, then the app's palette again. It then derives
|
|
25
|
+
`controlBorder.focus`, builds the palette-aware component slots, and merges `BASELINE_STATIC`, those
|
|
26
|
+
components and the app config. `palette.mode` is not read anywhere today.
|
|
27
|
+
- **Two places assume a white page:**
|
|
28
|
+
- `deriveFocusColour` checks 3:1 against `'#FFFFFF'` and `background.default`, and only ever
|
|
29
|
+
**darkens** the primary. On a dark page it would have to lighten.
|
|
30
|
+
- `contrastFindings` in `src/theme/themeCompleteness.js` checks against a fixed
|
|
31
|
+
`white: '#FFFFFF'` (line 298) plus `page: background.default`.
|
|
32
|
+
- `BASELINE_INTENTIONAL_DEFAULT_EXEMPTIONS` includes `palette.background.paper` with the reason "The
|
|
33
|
+
canonical surface is deliberately MUI white". That reason is false for a dark theme.
|
|
34
|
+
- The palette-aware slots use palette values (for example the autofill inset uses `background.paper`),
|
|
35
|
+
so they follow the resolved palette once it is right.
|
|
36
|
+
- The kit has components registered against the baseline (`src/theme/kitSxRegistry.js`, `THEME-4`/
|
|
37
|
+
`THEME-5`). A kit component that hard-codes a light value would show that value only in dark mode.
|
|
38
|
+
|
|
39
|
+
## Scope + non-goals
|
|
40
|
+
|
|
41
|
+
In scope:
|
|
42
|
+
1. `tokens.js`: a dark baseline palette with the sheet's values, and whatever exemption entries a
|
|
43
|
+
dark theme needs, each with a true reason.
|
|
44
|
+
2. `createAppTheme`: select the baseline palette by `palette.mode`. Make the focus derivation work in
|
|
45
|
+
both directions against the mode's surfaces.
|
|
46
|
+
3. `themeCompleteness.js`: contrast checks against the theme's own surfaces, not a fixed white. Mode-
|
|
47
|
+
specific exemptions.
|
|
48
|
+
4. Kit components that resolve a hard-coded light value instead of a token: **list** every one.
|
|
49
|
+
Switching one to an existing token is in scope. Anything that needs a new token is a finding.
|
|
50
|
+
5. `DESIGN.md` (a dark-mode section), `CHANGELOG.md`, and a **minor** version bump. The change is
|
|
51
|
+
additive: light output is unchanged, and dark is new.
|
|
52
|
+
|
|
53
|
+
Non-goals:
|
|
54
|
+
- No change to any light value or light behaviour.
|
|
55
|
+
- No automatic `prefers-color-scheme` switching and no toggle component.
|
|
56
|
+
- No consumer adoption. `WSG-THEME-1` does that in its own repo, after its own pin bump.
|
|
57
|
+
- No change to chart components beyond reading palette tokens they already read.
|
|
58
|
+
|
|
59
|
+
## Tier · precondition / gate
|
|
60
|
+
|
|
61
|
+
- **Tier 3 · tests: light-output regression guard, dark completeness, focus contrast in both modes,
|
|
62
|
+
and the kit's existing theme tests.** A change inside shared-core (`AGENTS.md` -> Tiering).
|
|
63
|
+
- Precondition: **`UCM-THEME-13` frozen.**
|
|
64
|
+
- Downstream: `webshop-guenter`/`WSG-THEME-1` waits for this release and for its own pin bump.
|
|
65
|
+
|
|
66
|
+
## Risks
|
|
67
|
+
|
|
68
|
+
- **Ten adopted apps consume the light path.** A light regression reaches all of them on their next
|
|
69
|
+
bump. That is why the regression guard is a required test, not a nice-to-have.
|
|
70
|
+
- **The three-layer palette merge interacts with augmentation** (the comment at the top of `tokens.js`:
|
|
71
|
+
only the first `createTheme` argument is augmented). A dark status entry missing
|
|
72
|
+
`main`/`contrastText` would silently keep MUI's light hue.
|
|
73
|
+
- **Contrast in the other direction.** Light status tints (`bg`) over a dark page, and a focus colour
|
|
74
|
+
derived by darkening, both fail on dark.
|
|
75
|
+
- **The `background.paper` exemption reason is currently mode-blind.** Leaving it would record a false
|
|
76
|
+
statement as the reason in every dark theme.
|
|
77
|
+
|
|
78
|
+
## Required tests to WRITE (you write them and run YOUR OWN new ones; the Orchestrator's run is the gate)
|
|
79
|
+
|
|
80
|
+
Kit test suite, narrow, next to the existing theme tests:
|
|
81
|
+
|
|
82
|
+
1. **Light regression guard.** For a fixed light app config, the fully resolved theme (palette,
|
|
83
|
+
typography, shape, components, exemptions) equals the output from before this change. Show that the
|
|
84
|
+
test fails when one light value is altered by hand. A structural test that cannot fail is
|
|
85
|
+
decoration.
|
|
86
|
+
2. **Dark completeness.** `assertThemeComplete(createAppTheme({ palette: { mode: 'dark', primary } }))`
|
|
87
|
+
has zero findings, or only exemptions with a true reason. The same check with a primary that has to be
|
|
88
|
+
**lightened** to clear contrast.
|
|
89
|
+
3. **Focus contrast.** `controlBorder.focus` clears 3:1 against both page surfaces in each mode.
|
|
90
|
+
4. **Status family on dark.** Each status key resolves `main/light/dark/contrastText` from the dark
|
|
91
|
+
baseline, not MUI's defaults.
|
|
92
|
+
|
|
93
|
+
Run, do not write: the kit's existing theme and `kitSxRegistry` tests.
|
|
94
|
+
|
|
95
|
+
## Parity guardrail
|
|
96
|
+
|
|
97
|
+
No light-mode change of any kind. No behaviour, API or data-contract change beyond the new `mode`
|
|
98
|
+
branch.
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
# B. Implementation map, filled by the Orchestrator and ADDRESSED TO THE IMPLEMENTER
|
|
103
|
+
|
|
104
|
+
*Placeholder. The Orchestrator fills the context package, the absolute working directory, the
|
|
105
|
+
progress contract and the preamble block on `git pull`, per `AGENTS.md` -> "Work Order". Do not
|
|
106
|
+
dispatch while this placeholder stands, and not before `UCM-THEME-13` is frozen.*
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
# C. Orchestrator only, NOT ADDRESSED TO THE IMPLEMENTER
|
|
111
|
+
|
|
112
|
+
> **If you are the implementer reading this work order as your own specification: STOP at this line.**
|
|
113
|
+
> Everything below describes what the Orchestrator does AFTER you finish. You do none of it: no
|
|
114
|
+
> reviewers, no verification run, no register edit, no `git add`/`commit`/`push`.
|
|
115
|
+
|
|
116
|
+
### Execution directive
|
|
117
|
+
|
|
118
|
+
Check `.claude/codex-status.md` first (newest-first; read it with `head`). No line for today means use
|
|
119
|
+
Codex.
|
|
120
|
+
|
|
121
|
+
### Review routing
|
|
122
|
+
|
|
123
|
+
Tier 3: independent `reviewer` (all configured lenses) and `ui_reviewer`, concurrent, one batch,
|
|
124
|
+
before the commit. No `sec_reviewer`.
|
|
125
|
+
|
|
126
|
+
### Verification
|
|
127
|
+
|
|
128
|
+
Render a kit demo surface in both modes at 375 px and 1280 px (`dev/`), and name the screenshots in
|
|
129
|
+
the register Notiz. No prototype is in scope.
|
|
130
|
+
|
|
131
|
+
### Register + commit + release
|
|
132
|
+
|
|
133
|
+
Row -> `done` with the review Notiz in the `AGENTS.md` shape. The publish runs on push to `main` when
|
|
134
|
+
`package.json`/`src/**` change (`.github/workflows/publish.yml`). Then add a planned row in
|
|
135
|
+
`webshop-guenter/WORK_ORDERS.md` for the pin bump to this version, and unblock `WSG-THEME-1`.
|
|
136
|
+
|
|
137
|
+
### Mini-handover
|
|
138
|
+
|
|
139
|
+
`Orchestrator: implement work-orders/UCM-THEME-14.md in ui-core-micha (main). git pull first, confirm
|
|
140
|
+
UCM-THEME-13 is frozen, read the WO, then follow orchestrate-codex.`
|