draggable_panel 4.1.0 copy "draggable_panel: ^4.1.0" to clipboard
draggable_panel: ^4.1.0 copied to clipboard

A floating panel window — drag it anywhere, spring-snap to the nearest side, stash it off the edge, tap to grow it in place.

4.1.0 #

Features

  • PanelDragArea: marks the part of an expanded panel that drags the window, so a scrollable inside it keeps its own swipes.

Fixes

  • An expanded panel no longer halves the platform touch slop, which had it taking drags meant for a scrollable inside it.

Changed

  • The DraggableActionPanel header stays put while the grid scrolls under it, and doubles as the panel's drag area.
  • With a drag area declared, a tap outside it is left to the content instead of collapsing the panel.

4.0.0 #

A rewrite. The panel is now a floating window: drag it anywhere, release it and it springs to the nearest side by projected velocity, flick it past an edge to park it off-screen, tap it to grow in place into a full panel. Material 3 visuals, spring-based motion throughout.

Breaking changes

  • DraggablePanel now takes collapsedBuilder + expandedBuilder and arbitrary content. The icons-and-buttons shape lives on as the DraggableActionPanel preset. See MIGRATION.md for the full mapping.
  • onPositionChanged(x, y) became onPlacementChanged(PanelPlacement). Stored pixel positions cannot be converted and should be dropped.
  • Every controller method that took a screen size is gone: forceDock, hidePanel, togglePanel, toggleMainButton, relayout and recomputeDockSide were layout math leaking into a state object.
  • Interaction flags moved off the controller onto PanelBehavior, passed to the widget.
  • DraggablePanelTheme became DraggablePanelThemeData, a ThemeExtension with nullable tokens, so a call-site override no longer clobbers an app-wide one. Sub-themes flattened into DraggableActionPanelThemeData.
  • DraggablePanelMotion (durations and curves) became PanelMotionSpec (springs). There is no mechanical mapping — a tween cannot carry entry velocity or be redirected mid-flight. panelSwitchInCurve and panelSwitchOutCurve went with it; neither had any effect in 3.x.
  • Removed: MultiValueListenableBuilder, TooltipSnackBar, DockType, PanelState, and the already-deprecated panelAnimDuration, dockAnimDuration and movementSpeed.
  • The panel must be given the whole window, since that is what it resolves its placement against. A smaller box still paints and still takes its gestures, but reports the mistake once in debug rather than leaving it to be found by eye.
  • Minimum Flutter is now 3.32 (Dart 3.8).

Added

  • Spring physics throughout: velocity projection, a critically damped 400 ms settle, and the iOS rubber band. Motion is interruptible — grabbing a moving panel folds its momentum into the next throw, and reversing an expansion halfway overshoots, turns around and comes back.
  • Grow-in-place expansion anchored at the corner the panel occupies, and a snapPolicy choosing between sides, corners, and free placement.
  • Edge parking: push the panel against a side and it stays there as a grab-able tab, pull it back and it returns. Both are ordinary drags rather than separate gestures, and an open panel closes on its way into the park. A tab moved along to another edge re-parks there instead of opening, so the two settings that drop the collapsed window still let you just put the panel somewhere else.
  • Three resting stages, two of them optional. stashable: false drops the park, collapsible: false drops the small window between tab and panel, and expandOnUnstash: true opens the panel straight out of a park.
  • PanelPlacement — resolution-independent resting positions with JSON round-tripping, so a placement saved on a tablet restores on a phone.
  • PanelBehavior for interaction flags, covering idle parking, tap-outside parking, keyboard avoidance, haptics and the snap policy.
  • Full accessibility: per-corner custom semantics actions, keyboard corner navigation, a dismiss action, screen-reader-aware drag suppression, honoured reduced motion, and PanelSemantics for localizable copy.
  • Committed-moment haptics, independent of the motion preference.
  • DraggablePanelScope for reaching the controller from panel content.
  • A theme token for every visual the panel paints, frosted glass through surfaceFilter, and the springs themselves.
  • The DraggableActionPanel preset — an action grid with captions and badges, a header with a close control, scrolling content, and a builder for every part.

Changed

  • Rotation, resize, split-screen and the keyboard re-place the panel by re-resolving its placement, carrying velocity, instead of teleporting it.

Performance

  • Motion is paint-only and isolated behind its own repaint boundary. A frame of movement costs zero widget builds, zero layouts, and no repaint of the application behind the panel — all three asserted by regression tests.

Fixed

  • Panel content sits inside a transparent Material, so a bare Text in a builder inherits the app's text style instead of rendering as oversized debug type, and an InkWell finds something to ink on.
  • Drag velocity is no longer discarded on release; a flick and a slow drop now differ.
  • Dragging past an edge stretches against a rubber band and springs back, instead of the panel stopping dead against the bound mid-gesture.
  • Theme changes crossfade the panel along with the rest of the app.

3.0.0 #

Major release: open/hide stability, adaptive content-sized layout, and end-to-end customization.

Fixes

  • Deterministic button hide/reveal — no more late or missing hide on open.
  • Resize (keyboard/rotation/split-screen) no longer pulls a hidden button back on-screen.
  • Single-frame open (removed the await between hide and reveal).
  • Off-screen position no longer persisted via position listeners.
  • No crash with an empty items list.

Layout

  • Panel sizes to its content in both axes; panelWidth is now the maximum.
  • Item grid balances columns so the last row isn't half-empty; height caps to free space and scrolls.
  • Panel anchors flush to the button's inner edge.

Customization

  • Motion via DraggablePanelTheme.motion (durations + curves).
  • Behavior flags on the controller: tapToToggle, draggable, closeOnTapOutside.
  • Content builders: itemBuilder, buttonBuilder, handleBuilder.
  • Shell builders: itemFrameBuilder, buttonFrameBuilder.
  • Panel builders: panelBuilder (surface), panelContentBuilder (layout).
  • Custom tooltip via onShowTooltip.
  • Per-item styling on DraggablePanelItem: color, foregroundColor, badgeColor, badgeLabel.
  • New theme tokens: handle drag icon/size, item iconSize, button labelStyle, tooltip text style.

Breaking changes

  • Durations moved to DraggablePanelTheme.motion; controller panelAnimDuration/dockAnimDuration deprecated (no effect).
  • DraggablePanelController.movementSpeed deprecated in favor of animateMovement.
  • DraggablePanelController.toggleMainButton now returns void instead of Future<void>.

2.0.2 #

  • Fixed tooltip text color not adapting to light/dark theme.

2.0.0 #

  • Sub-themes for items, buttons, tooltip, and drag handle.
  • Layout properties: panelWidth, panelContentPadding, itemSpacing, buttonSpacing, sectionSpacing.
  • Material 3 dark theme support with surface-based default colors.
  • Border no longer affects content layout.
  • No breaking changes — existing code works without modifications.

1.4.3 #

Fixes

  • Fixed panel overflow when panelBorder is set: Panel height now accounts for border width when calculating items per row.

1.4.2 #

Major theme refactor and customization improvements.

What's new

  • DraggablePanelTheme: Introduced a comprehensive theme class to centralize all styling properties.
  • Enhanced Customization: You can now customize every aspect of the panel, including button colors, shadows, borders, and more, via the theme property.
  • Simplified API: Removed individual style arguments from DraggablePanel in favor of the theme object, making the API cleaner and more consistent.

Improvements

  • Added widget tests to ensure reliability.
  • Updated documentation with new usage examples.

1.3.1 #

Code quality improvements and enhanced documentation.

What's new

  • Enhanced documentation: comprehensive dartdoc comments with usage examples and parameter descriptions across all public APIs.
  • Improved tooltips: better theme adaptation and modern appearance for item/button tooltips.

Improvements

  • Better code organization and widget decomposition for improved maintainability.
  • Optimized performance with reduced widget rebuilds and better const usage.
  • Enhanced position listener handling with improved lifecycle safety.
  • Stricter code quality with comprehensive lint rules and zero analysis issues.

Migration notes

  • No breaking changes. All existing code works as expected.

1.2.0 #

Desktop/Web resize stability, auto-docking, and controller improvements.

What's new

  • Auto-dock on window resize: the draggable button now snaps to the nearest edge when the window is resized on desktop/web, matching the expected behavior.
  • Stable dock side: introduced isDockedRight in DraggablePanelController to track the docked side explicitly. This prevents side flipping during resizes and ensures consistent alignment when the button is off-screen.
  • Resize handling in widget: DraggablePanel now observes didChangeMetrics and reclamps/repositions without long animations during resize.

Changes

  • DraggablePanelController:
    • Added bool get isDockedRight and internal tracking updated in forceDock().
    • hidePanel(), togglePanel(), and toggleMainButton() now use isDockedRight instead of recomputing side from current left/width.
    • Added recomputeDockSide(pageWidth) helper for future scenarios where side needs recalculation without moving.
  • DraggablePanel:
    • Uses controller.isDockedRight in UI instead of deducing side via left > width/2.
    • On init, initial position is clamped and, if closed, docked and panel hidden off-screen on the correct side.
    • On resize, positions are clamped, side is docked, and open/closed panel positions recalculated accordingly with zero-duration movement during the resize frame.

Fixes

  • Panel and button no longer drift or jump when resizing the window; the open panel stays aligned to its edge, and the closed panel remains fully off-screen on the correct side.
  • Prevented duplicate/misleading side calculations that caused inconsistencies during transitions.

Performance and cleanup

  • Reduced unnecessary rebuilds during resize by batching updates and suppressing long animations for these events.
  • Minor readability improvements (clearer border condition, removal of unused code, better ordering of resize operations).

Migration notes

  • No breaking API changes. If you previously derived side from draggablePositionLeft, consider reading controller.isDockedRight for consistency with the new logic.

1.1.0 #

  • Added: Position change listener API in DraggablePanelController (addPositionListener / removePositionListener).
  • Added: Public dockBoundary getter for consistent boundary logic across widget and controller.
  • Changed: toggle() now respects current panelState (not initialPanelState). Auto-toggle on mount removed to preserve user state. Initial position is clamped and (when starting closed) docked to the nearest edge.
  • Fixed: Panel no longer resets to default after visibility toggles; duplicate position callbacks removed; unified docking logic.
  • Performance: Batched x/y updates during drag via setPosition(x, y); reduced redundant notifications and rebuilds; lifecycle safety (mounted checks) and controller rewire in didUpdateWidget.

1.0.6 #

  • Added tooltip snackbar when long press on the panel buttons and items.
  • Records replaced by DraggablePanelItem and DraggablePanelButton models with description field for tooltips.

1.0.3 #

  • Removed copy method from DraggablePanelController. It was not necessary. Issue was fixed by another way. Please if you use your own DraggablePanelController don't forget to dispose it.

1.0.2 #

  • Added copy method to DraggablePanelController. It fixes the issue when you hide and re-show the panel.

1.0.1 #

  • In this update, I added the DraggablePanelController to give you the ability to control the panel directly outside of this widget. Just create it and pass it to the DraggablePanel widget. See example.

1.0.0 #

  • Changed alignment of Wrap inside DraggablePanel.

0.0.9 #

  • Added new optional param panelHeight. This param is used to set the height of the panel. If not set, the panel will take the height of the child widget based on item's and button's length.

0.0.8 #

  • The panel size calculation has been changed.

0.0.6 #

  • Added web support with essential configuration for PWA functionality.
  • Improved draggable panel logic by introducing better state management and optimizing boundary checks.
  • Fixed issues with initial panel positioning and docking behavior.
  • Simplified and cleaned up redundant code for better maintainability.

0.0.5 #

  • Now child is nullable in DraggablePanel widget. This is useful when you want to use DraggablePanel inside other stack widgets.

0.0.4 #

  • The DraggablePanelItem and DraggablePanelButton models were removed and replaced with Record. This was done to make the package easier to use. If you were using DraggablePanel in a package, you would need to import models for others that use your same package. Now, this is not necessary.

0.0.3 #

  • Initial release.
27
likes
160
points
1.55k
downloads
screenshot

Documentation

API reference

Publisher

verified publishershodev.live

Weekly Downloads

A floating panel window — drag it anywhere, spring-snap to the nearest side, stash it off the edge, tap to grow it in place.

Repository (GitHub)
View/report issues

Topics

#draggable-panel #floating-panel #animation #accessibility

License

MIT (license)

Dependencies

flutter

More

Packages that depend on draggable_panel