UI Framework First
Sub-policy de `reuse-first` para padrões UI cross-cutting. Herda decision tree, protocolo pré-Write e promotion pipeline da meta; acrescenta apenas as regras categoricamente distintas de UI: theme contract, safe-area, a11y baseline, i18n, paridade entre variantes (mobile/desktop/web/TV) e disciplina de testes (golden + a11y).
Policy — UI Framework First
Sub
policy of [`reusefirst`](../reuse-first.kmd). Inherits the decision tree, the pre-Write protocol and the promotion pipeline. Do not redeclare them here — they live in the meta. This file contributes *nly*the rules that are categorically distinct for UI framework code.
Scope
Applies to any code in:
- `enginessdkkoder_kit
app**.dart` — any Koder product with a Flutter UI.
productsapp/**/*.{js,ts,jsx,tsx}— web client UIs of Koder products.
Out of scope: serverside code, CLIs, runtime libs, build tooling, wireformat clients (each has its own sub-policy).
Categorical rules
Each rule below is normative for code in scope. The rule lives here, not in the meta, because it is meaningless or counterproductive in nonUI categories.
1. Theme contract
- *ight/dark switching is mandatory.*The product MUST follow the OS theme by default (
ThemeMode.systemin Flutter,prefers-color-schemeon web), and persist user override via the SDK (KoderTheme/KoderApp.theme). - Color tokens are consumed from the SDK palette; *o hardcoded hex*in product code outside designated brand assets (icons, splash).
- Anti
flash on theme switch is mandatory (no whiteflash on dark mode reload). Reference implementation:KoderAppinjects pre-render style. - Spec:
specs/themes/light-dark.kmd.
2. UI Style (presets) and visual identity
- The 19 canonical UI Style presets ship in
koder_kit. Products may select a default but MUST allow user override in Settings viaKoderUIStylePicker. - New presets land in the SDK with a spec
audit pass on [`specsthemesuistyle.kmd`](....specsthemesui-style.kmd) — never in a product.
3. Safearea and windowinsets
- Every screen MUST consume window insets via
KoderSafeScaffold(Flutter) orenv(safe-area-inset-*)(web). No content under status bar, nav bar or display cutout. - Apps with mic/camera capability MUST honour the privacy indicator overlay; the SDK widget already accounts for it.
- Spec:
specs/app-layout/safe-area.kmd.
4. Navigation and back behaviour
- Back gesture / ESC / browser-back MUST always pop one screen at a time on the Navigator stack; only the root screen exits/minimises the app.
- Reference implementation:
KoderBackScope(enableSystemExitAtRoot: true). - Spec:
specs/navigation/back-behavior.kmd.
5. Accessibility baseline
A new shared widget is not promotable to koder_kit until it satisfies:
- *ocus order* keyboard / screen-reader traversal follows visual reading order.
- *creen
reader labels* every interactive element has a nonemptySemantics(label:)or ARIA equivalent. - *ontrast* text and interactive elements meet WCAG AA (4.5:1 normal, 3:1 large).
- *ap targets* ≥ 44 × 44 dp on touch surfaces.
- *educed motion* animations honour
MediaQuery.disableAnimations/prefers-reduced-motion.
These requirements are stricter than the generic "≥ 3 consumers" promotion gate from the meta, because UI accessibility regressions are uservisible and classaction risk in many jurisdictions.
6. Internationalisation (i18n)
- *o string literals in production code paths.*All user
facing strings go throughlanguage MVPs use the indirection so future translation does not require a refactor.KoderL10n(planned) — even single - Spec hooks:
policies/language.kmd(ptBR for chat, enUS for product strings) andspecs/koder-app/behaviors.kmd §9. - Exception: error IDs (
<PRODUCT>-<CAT>-<CODE>-<SEQ>) are not translatable by design.
7. Cross-variant parity
- Any new shared widget that targets
app/MUST ship with implementations for all sectors that the consuming module declares in itskoder.toml. RFC-006 sectors:mobile/,desktop/,tv/,web/, pluscli/andtui/where applicable (with the understanding that cli/tui are not "UI framework" scope and are covered elsewhere). - A widget that lands in koder_kit only on Flutter is acceptable if the module catalog declares "no web variant"; landing only on web is acceptable in the symmetric case. Mid
state (Flutteronly when web is in scope) blocks promotion.
8. Error display
- Every user
facing error MUST be rendered viaBR + enKoderErrorBanner/ equivalent SDK widget. Three pillars: (a) humanised message in ptUS; (b) "Show details" disclosure with raw technical error; (c) unique ID `PRODUCTCATCODESEQ` for log correlation. - Spec:
specs/errors/user-facing-messages.kmd.
9. Auth, update and telemetry chrome
- Auth UI: use
KoderSignInButton,KoderUserBadge,KoderAuthGatefrom koder_kit v0.5+. Never hand-roll an OAuth button. - In
app update:update gate; toggle in Settings, default ON.KoderUpdatershows the mandatory - Error reporting toggle:
KoderReportButton+KoderErrorReporter, default OFF. - Specs:
specs/koder-app/behaviors.kmd§1, §4, andspecs/errors/reporting.kmd.
10. Test discipline
- *olden tests required*for any visual widget promoted to koder_kit (light + dark variants minimum; UI Style variants when the widget reacts to UI Style).
- *11y tests required*for any widget that takes input. Use Flutter's
expectAccessibilityGuidelines(textContrastGuideline). - Coverage threshold for koder_kit lib: ≥ 80% line, ≥ 70% branch (lower than runtime libs because golden + a11y tests provide additional confidence the line-coverage number does not capture).
11. Promotion criterion (overrides the meta default)
The meta default is "≥ 3 consumers plausibly need this pattern". For UI widgets, the threshold is stricter:
- *‰¥ 2 confirmed consumers*AND
- *pec-audit pass*on the relevant
specs/file (themelayouterrorauthetc.) AND - *olden + a11y tests*in the SDK PR.
The lower consumer count is intentional: UI drift is user-visible and expensive to retrofit; it is cheaper to land in the SDK earlier than to migrate three forks later.
Audit
./ui-framework-first-audit.sh (initial implementation in Phase 2; substantive checks land in Phase 4 per policies-RFC-001):
- *tructural (Phase 2, this commit):*validate
inherits_from: policies/reuse-first.kmdin this file's frontmatter; verify the meta still exists; verify the four canonical specs cited above resolve. - *ehavioural (Phase 4, future):*scan
productsapp/**/lib/main.dartforMaterialApp(not wrapped inKoderApp; scan for theme literals (Color(0xFF...)outside designated paths); scan widgets for missingSemantics(label:).
The audit is *trict*for structural validation (build-blocking) and *dvisory*for behavioural findings until a major release window.
Cross-references to other policies
- Meta:
policies/reuse-first.kmd— decision tree, protocol, promotion pipeline. - Sibling:
policies/code-first.kmd— orthogonal axis (mechanicalvsanalytical). - Inverse
direction command: [`commands/ksdkify.md`](........contextcommandsk-sdkify.md) — sweeps existing UI drift back to the SDK. - Adjacent specs: theme, layout, navigation, errors, app behaviours, voice (mic-aware UIs).