NumberStepper
A themed numeric input with +/- nudge buttons, replacing the native <input type="number"> spin buttons. No boxed/bordered control — minimal icon buttons only, consistent with the framework's other borderless inputs (e.g. MealReviewCard's name field, ClarificationPrompt's free-text field).
Playground
Click the chevrons — the value pulses on every nudge. With stepPercent on, the nudge amount is 10% of the value at the time you started clicking (frozen between clicks, so repeated clicks move a consistent distance instead of compounding) rather than a fixed absolute step.
vue
<script setup>
import { NumberStepper } from 'yemek'
</script>
<template>
<NumberStepper
v-model="confirmProtein"
accent-color="var(--yemek-nutrient-protein)"
:min="0"
:max="300"
/>
</template>Props
| Prop | Type | Default | Description |
|---|---|---|---|
modelValue | number | string | null | — | Current value (v-model). |
step | number | 1 | Fixed nudge amount, used when stepPercent is unset. |
stepPercent | number | undefined | Dynamic percent-based stepping — nudge amount is a fraction of a "base" value instead of a fixed step, frozen between nudges so N consecutive clicks move the same total distance rather than compounding, and re-armed whenever the value changes from outside the stepper. |
min | number | undefined | Lower bound — clamped on blur and nudge, not on every keystroke (so typing a value below min digit-by-digit still works). |
max | number | undefined | Upper bound, same clamping behavior as min. |
accentColor | string | undefined | CSS color for the value text (e.g. var(--yemek-nutrient-protein)) — lets each field pick whichever identity fits instead of the kit guessing one. |
placeholder | string | undefined | Placeholder shown when the value is empty. |
Events
| Event | Payload | Fired when |
|---|---|---|
update:modelValue | number | '' | Standard v-model — on typing, blur-clamp, or a nudge. |
Behavior notes
- Bounds-checking (
min/max) is pure numeric validation, not domain logic, so it stays in the component — same precedent asMetricRing's ratio math. Portion/gram scaling, macro clamping to a plausible meal size, etc. all stay the consumer's own domain logic; this only clamps to whatevermin/maxit's given. - Typing is never clamped mid-keystroke — only on blur or a nudge-button click. Clamping every keystroke would make a value below
minunreachable by typing (e.g. typing "1" of "1500" into a field withmin=1000would instantly snap to 1000). - Each nudge pulses the value with a quick scale animation — feedback that the click registered, not a silent number swap.
prefers-reduced-motion: reducedisables the pulse and the button's tap-scale feedback.