UI Framework First

mandatory

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).

Sub-policy of reuse-first. 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 only 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: server-side code, CLIs, runtime libs, build tooling, wire-format 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 counter-productive in non-UI categories.

1. Theme contract

  • Light/dark switching is mandatory. The product MUST follow the OS theme by default (ThemeMode.system in Flutter, prefers-color-scheme on web), and persist user override via the SDK (KoderTheme / KoderApp.theme).
  • Color tokens are consumed from the SDK palette; no hardcoded hex in product code outside designated brand assets (icons, splash).
  • Anti-flash on theme switch is mandatory (no white-flash on dark mode reload). Reference implementation: KoderApp injects 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 via KoderUIStylePicker.
  • New presets land in the SDK with a spec-audit pass on specs/themes/ui-style.kmd — never in a product.

3. Safe-area and window-insets

  • Every screen MUST consume window insets via KoderSafeScaffold (Flutter) or env(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:

  • Focus order: keyboard / screen-reader traversal follows visual reading order.
  • Screen-reader labels: every interactive element has a non-empty Semantics(label:) or ARIA equivalent.
  • Contrast: text and interactive elements meet WCAG AA (4.5:1 normal, 3:1 large).
  • Tap targets: ≥ 44 × 44 dp on touch surfaces.
  • Reduced 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 user-visible and class-action risk in many jurisdictions.

6. Internationalisation (i18n)

  • No string literals in production code paths. All user-facing strings go through KoderL10n (planned) — even single-language MVPs use the indirection so future translation does not require a refactor.
  • Spec hooks: policies/language.kmd (pt-BR for chat, en-US for product strings) and specs/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 its koder.toml. RFC-006 sectors: mobile/, desktop/, tv/, web/, plus cli/ and tui/ 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 (Flutter-only when web is in scope) blocks promotion.

8. Error display

  • Every user-facing error MUST be rendered via KoderErrorBanner / equivalent SDK widget. Three pillars: (a) humanised message in pt-BR + en-US; (b) "Show details" disclosure with raw technical error; (c) unique ID <PRODUCT>-<CAT>-<CODE>-<SEQ> for log correlation.
  • Spec: specs/errors/user-facing-messages.kmd.

9. Auth, update and telemetry chrome

  • Auth UI: use KoderSignInButton, KoderUserBadge, KoderAuthGate from koder_kit v0.5+. Never hand-roll an OAuth button.
  • In-app update: KoderUpdater shows the mandatory-update gate; toggle in Settings, default ON.
  • Error reporting toggle: KoderReportButton + KoderErrorReporter, default OFF.
  • Specs: specs/koder-app/behaviors.kmd §1, §4, and specs/errors/reporting.kmd.

10. Test discipline

  • Golden tests required for any visual widget promoted to koder_kit (light + dark variants minimum; UI Style variants when the widget reacts to UI Style).
  • A11y 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
  • Spec-audit pass on the relevant specs/ file (themelayouterrorauthetc.) AND
  • Golden + 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):

  1. Structural (Phase 2, this commit): validate inherits_from: policies/reuse-first.kmd in this file's frontmatter; verify the meta still exists; verify the four canonical specs cited above resolve.
  2. Behavioural (Phase 4, future): scan productsapp/**/lib/main.dart for MaterialApp( not wrapped in KoderApp; scan for theme literals (Color(0xFF...) outside designated paths); scan widgets for missing Semantics(label:).

The audit is strict for structural validation (build-blocking) and advisory 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 (mechanical-vs-analytical).
  • Inverse-direction command: commands/k-sdkify.md — sweeps existing UI drift back to the SDK.
  • Adjacent specs: theme, layout, navigation, errors, app behaviours, voice (mic-aware UIs).