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

Policy — UI Framework First

Subpolicy 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.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; *o hardcoded hex*in product code outside designated brand assets (icons, splash).
  • Antiflash on theme switch is mandatory (no whiteflash 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 specaudit pass on [`specsthemesuistyle.kmd`](....specsthemesui-style.kmd) — never in a product.

3. Safearea and windowinsets

  • 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:

  • *ocus order* keyboard / screen-reader traversal follows visual reading order.
  • *creenreader labels* every interactive element has a nonempty Semantics(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 userfacing strings go through KoderL10n (planned) — even singlelanguage MVPs use the indirection so future translation does not require a refactor.
  • Spec hooks: policies/language.kmd (ptBR for chat, enUS 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. Midstate (Flutteronly when web is in scope) blocks promotion.

8. Error display

  • Every userfacing error MUST be rendered via KoderErrorBanner / equivalent SDK widget. Three pillars: (a) humanised message in ptBR + enUS; (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, KoderAuthGate from koder_kit v0.5+. Never hand-roll an OAuth button.
  • Inapp update: KoderUpdater shows the mandatoryupdate 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

  • *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):

  1. *tructural (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. *ehavioural (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 *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).
  • Inversedirection 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).

Source: ../home/koder/dev/koder/meta/docs/stack/policies/reuse/ui-framework-first.kmd