Skip to content

Add fill color for closed freehand paths (+ ContextBar close/fill controls) #140

Description

@akshay2211

Description:

Summary

Element.Shape supports an optional fillColor, but Element.Path (freehand
PEN strokes) is stroke-only — there's no way to fill a loop the user has drawn.
Add a fill color for closed paths, mirroring the Shape fill model, and
expose it through the published drawbox-ui ContextBar so it's usable from the UI.

Motivation

Filling a closed freehand region is a common, expected drawing primitive, and the
data/UI plumbing for fills already exists for shapes. Today a user drawing a
closed loop can only outline it.

Design

Two additive, back-compatible fields on Element.Path:

  • closed: Boolean = false — draws the closing segment (last→first) so the loop
    has a continuous outline.
  • fillColor: Color? = null — interior fill, painted only when the path is
    also closed (an open path has no well-defined interior).

closed is an explicit flag (not geometric auto-detection) for determinism,
clean round-trip/SVG (Z) mapping, and collab/LWW friendliness. Closure and
fill stay orthogonal, so a closed-but-unfilled loop is also representable.

Scope

  • Model: Element.Path.closed + Element.Path.fillColor.
  • Renderer: fill pass under the stroke for closed+filled paths; closes both
    the uniform and variable-width stroke geometry.
  • Serialization: threads both fields; legacy JSON loads as open/unfilled.
  • Domain: SetSelectedFillColor now covers paths; new
    SetSelectedPathClosed intent + DrawBoxController.setSelectionPathClosed.
  • drawbox-ui: ContextBarIntent.SetPathClosed, ContextBarState.pathClosed,
    ContextBarSlots.showPath, a pathContextItems builder (open/close toggle +
    fill swatch), and PathClosedIcon.
  • Sample: HomeScreen treats a freehand-path selection as fillable and shows
    the close/fill chips.
  • SVG export: closes (Z) and fills.
  • Docs: FEATURES.md cataloging the full menu surface.

Public API note

The frozen 2.0 surface (DrawBoxController, Mode, Intent, Event, State)
is only extended here (new optional Element.Path fields + new intents), so
it's semver-safe. The drawbox-ui ContextBar additions are likewise additive.

Acceptance criteria

  • A closed Element.Path with a fillColor renders filled + stroked.
  • Open paths, and paths without a fill color, are unchanged.
  • Fill survives JSON round-trip; legacy drawings still load.
  • SetSelectedFillColor + SetSelectedPathClosed fill a selected path.
  • SVG export closes and fills the path.
  • Filling a path is reachable via UI: select loop → Close → Fill.

Flow

Select a freehand loop → tap Close → tap Fill → pick a color → it fills.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions