Skip to content

feat: component styles on every widget with app-wide FlowTheme defaults - #21

Merged
divyanshub024 merged 2 commits into
mainfrom
dv/component-styles
Aug 24, 2026
Merged

feat: component styles on every widget with app-wide FlowTheme defaults#21
divyanshub024 merged 2 commits into
mainfrom
dv/component-styles

Conversation

@divyanshub024

@divyanshub024 divyanshub024 commented Aug 23, 2026

Copy link
Copy Markdown
Member

Summary

Adds Material's component-theme tier on top of flow_ui's tokens. Every major widget now takes an optional style object of color and text overrides, and FlowTheme carries an app-wide default for each.

  • Eight new style classes in lib/src/styles/, joining FlowMenuStyle (moved there too): FlowComposerStyle, FlowMessageStyle, FlowMarkdownStyle, FlowCodeBlockStyle, FlowErrorStateStyle, FlowMessageActionsStyle, FlowPillStyle, FlowSuggestionStyle. Each is an immutable data bag of optional fields with merge (other wins), lerp (theme transitions, following the nullable syntax convention), and value equality. Text fields merge over their role's base.
  • FlowTheme gains one optional field per style (markdownStyle, menuStyle, composerStyle, ...) with full copyWith/lerp. Resolution is field by field everywhere: the widget's style wins over the theme's, tokens beneath both.
  • FlowMarkdownStyle opens the markdown surface per element: heading cuts for all six levels, link color, inline-code face and painted chip fill, quote bar and ink, table header/cell styles and hairlines, rule color. The settled-span cache keys on the resolved style, so restyling invalidates while streaming deltas keep reusing it.
  • Faithful details: the composer's outlineColor flattens the gradient hairline in every state (the menu border precedent); the code block's borderColor holds through hover unless hoverBorderColor says otherwise; failed turns keep their error treatment regardless of bubbleColor.
  • The style classes live in a new lib/src/styles/ folder so the dependency direction matches the taxonomy: widgets -> styles and theme -> styles, with flow_theme.dart no longer importing from widgets/. Everything re-exports through the barrel, so the public API surface is purely additive.

Docs: every component page gains a Restyling section, theming.mdx a "Component styles" section with the resolution story, and the changelog a 0.3.0 (unreleased) entry. The pubspec stays at 0.2.0 so the pending release is unaffected.

Screenshots

How this was verified

flutter analyze clean in the package root, example/, and playground/; dart format applied; docs site builds; flutter pub publish --dry-run validates. A scratch widget-test harness proves the resolution chain behaviorally: a theme FlowMarkdownStyle reaches link spans and chip fills, a widget-level field beats the theme's, FlowMessageStyle/FlowCodeBlockStyle land on the bubble and block grounds, and with nothing installed every token default holds. The existing streaming-reveal tests pass unchanged.

Checklist

  • flutter analyze lib and flutter analyze in example/ and playground/ are clean
  • dart format . applied
  • Exercised in the playground — with a stage demo added or updated if this is a new component or variant
  • No new entries under dependencies: in pubspec.yaml (Flutter SDK and flutter.dev packages only)
  • Nothing model-facing — no prompts, schemas, or provider/network calls
  • New public API is exported from lib/flow_ui.dart and documented in docs/ and the README table
  • CHANGELOG.md updated for user-facing changes, with breaking changes called out
  • PR title follows conventional commits (feat:, fix:, refactor:, docs:, chore:)

Note

Low Risk
Additive theming API with field-by-field merge over existing tokens; no auth, data, or behavior changes unless hosts opt in.

Overview
Adds Material-style component themes on top of flow_ui tokens. Major widgets now take an optional FlowXStyle bag of color/text overrides, and FlowTheme can carry an app-wide default for each.

Resolution is field by field: widget style wins over theme style, tokens underneath. Text fields merge onto their role’s base. FlowMenuStyle moves to lib/src/styles/ with the new classes (FlowComposerStyle, FlowMessageStyle, FlowMarkdownStyle, FlowCodeBlockStyle, FlowErrorStateStyle, FlowMessageActionsStyle, FlowPillStyle, FlowSuggestionStyle). Public API is additive.

FlowMarkdownStyle covers headings, links, inline-code chips, quotes, tables, and rules; the settled-span cache keys on the resolved style. A few look details stay faithful: composer outlineColor flattens the gradient hairline; code-block borderColor holds through hover unless hoverBorderColor is set; failed user turns keep error treatment regardless of bubble style.

Docs add a Restyling section per component plus a theming overview; changelog notes 0.3.0 (unreleased).

Reviewed by Cursor Bugbot for commit 88b289a. Bugbot is set up for automated code reviews on this repo. Configure here.

@divyanshub024
divyanshub024 merged commit c29d3c9 into main Aug 24, 2026
5 checks passed
@divyanshub024
divyanshub024 deleted the dv/component-styles branch August 24, 2026 10:30

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 88b289a. Configure here.

),
style: typography.labelMediumEmphasised
.copyWith(color: labelForeground)
.merge(style?.labelStyle),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Label style skips disabled ink

Low Severity

labelStyle is merged after the enabled/disabled foreground is applied, so a labelStyle that sets color keeps full-strength ink on disabled FlowPill and FlowSuggestion rows. iconColor / removeColor / foregroundColor correctly run through flowDisabledColor, so disabled pills and suggestions can show a muted icon beside an unmuted label.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 88b289a. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant