drawkit 0.1.1
drawkit: ^0.1.1 copied to clipboard
Animated hand-drawn UI for Flutter: real widgets on top, seeded pen strokes behind, one shared boil clock — the Dart port of drawably with zero dependencies beyond the Flutter SDK.
0.1.1 #
- The gallery demo is live at https://sandkshnbh.github.io/drawkit/, deployed by a new GitHub Pages workflow on every push, and the README links it from the intro and the gallery section.
0.1.0 #
-
Arabic gallery — the sample flips to Arabic when its RTL toggle is on.
example/lib/l10n.dartholds thedemoArabicswitch that the gallery build keeps in sync with the direction, atr(en, ar)picker that works without a context, a noun table for the sample keys that double as labels (so the keys stay stable while the display localizes), and month/weekday lists that the date pickers accept. Every string on the twelve gallery pages, the sidebar chrome, and the sample's own status lines routes through it, and the example tests prove the Arabic sidebar plus a sweep that keeps English out of the Arabic copy. -
Audit fixes (P2) — the polish half of the AUDIT.md sweep. The core is stricter and steadier: the focus ring clamps its radius to half the shortest side and rejects negative insets,
DrawkitStyle.copyWithlearnedclearWidth,drawkitContrastcomposites translucent colors before measuring,RoughOptions.copyWithcovers every field includingboilSeed/clearBoilSeed, andDrawkitSurfacerebuilds its boil schedule when its theme changes, caches its painter until an input moves, and treatsseed: nullas a fresh sketch (so doesDrawkitList); the anchored arrow polls for its target, then settles after stable frames. Controls self-correct: button presses stay centered, checkbox and radio honor reduced motion, the select detects a placeholder by value rather than label, the rating asserts a positive count and clamps non-negative width, progress bars fall back to a readable width when unconstrained, the skeleton's sweep mirrors in RTL, and the nav badge clamps to 99 and drops out of announcements when empty; the app bar forcesTextDecoration.none, the avatar clamps its overlap, the table pads short rows, and the figure announces its caption with arefreshLabelhook on refresh. Overlays tightened: the panel gains a pressed wash, the date picker re-clamps when its bounds or value change, menu dividers are real ink on the boil clock, and neither menus, selects, nor FAB menus steal focus from a pushed route; the dialog scrolls tall content and its show function now threadsmaxWidth/paddingthrough (they were ignored). Tests got a sharedtest/harness.dart(one host, route host, a11y host, disposal smoke), the feedback suite split into dialog, toast, and progress files, the accordion suite moved out of the menu file, the JS fixture path survives any working directory, and the pixel and size assertions read the real laid-out geometry. 278 tests. -
Audit fixes (P1) — the parity and polish half of the AUDIT.md sweep. Semantics grew roles wherever the engine can hear them:
tab/tabBaron the segments and tabs,table/row/cell/columnHeaderon the table, and a strictly gatedprogressBar(value plus min/max) on the determinate bar. The command palette reworked:DrawkitCommandcarriesleading,group, andenabled; groups draw headers, disabled rows are skipped by the roving highlight and refused on Enter, the list scroll-reveals the highlight, a repeated invoke no longer pops twice, andshowDrawkitCommandPalettegainedfilterCallbackandinitialSelection.DrawkitDialogstopped double-announcing (route semantics are opt-in viarouteSemantics/semanticLabel), paints its scrim from the resolved palette, andshowDrawkitDialoggrewbarrierLabel,requestFocus,useRootNavigator,routeSettings,transitionDuration,anchorPoint, andfullscreenDialog.DrawkitSheetis a stateful draggable now — the handle follows the finger on a widened strip, a fling or a 30% drag dismisses, otherwise it settles back — meets the dialog's parity set plusenableDrag,isScrollControlled, andmaxHeightFactor, and yields to the keyboard viaviewInsets. The date picker gainedselectableDayPredicate,onDisplayedMonthChanged,headerText/footerText, and a typedDrawkitDatePickerMode.inputentry with date parsing and announced errors, all threaded through its show function.DrawkitHighlightskips its repaint boundary so blend modes multiply through the real backdrop,DrawkitButtonannounced-loading text is overridable, the toasts exposeplainLinger/actionLinger, and the sketch-in, stagger, and shake animations retune live from their widgets instead of latching, while reduced motion short-circuits every one of them. The engine stays total:ellipsePointsandvariantssurvive non-positive counts. Tests hardened to prove the fixes: the gallery guidelines now walk RTL and dark pages at a 1.2 text scaler and smoke the dialog and toast under reduced motion, the example exercises sidebar selection and the RTL/dark toggles, a pixel test proves boil frames genuinely repaint, the palette and nav keyboard suites pin roving focus and disabled skipping, andtest/audit_fixes_test.dartcovers the badge clamp, popover mirroring and flipping, grab-handle gesture math, dialog focus restoration, the date picker predicate and typed entry, and reduced-motion standstills. 278 tests. -
Audit fixes (P0) — the correctness half of the AUDIT.md sweep. Overlaid routes were mounting outside the kit's scope: the dialog, sheet, toast, and command palette now wrap their
pageBuilderin aDrawkitThemeplus a route-levelDefaultTextStyle(drawkitRouteTextStyle) that carries the readable ink, andshowDrawkitDialoggrewmaxWidth/padding(the command palette dropped its second, nested copy of the frame). The date picker's month paging walks the keyboard cursor into the target month (day clamped), the menu tracks its anchor from the controller's info and scrolls long item lists instead of overflowing, the rating's taps and paint mirror together under RTL, the segmented focus ring lands on the visual first/last segment, and the floating bar, when hidden, ignores pointers, focus, and semantics.DrawkitNavBar's badge stays a circle at any label length and its height scales with the text scaler,DrawkitInputhands focus back when it turns read-only, the breadcrumb's whole tap target is live, the FAB label inks with the pen, andDrawkitSliderasserts sane bounds. The disabled-mid-press reset defers a frame so sibling buttons rebuild safely;DrawkitStaggerrecomputes its schedule when the child count or duration changes; the refresh indicator swallowsonRefresherrors; the marquee no longer announces its clone; the doodle clamps its stroke width; table and decoration surfaces survive unbounded intrinsics; and the engine guards emptysmooth, degenerateroughEllipse, and zero-stepsampleLine. Eight tests that could not fail were rewritten into real checks, andtest/audit_fixes_test.dartpins the regressions. 262 tests. -
Gallery reorganization — the demo app is grouped by function now (Foundations, Actions, Forms, Navigation, Overlays, Feedback, Display) with uppercase section headers in the sidebar, and every page collects its whole family: Buttons absorbs the icon-button, fab, and fab-menu demos, Fields gains the search field, Choices gains chips and segments, Select & Dates gains the date picker, the new Values page holds the slider, stepper, and rating, Navigation absorbs the floating-capsule demos and gains the pager, the new Tabs & Steps page takes tabs and steps, Menus & Popovers gains the tooltip, the new Dialogs & Sheets page takes the modals, sheets, and toasts, Feedback & States absorbs validation, the empty state, undo, and pull-to-refresh, and Cards & Tables / Type & Ink / Pictures & Extras round out the display set. 17 gallery pages; no library changes.
-
Floating navigation —
DrawkitFloatingNavBarfloats a paper capsule above the content (directional margin + bottom safe area) with the picked destination wearing a soft ink blob. Two label moods:showLabels: truekeeps every label beside its glyph,falselets only the pick open into a label (flexible,AnimatedSize).hideOnScrollplus aScrollControllertuck the bar below the fold while the list moves down and slide it back on the first upward flick (reduced motion snaps).DrawkitNavDestinationgrew abadgecount — a small error-ink disc on the icon's corner, folded into the announced label ("Inbox, 3 notifications") and drawn by the newDrawkitNavBadgein the floating bar, the rail, and the bottom bar alike.DrawkitFabMenuis the speed-dial sibling ofDrawkitFab: labelled pills unfold above the circle (nearest action leads the stagger), the face turns 45°, Escape and outside taps fold it back, and focus walks from the top pill into the trigger. The gallery shipped the floating demos (both label moods, a scroll-aware list, and the speed dial). 249 tests. -
Internal cleanup — the keyboard intents the focusable controls share moved into
src/core/intents.dart(one definition instead of fifteen private copies per widget), the popup panels (DrawkitMenu,DrawkitPopover,DrawkitSelect) share their positioner, check painter, and row widget throughsrc/widgets/drawkit_panel.dart,drawkitReduceMotionlives incore/motion.dart(wasstyle.dart), andDrawkitTonelives incore/style.dart(wasdrawkit_button.dart). No API or pixel changes. -
Themes & Dark Mode —
DrawkitPaletteis a value type with two presets now:DrawkitPalette.light(the CSS values, untouched) andDrawkitPalette.dark(night paper#1D1E21, indigo pen#8B88FF).DrawkitStylecarries apalettefield and every widget resolves ink, tone, paper, and chrome through it, soDrawkitTheme(data: DrawkitPalette.dark.style, child: …)re-inks the whole kit — text, strokes, popovers, dialogs, the command palette.drawkitReadableInkis direction-aware: it darkens toward black on light backgrounds and lightens toward white on dark ones (default background: the light paper). The gallery gained an "Ink · Palette" page (both papers side by side with live contrast ratios), the sidebar grew a dark toggle,test/dark_test.dartlocks the presets, the direction rule, and the dark control sample against all four accessibility guidelines, and the gallery audit now runs every page twice — light and dark. Breaking:DrawkitPalette.penand friends are instance fields now —DrawkitPalette.light.penreads the old value. -
Accessibility — every control now answers the accessibility guidelines: a shared
DrawkitTapTarget(drawkitMinTapTarget= 48) wraps the drawings inside their gesture layers, so touch boxes reach 48×48 (iOS 44 included) while the sketch keeps its size;DrawkitButton,DrawkitIconButton,DrawkitFab, checkbox, radio, toggle, chip, segments, tabs, slider, stepper, pager, breadcrumb, nav tiles, menu rows, select rows, popover triggers, accordion headers, and date-picker cells (48px grid) all passandroidTapTargetGuidelineandiOSTapTargetGuideline. Gesture detectors are excluded from semantics and every tappable node carries an explicitonTapplus a label (labeledTapTargetGuidelineclean). Text follows WCAG contrast on the paper: solid buttons now ink their label in the paper color (the drawn fill stays the tone), tone/state buttons pass their label throughdrawkitReadableInk(darkened until 4.5:1 while the stroke keeps the brand tone), placeholders and hints moved frominkFainttoinkMuted, disabled fields announceenabled: false, anddrawkitContrastis exported for checks.test/a11y_test.dartlocks the four guidelines over a broad control sample plus a 2× text-scale pass, andexample/test/a11y_gallery_test.dartaudits every gallery page. -
Focus & Keyboard — one shared ring for every control:
drawkitFocusRingRectanddrawkitFocusRingCircleare exported helpers, and the existing rings (button, icon button, checkbox, radio, toggle, select, slider) all come from them now.DrawkitSlideranswers Home/End (the ends) and PageUp/PageDown (five steps), and horizontal arrows follow the reading direction (RTL included, like Flutter sliders).DrawkitSegmentedButtonandDrawkitTabskeep a roving tab stop — the selection is the only stop, arrows move (and activate) with wrap-around, plus Home/End.DrawkitBreadcrumb,DrawkitNavRail/DrawkitBottomNav,DrawkitChipandDrawkitPageractivate from the keyboard, andDrawkitAccordionheaders answer Up/Down/Home/End.DrawkitMenuandDrawkitSelectwalk rows with arrows (wrapping, skipping disabled rows), answer Home/End, and hand focus back to the trigger or field on close; the command palette gained Home/End.DrawkitDatePickeris a single tab stop: arrows walk days and weeks (RTL aware), PageUp/PageDown page months keeping the day, Home/End jump to the month's edges, Enter picks. Dialog and sheet Escape, Tab trap, and focus return are pinned down by tests. -
States —
DrawkitInput/DrawkitTextareagainederrorandhelper: an error inks the outline and cursor red, replaces the helper below the field, and announces itself through a live region.DrawkitEmpty(faint doodle, header title, quiet message, optional action) for the blank-margin case. Toasts learned actions:DrawkitToastAction(Undo/Retry) underlines a verb in the pill re-inked on hover/focus, keyboard- and tap-activatable; running it closes the toast, action toasts linger 5s by default, and only actionless toasts keep letting taps pass through.DrawkitRefreshpulls to refresh without Material: a rotating arrow doodle follows the drag, hands off to the spinner while the future settles, works with clamping and bouncing physics, and is reduced-motion aware. -
Fixed — text decorations (
DrawkitUnderline,DrawkitHighlight,DrawkitCircle, the quote) no longer swallow a bounded height: the alignment box is shrink-wrapped vertically (heightFactor: 1), so a decoration inside a row or card draws around its line box instead of inflating to the available space (a toast action used to stretch its pill to the full height). -
Content —
DrawkitHeading(three display sizes, optional pen rule),DrawkitAvatar+DrawkitAvatarGroup(drawn discs, overlapping stack with a+noverflow pocket),DrawkitFigure(framed child with a muted plate caption),DrawkitRating(inked stars, tap-to-set / tap-again-to-clear, slider semantics with increase/decrease),DrawkitDoodle(star, squiggle, spiral, burst, arrow — decorative and excluded from semantics) andDrawkitMarquee(seamless ticker flowing start→end, pause on hover, reduced-motion aware). -
Structure —
DrawkitAppBar(leading/title/actions over a paper surface with the heavier shelf rule, announces itself as a header),DrawkitNavRail+DrawkitBottomNav(sharedDrawkitNavDestination; the chosen tile wears a scribble wash and redraws on pick),DrawkitBreadcrumb(pen underlines on tappable crumbs, bold current page, muted separators) andDrawkitTable(flex-weighted columns, bold header rule, faint row rules). Every piece is direction-aware. -
Menus —
DrawkitMenu(dropdown on a real anchor; paper panel with checked/hint rows and ruled dividers),DrawkitPopover(any trigger, any panel; width follows the anchor),DrawkitAccordion(headers on a sketch line,AnimatedSizebodies, single- or multi-open),DrawkitCommandPaletteviashowDrawkitCommandPalette(filter + arrow/enter/escape keys), andDrawkitDatePicker+showDrawkitDatePicker(Monday-first grid, selected ring, today dot, localizable month/weekday names). Panels join the anchor'sTapRegiongroup: an outside tap folds them away, row taps stay intact.DrawkitSelectgained the same outside-tap dismissal. -
Feedback —
showDrawkitDialog/showDrawkitSheet(paper panels over a soft scrim; the modal traces itself in viaDrawkitSketchIn, the sheet slides in from the bottom or the direction-aware end edge, and its grab handle flings closed),showDrawkitToast(tap-through overlay pill with tone ink and auto-dismiss),DrawkitProgressBar(leading-edge fill, sweeping indeterminate band),DrawkitSpinner(dashed ring on one clock), andDrawkitSkeleton+DrawkitSkeleton.circle(faint strokes with a per-line shimmer sweep). All reduced-motion aware. -
Actions —
DrawkitSegmentedButton(rough frame, scribbled wash under the pick),DrawkitSlider(tap/drag/keyboard, division snapping, fill from the leading edge),DrawkitStepper(boundary-aware − / +),DrawkitSearchField(pen magnifier in the leading gutter, × clears and reports''), plusDrawkitIconButtonandDrawkitFabindrawkit_button.dart. All followDirectionalityand reuse the existing surface conventions. -
Motion —
DrawkitSketchIntraces every surface below it on mount (aDrawkitSketchScopecarries the progress; surfaces trim at paint time, no per-tick rebuilds),DrawkitStaggerdraws a list in one clock, a step apart, andDrawkitShake/DrawkitShakeControllerplay the damped "wrong!" wiggle. All three honor reduced motion.drawkitEaseanddrawkitReduceMotionmoved tostyle.dart(same public API). -
RTL — every widget follows the ambient
Directionality: layout uses directional geometry (EdgeInsetsDirectional), and painted anchors flip with it — the select chevron and menu alignment, the list gutter and markers, the toggle's resting side and travel, chip/tabs/pager spacing. LTR output is unchanged, stroke for stroke. -
Fixed —
DrawkitQuote's footer rule drew through the attribution text; it now rules the top of a 10px footer band spanning the quote's width, with the text starting 8px in (thedrawablyDividercontract). The gallery's tooltip and arrow demos mirror in RTL (PositionedDirectional). -
Fixed — text decorations (
DrawkitUnderline,DrawkitHighlight,DrawkitCircle) keep theTextPainter's width, so the strokes stay aligned with the glyphs when the constraint is wider (single-line text shifted in RTL);DrawkitKbdkeeps keycap glyph order LTR inside RTL paragraphs. -
Fixed —
DrawkitArrow(and the tooltip's arrow) drew with stale measurements on the first frames: a repaint alone reused the frames cached for the surface's size, so the arrow only appeared after the next rebuild (any tap). The anchor poll now rebuilds, and arrows show as soon as the anchors land.
0.1.0 #
First release: the complete drawably port.
- Engine —
mulberry32PRNG (bit-exact with the JS reference) and the full rough geometry: sampled lines, ellipses, rounded rects, checkmarks, scribble fills, double strokes, arrows, and thevariantsframe generator. Verified against golden vectors generated from the JS source (test/fixtures/). - Core —
DrawkitSurface(seeded chrome behind any child, one shared boil clock, pre-built frames, trim/matrix accent layers),DrawkitStyle/DrawkitTheme,drawkitStroke/drawkitFillPaint,drawkitReduceMotion. - Controls —
DrawkitButton,DrawkitCheckbox,DrawkitRadio,DrawkitToggle,DrawkitInput,DrawkitTextarea,DrawkitSelect. - Surfaces —
DrawkitDivider,DrawkitCard,DrawkitBadge,DrawkitList. - Text —
DrawkitUnderline,DrawkitHighlight,DrawkitCircle(per-line-box viaTextPainter). - Composites —
DrawkitArrow,DrawkitChip,DrawkitTabs,DrawkitTooltip,DrawkitAlert,DrawkitSteps,DrawkitKbd,DrawkitQuote,DrawkitPager. - Typeface — opt-in
DrawkitPenfamily. - Gallery — a web example app exercising every widget.