This is a pre-release. djust 0.9.0 has shipped since: read the djust 0.9.0 release notes.
Changed
WizardMixin.as_live_fieldauto-picksdom_eventby widget class (closes #1156) — previously the view-levelwizard_input_eventattribute applied uniformly to every widget the wizard rendered. An author settingwizard_input_event = "dj-input"to capture unblurred text edits (per #1095) unintentionally also stampeddj-inputon radios, selects, and checkboxes — which was semantically wrong (there's no keystroke stream to fire on) and pre- #1155 incurred a 300ms debounce stall on every click.as_live_fieldnow inspects the field's widget class (walking the widget's MRO so any subclass of an enumerated builtin inherits the default automatically) and picks:dj-changefor click-fired widgets —RadioSelect,CheckboxInput,CheckboxSelectMultiple,Select, plus every Django Select subclass (SelectMultiple,NullBooleanSelect) and any app's RadioSelect/Select subclass matched via MRO. They commit exactly one value per user interaction, no stream to batch.wizard_input_eventfor text-stream widgets (TextInput,Textarea,NumberInput,EmailInput, etc.) — preserves the #1095 contract for authors who need unblurred-text capture.- Caller-passed
dom_event="..."still wins — the widget-aware default is a default, not a mandate.
Apps that had implemented their own
as_live_fieldoverride to do exactly this mapping can delete the override.New
_CLICK_FIRED_WIDGET_CLASSESClassVar (frozenset of widget class names) lets apps with custom commit-style widgets extend the dispatch without overridingas_live_fielditself:class MyWizard(WizardMixin, LiveView): _CLICK_FIRED_WIDGET_CLASSES = frozenset({ *WizardMixin._CLICK_FIRED_WIDGET_CLASSES, "MyColorPickerWidget", })Files:
python/djust/wizard.py(new_default_dom_event_forhelper +_CLICK_FIRED_WIDGET_CLASSESClassVar, ~20 LoC; updatedwizard_input_eventdocstring to clarify text-only scope). 15 new cases inTestAsLiveFieldWidgetAwareDomEventintests/unit/test_wizard_mixin.pycover text/textarea/integer/email trackingwizard_input_event, radio/select/checkbox/ CheckboxSelectMultiple locked todj-change, caller-passeddom_eventoverrides, ClassVar extension for custom widgets, and MRO walk catchingSelectMultiple/NullBooleanSelect/ app-defined RadioSelect subclasses.
Fixed
dj-inputon click-fired widgets no longer incurs a 300ms debounce (closes #1154) —DEFAULT_RATE_LIMITSinpython/djust/static/djust/src/08-event-parsing.jswas missing entries forradio,checkbox,select-one, andselect-multiple. The input handler's fallback ({ type: 'debounce', ms: 300 }) kicked in for these widget types, soWizardMixin.wizard_input_event = "dj-input"— the class-wide setting recommended by #1095 — silently inserted 300ms of dead air between a radio click and the WS event being sent.Fix adds a new
passthroughrate-limit type for click-fired widgets (they commit exactly one value per user interaction, no stream to batch) plus a branch in the input handler in09-event-binding.jsthat skips the rate-limit wrapper whenrateLimit.type === 'passthrough'. Text/textarea fields retain their 300ms debounce unchanged. The defensive 300ms fallback for unknown widget types is intact.Real-world measurement from a wizard with a Yes/No radio and
wizard_input_event = "dj-input":click → WS send total click → DOM Before 1104 ms ~1150 ms After 1 ms ~75 ms dj-debounce/dj-throttleexplicit overrides on a radio still work — passthrough is the default, not a mandate. Files:python/djust/static/djust/src/08-event-parsing.js(4-lineDEFAULT_RATE_LIMITSextension),python/djust/static/djust/src/09-event-binding.js(7-linepassthroughbranch + a one-lineObject.assign({}, …)clone of the default before the override branches mutate it — without the clone,dj-debounce/dj-throttleon one element permanently flips the sharedDEFAULT_RATE_LIMITSentry and pollutes every subsequently- bound element of the same type). 9 new cases intests/js/dj-input-click-widgets.test.jslock in synchronous firing for radio/checkbox/select-one/select-multiple, continued debounce for text/textarea, thatdj-debounceoverrides still apply, and that an override on one radio does not leak into a sibling radio's wrapper (regression for the shared-state mutation).