Freight Quote
Freight Quote
Quote logic mixes predicate requirements, direct field dependencies, mutually exclusive handling branches, admin gating, and promo locks without hand-written orchestration code.
{ isAdmin: false, promoActive: false }{
"conditions": {
"isAdmin": false,
"promoActive": false
},
"values": {
"accountType": "personal",
"serviceLevel": "standard",
"vehicleType": "van",
"handlingMode": "none"
},
"fouls": []
}What this demonstrates
Section titled “What this demonstrates”A freight quoting form with 13 fields and 7 rules spanning 5 of Umpire’s 6 rule types. The form adapts to user input, external conditions, and mutually exclusive handling modes — all without hand-written orchestration code.
Rule types in play
Section titled “Rule types in play”| Rule | What it does here |
|---|---|
requires | Company name only matters for business accounts. Hazmat class requires the hazardous toggle. |
enabledWhen | Admin-only fields (discount override, price hold) gate on the isAdmin condition. Promo locks service level and vehicle type. |
oneOf | Fragile and climate-controlled handling are mutually exclusive branches — picking one hides the other’s fields. |
disables | (not used here — see the Printer Menu for disables in action) |
| conditions | isAdmin and promoActive are external facts, not field values. Toggle them with the switches at the top. |
Things to try
Section titled “Things to try”- Switch account type from Personal to Business — Company Name enables. Switch back and Umpire calls a foul on the stale value with an inline reset button.
- Check “Hazardous materials” — Hazmat Class enables. Uncheck it and the class value produces a foul.
- Change handling mode from Standard to Fragile — blankets and crate type appear. Switch to Climate-controlled — the fragile fields foul, temp/humidity appear. This is
oneOfin action. - Toggle the FREIGHT50 promo — Service Level and Vehicle Type disappear (condition-driven hiding).
- Toggle Admin Mode — Discount Override and Price Hold appear.
Implementation
Section titled “Implementation”This demo uses @umpire/signals with Preact and @preact/signals. Each field component reads signal-backed values during render — Preact auto-subscribes and re-renders only the fields that changed.
The entire Umpire integration is the rule definitions and a ~10-line signal adapter. No useEffect, no state synchronization, no manual subscriptions.
const freightUmp = umpire({ fields, rules: [ requires('companyName', v => v.accountType === 'business'), requires('hazClass', 'hazardous'), oneOf('handlingMode', { fragile: ['blankets', 'crateType'], climate: ['tempRange', 'humidity'], }, { activeBranch: v => v.handlingMode === 'none' ? null : v.handlingMode }), enabledWhen('discountOverride', (_, c) => c.isAdmin), enabledWhen('priceHold', (_, c) => c.isAdmin), enabledWhen('serviceLevel', (_, c) => !c.promoActive), enabledWhen('vehicleType', (_, c) => !c.promoActive), ],})Seven rules. That’s the entire form logic. Umpire handles the cascading availability, the fouls when stale values need cleanup, and the per-field reason messages.