Upgrade Guide
Overview
Wind follows Semantic Versioning 2.0.0. Within a major version, upgrades are backward compatible: a project pinned to ^1.0.0 resolves to the latest 1.x automatically, and no public API is removed or renamed across minor releases. This guide lists the per-version changes worth knowing about, newest first. If a section has no "Action required" entry, the upgrade is drop-in.
1.0.x to 1.1.0
A backward-compatible minor release. The headline additions are opt-in, so existing apps compile and render unchanged. One debug-only assertion and a few input behavior changes are worth a quick scan.
New, opt-in
These features do nothing until you use them.
className aliases (WindThemeData.aliases). Map a bare token to a full utility string and Wind expands it (recursively) before parsing, in every widget:
WindTheme(
data: WindThemeData(
aliases: {
'row': 'flex flex-row',
'col': 'flex flex-col',
'center': 'items-center justify-center',
'card': 'p-4 rounded-lg bg-white dark:bg-gray-800',
},
),
child: const MyApp(),
)
// then anywhere:
WDiv(className: 'row center', children: [...])
See Theming: Aliases for the full semantics (bare-token keys, recursion, shadowing, the empty default).
WIcon.foregroundColor. Pass a runtime Color directly instead of interpolating it into a text-[#hex] className, which would bloat the parser cache:
// category.color is a runtime value (for example from the database)
WIcon(Icons.star, foregroundColor: category.color, className: 'text-lg')
It overrides any text-* / dark:text-* from the className and stays out of the parser cache key, matching WText.foregroundColor.
WInput read-only state. readOnly: true now activates a readonly state, so readonly: prefixed classes style a read-only field the way disabled: styles a disabled one:
WInput(
readOnly: true,
value: 'Locked',
className: 'p-3 rounded-lg bg-white dark:bg-gray-800 readonly:bg-gray-100 dark:readonly:bg-gray-700',
)
Behavior changes to review
No code change is required, but the rendered result differs in these cases.
WInputrenders Material-free. It now builds onEditableTextinside a decoratedContainerinstead of a MaterialTextField, so it no longer requires aMaterialAppancestor and works under Cupertino, a custom root, or a bareWidgetsApp. If you relied on ambient MaterialInputDecorationtheming bleeding intoWInput, style it withclassNameinstead.- Selection handles are Cupertino-style on every platform. Previously Material-style on Android and web. The copy / cut / paste menu reads
WidgetsLocalizations, so it works under any ancestor. Behavior is identical; only the handle and toolbar appearance changes on Android and web. InputType.numberrestricts input to a signed decimal on every platform. A default formatter now allows digits, one decimal point, and an optional leading minus, so the field is numeric on web too (where the keyboard type alone enforces nothing). Supply your owninputFormattersto override the default.
Action required
- Do not pass both
valueandcontrollertoWInput. Supplying both was always a logic error (the controller silently won); it now throws anAssertionErrorin debug builds. Pick one: usevalue+onChangedfor React-style binding, or acontrollerfor imperative control.
// Before (silently used the controller, ignored value)
WInput(value: _text, controller: _controller)
// After: choose one
WInput(value: _text, onChanged: (v) => setState(() => _text = v))
// or
WInput(controller: _controller)
Fixes you get for free
No action needed; these land automatically.
- Form widget labels, hints, and errors (
WFormInput,WFormSelect,WFormCheckbox,WFormDatePicker) carrydark:pairs, so they stay legible in dark mode. - A conditional
prefix/suffix(for example a clear button that appears once the field has text) no longer drops focus on the first keystroke, and an appearing suffix no longer changes the field height. - A disabled
WInput(enabled: false) is fully non-interactive again and reportsisEnabled: falseto assistive technology. WInputemits a single cleantextFieldsemantics node instead of the previous double node.