vuetifyjs / vuetify

🐉 Vue Component Framework
https://vuetifyjs.com
MIT License
39.86k stars 6.97k forks source link

[Feature Request] Strict precision for VNumberInput #19898

Open J-Sek opened 5 months ago

J-Sek commented 5 months ago

Problem to solve

In my large web app I have multiple forms with many different use cases for number inputs. When I want user to put a value in USD it should display nicely using expected formatting and enforce up to 2 decimal digits. Having "$" prefix is OK, but actually formatting and enforcing precision is a level-up in terms of UX.

Playground

Proposed solution

Simplified implementation:

// <v-text-field v-model='internalValue' :rules='rules' @blur='onBlur' />

const internalValue = ref('');
const props = defineProps<{
  grouping?: boolean;
  precision?: number | null;
}>();
const enforcePrecision = computed(() => props.precision != null && props.precision > 0 && Number.isInteger(props.precision));

const rules = computed(() => [
  (v: number | null) => !v || !enforcePrecision.value || (String(v).split('.')[1] ?? '').length <= props.precision || `Expected up to ${props.precision} decimal places`,
]);

async function onBlur(event: Event) {
  if (!isEmpty(internalValue)) {
    emit(formatForEmit(internalValue));
  }
);

I think implementation would require additional props for grouping character and decimal separator.

propsFactory({
  groupingSeparator: { type: String, default: ',' },
  decimalSeparator: { type: String, default: '.' },
  // ...
});
function formatForField(v: string) {
  // add grouping separator if props.grouping === true
  // add decimal separator if props.precision > 0 or undefined
  // cut decimal part if props.precision > 0
}
function formatForEmit(v: string) {
  return parseNumber(formatForField(v));
}
function parseNumber(v: string) {
  // remove everything except first occurrence of decimal separator and `-` sign before passing text to `parseFloat`
}

Related to:

J-Sek commented 5 months ago

We could take some inspiration from PrimeVue's InputNumber. However their API binds itself strongly to Intl.NumberFormat`. We could deliver better DX with:

Edit: I will not continue subject of grouping/formatting in this issue in order to keep it focused on precision and hopefully get it done faster.