calm-components

Enforces Odova's Calm Flutter widget library rules, states, and token usage.

Updated Sep 2, 2026
One-click install
npx skills add https://github.com/zakariaf/Odova --skill calm-components-zakariaf
Or copy as Structured Prompt for Agent
Please help me install this Agent Skill.
Skill: calm-components
Source: https://github.com/zakariaf/Odova/tree/main/.claude/skills/calm-components
Command: npx skills add https://github.com/zakariaf/Odova --skill calm-components-zakariaf

SYSTEM DOCUMENTATION & REQUIREMENTS

💡 This Skill includes scripts (resource) and references (resource) components.

What problem does it solve? Flutter teams building Odova screens can drift from the Calm design system by reaching for Material widgets, hand-rolled BoxDecorations, ripples, or borders, producing inconsistent UI that fails review late. This Skill defines exactly what each of the 22 Calm widgets is, which states and tokens it reads, and how to keep feature code compliant. ## Core Features & Use Cases - Component contract: Documents all 22 Calm widgets (CalmButton, CalmCard, CalmRowGroup, CalmField, CalmSheet, CalmNumberPad, and more) with variants, states, constructor signatures, and the exact CalmColors/CalmType/CalmSpace/CalmShapes/CalmMotion tokens each state reads. - Interaction rules: Specifies the 90ms scale-and-tint press via CalmPressable, NoSplash enforcement, the additive 3pt focus ring, the 52pt hit-area floor, and reduced-motion collapse to Duration.zero. - Automated hygiene gate: Ships scripts/check_component_hygiene.sh, which fails a PR on BoxDecoration outside lib/ui/calm/, live ink splashes, borders outside the two allowlisted files, Material widget substitutes, and ColorScheme/TextTheme reads in lib/ui/. - Use Case: When building a new Odova screen or reviewing a PR, consult the component inventory to pick the right Calm widget instead of ListTile or Card, then run the hygiene script before merging. ## Quick Start Ask the assistant to build or review an Odova screen widget using the Calm component rules and then run the component hygiene check over lib/.

Frequently Asked Questions about calm-components

High-intent search queries and answers about installing and using this skill.

FAQPage Schema
How do I replace Material widgets with Calm components in Flutter?

Use the mapping table: CalmButton replaces ElevatedButton/FilledButton/TextButton, CalmCard replaces Card, CalmListRow inside CalmRowGroup replaces ListTile, CalmField replaces TextField, and CalmSheet replaces showModalBottomSheet. Each Calm widget reads its values from CalmColors/CalmType/CalmSpace/CalmShapes/CalmMotion.of(context).

How do I implement press feedback without InkWell ripple in Flutter?

Use CalmPressable, which combines AnimatedScale at 90ms with easeOut and a one-step surface tint change (surface to surface2 to surface3). The app theme sets NoSplash.splashFactory and transparent highlightColor so any surviving InkWell stays silent.

What does check_component_hygiene.sh validate?

The script fails on BoxDecoration or ShapeDecoration outside lib/ui/calm/, Material widget substitutes, Border.all/BorderSide outside the allowlisted files, live ink splashes, InkWell without NoSplash, and Theme.of(context).colorScheme/textTheme reads inside lib/ui/.

Why must Flutter controls smaller than 52pt still meet the touch target?

Calm's design rule sets a 52pt minimum hit area, but controls like CalmChip paint at 40pt. CalmPressable wraps them in a render object that expands the gesture target to 52pt while keeping the painted size unchanged, so the visual spec stays intact.

Can a CalmCard have a border for extra separation?

No. Calm surfaces never carry borders; depth comes from the two-layer warm shadow (elev1) plus the sheen highlight. The only borders allowed in the codebase are the CalmField input ring and the CalmPressable focus ring.

How should disabled buttons behave in Odova forms?

A disabled CalmButton uses the surface2/ink4 color pair and must be accompanied by a CalmButtonExplain stating what is missing. On the five log.* forms, Save is never disabled at all; it validates on tap and focuses the first failing field.