utils/design_system
Krzysztof kuhy Rudnicki 978d32af3a Don't judge allowlist rot from a file-scoped run; cut two library versions
Two things, because the first is what blocked the second from committing.

**The rot check was scope-blind.** pre-commit passes only the staged
manifests, so a run that sees no package.json cannot learn anything about
whether the fleet-wide typescript hold is still needed -- yet it concluded the
entry was dead and exited 2. Staging two pubspec.yaml files in utils was
enough to make the repo uncommittable. The dead-entry check now runs only
under --all, which is CI and the manual whole-repo run; a subset scan has seen
a subset by construction.

**crdt_sync_dart 0.11.1 and design_system 0.2.1.** Both had dependency
upgrades land after their newest tag, so a consumer moving to "latest tag"
would pick up the pre-upgrade constraints (crdt_sync_dart-v0.11.0 still
carries `crypto: ^3.0.7`, `http: ^1.6.0`, `lints: ^5.0.0`) while carrying its
own new exact pins -- the unsatisfiable-resolution case exact pins create.
Version bump only; the dependency work is already in 922fb36 and 704c67e.

The allowlist end-to-end tests moved to their own file for the 250-line cap,
and `run`/`canned` moved to conftest so both files share one definition.
`canned` is no longer autouse: the resolver tests patch `_fetch` themselves.

293 tests, 100% branch coverage on every production module.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CRykabMwPgDzFHcARoqpaK
2026-08-28 14:07:09 +02:00
..
lib Freeze the motion, haptic and sound vocabularies, and ship them as tokens 2026-08-22 17:28:02 +02:00
scripts crdt_sync_dart: latest stable + exact pins, 100% coverage, CI for both crdt_sync packages 2026-08-28 12:32:24 +02:00
test Freeze the motion, haptic and sound vocabularies, and ship them as tokens 2026-08-22 17:28:02 +02:00
.gitignore Add design_system: the shared Flutter component layer 2026-08-14 22:51:06 +02:00
.pre-commit-config.yaml Fix the cap hook in CI, and the re-exports its --all-files run exposed 2026-08-22 15:52:59 +02:00
analysis_options.yaml Add design_system: the shared Flutter component layer 2026-08-14 22:51:06 +02:00
pubspec.yaml Don't judge allowlist rot from a file-scoped run; cut two library versions 2026-08-28 14:07:09 +02:00
README.md Add the shared markdown-naming gate and migrate utils' own docs 2026-08-24 15:53:12 +02:00

design_system

The shared Flutter component layer for kuhy's apps.

~/utils/unified-design-system/ froze the token layer — one palette, one spacing scale, one type scale — but it is documentation only: 1220 lines of prose and annotated HTML, zero importable code. Every repo transcribed the token table by hand, and then drifted from it.

This package is that same token set as Dart, plus the handful of widgets that had each been reimplemented in three or more repos. The components own the tokens: a consumer that depends on this package has nothing local left to edit, so the palette is enforced by the compiler and the package manager instead of by prose plus discipline.

Consuming it

Tag-pinned git dependency, matching the convention sync_settings_ui and crdt_sync_dart already use:

dependencies:
  design_system:
    git:
      url: https://github.com/kuhyx/utils
      ref: design_system-v0.1.0
      path: design_system

Then delete the repo's local lib/ui/theme.dart and import the package:

import 'package:design_system/design_system.dart';

MaterialApp(
  theme: buildLightTheme(),
  darkTheme: buildDarkTheme(),
  // ...
);

What's in it

Export Replaces
AppPalette ~318 raw Color(0x…) literals, almost all inside hand-copied theme files
AppSpacing / AppRadius / AppTextSize the six-repo consensus scales, transcribed per repo
buildLightTheme() / buildDarkTheme() 10 divergent theme.dart copies (2 byte-identical, 8 drifted)
AppStatusColors 4 hand-rolled ThemeExtensions with inconsistent field sets
confirmDestructive() ~35 inlined AlertDialogs
showToast() / showError() ~38 raw SnackBar sites and zero helpers
EmptyState 4 variants, only one of them reusable
SectionHeader 3 near-identical private widgets

Why the scales are what they are

The values are the six-repo consensus — todo, home_inventory, dufs-cloud, habit_stack, and untools all shipped byte-identical copies — which is also exactly what unified-design-system/DOCS-tokens.md specifies. Repos that had drifted (diet-guard, macro-cam) are corrected to this package, not the other way round.

Why explicit ColorSchemes, never fromSeed

The palette is hand-picked to hit specific contrast ratios. A seeded scheme silently replaces those values with algorithmically derived ones. The secondary/tertiary slots are set explicitly for the same reason: without them, widgets that reach for secondaryContainer (e.g. SegmentedButton's selected segment) fall back to stock Material teal — confirmed on-device.

Development

flutter analyze                                  # must be clean
dart format lib test
flutter test --coverage
scripts/check_coverage.sh coverage/lcov.info 100 # 100% line coverage, gated

Coverage is a gate, not a convention: this ships as a 100%-covered shared package by requirement. The gate runs on pre-push.