New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

vueless

Package Overview
Dependencies
Maintainers
0
Versions
842
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

vueless - npm Package Compare versions

Comparing version 0.0.766 to 0.0.767

2

package.json
{
"name": "vueless",
"version": "0.0.766",
"version": "0.0.767",
"license": "MIT",

@@ -5,0 +5,0 @@ "description": "Vue Styleless UI Component Library, powered by Tailwind CSS.",

@@ -20,3 +20,3 @@ import defaultConfig from "./config.ts";

*/
modelValue?: number | string;
modelValue?: string;
/**

@@ -23,0 +23,0 @@ * Input label.

@@ -1,2 +0,2 @@

import { onMounted, nextTick, ref, onBeforeUnmount, toValue, watch } from "vue";
import { onMounted, nextTick, ref, onBeforeUnmount, toValue, watch, computed, readonly } from "vue";

@@ -7,7 +7,12 @@ import { getRawValue, getFormattedValue } from "./utilFormat.ts";

const digitSet = ["1", "2", "3", "4", "5", "6", "7", "9", "0"];
const rawDecimalMark = ".";
const comma = ",";
const arrowKeys = ["ArrowUp", "ArrowRight", "ArrowDown", "ArrowLeft"];
const minus = "-";
export default function useFormatCurrency(
elementId: string = "",
options: (() => FormatOptions) | FormatOptions,
formatOptions: (() => FormatOptions) | FormatOptions,
) {
let prevValue = "";
let inputElement: HTMLInputElement | null = null;

@@ -17,6 +22,8 @@

const rawValue = ref("");
const prevValue = ref("");
// update value according to updated options
const options = computed(() => toValue(formatOptions));
watch(
() => toValue(options),
() => options,
() => setValue(formattedValue.value),

@@ -31,3 +38,3 @@ { deep: true },

inputElement.addEventListener("input", onInput);
onInput(formattedValue.value as unknown as InputEvent);
inputElement.addEventListener("keydown", onKeydown);
}

@@ -42,59 +49,194 @@ });

// Use to set input value manually
function setValue(value: string | number) {
const localFormattedValue = getFormattedValue(value, toValue(options));
/**
* Set input value manually.
* @param {Intl.StringNumericLiteral} value
* @returns {void}
*/
function setValue(value: string) {
const newFormattedValue = getFormattedValue(value, options.value);
formattedValue.value = localFormattedValue;
rawValue.value = getRawValue(localFormattedValue, toValue(options));
formattedValue.value = newFormattedValue;
rawValue.value = getRawValue(newFormattedValue, options.value);
prevValue = formattedValue.value;
prevValue.value = formattedValue.value;
}
function onKeydown(event: KeyboardEvent) {
if (!event.target || !inputElement) return;
const cursorStart = inputElement.selectionStart || 0;
const cursorEnd = inputElement.selectionEnd || 0;
const isEndOfValue = cursorEnd === formattedValue.value.length;
const isKeyCombination = event.ctrlKey || event.shiftKey || event.metaKey || event.altKey;
const isSelection = cursorEnd !== cursorStart;
if (event.key === "Backspace" && !isSelection) {
const charToRemove = inputElement.value[cursorStart - 1];
const isFormatChar = [
options.value.thousandsSeparator,
options.value.prefix,
options.value.decimalSeparator,
].includes(charToRemove);
// Skip unremovable character and put cursor one step back.
if (isFormatChar && !inputElement.value.endsWith(options.value.decimalSeparator)) {
event.preventDefault();
inputElement.setSelectionRange(cursorStart - 1, cursorEnd - 1);
}
return;
}
const endsWithDecimal = formattedValue.value.endsWith(options.value.decimalSeparator);
const includesDecimalMark =
formattedValue.value.includes(options.value.decimalSeparator) && !endsWithDecimal;
const isCharKey = !arrowKeys.includes(event.key) && !isKeyCombination;
if ((event.key === comma || event.key === rawDecimalMark) && endsWithDecimal) {
event.preventDefault();
return;
}
if (isEndOfValue && includesDecimalMark && isCharKey && !isSelection) {
const fraction = prevValue.value.split(options.value.decimalSeparator).at(-1) || "";
if (fraction.length >= options.value.maxFractionDigits) {
event.preventDefault();
}
return;
}
}
async function onInput(event: Event) {
if (!event.target) return;
if (!event.target || !inputElement) return;
await nextTick(async () => {
if (!inputElement) return;
await nextTick();
let cursorStart = inputElement.selectionStart;
let cursorEnd = inputElement.selectionEnd;
const cursorStart = inputElement.selectionStart || 0;
const cursorEnd = inputElement.selectionEnd || 0;
const hasValueInputValue = cursorEnd === 1 && cursorStart === 1;
const input = event.target as HTMLInputElement;
const value = input.value || "";
const input = event.target as HTMLInputElement;
const localFormattedValue = getFormattedValue(value, toValue(options));
let value = input.value || "";
const currentValueOffsetLength = localFormattedValue
.split("")
.filter((value: string) => value === toValue(options).thousandsSeparator).length;
const prevCursorPosition = cursorEnd - 1;
const eventData = (event as InputEvent).data || "";
const prevValueOffsetLength = prevValue
.split("")
.filter((value) => value === toValue(options).thousandsSeparator).length;
if (value === minus) {
formattedValue.value = minus;
rawValue.value = minus;
}
const prefixLength = toValue(options).prefix.length;
const offset = currentValueOffsetLength - prevValueOffsetLength;
if (!value || value.startsWith(`${options.value.decimalSeparator}0`)) {
formattedValue.value = options.value.prefix;
rawValue.value = "";
formattedValue.value = localFormattedValue || toValue(options).prefix;
rawValue.value = getRawValue(localFormattedValue, toValue(options));
return;
}
await nextTick(() => {
if (localFormattedValue.length === cursorEnd || !cursorStart || !cursorEnd) return;
// Replace dot with decimal separator
if (eventData === rawDecimalMark || eventData === comma) {
value = [
...prevValue.value.slice(0, prevCursorPosition),
options.value.decimalSeparator,
...prevValue.value.slice(prevCursorPosition),
].join("");
}
if (hasValueInputValue && prefixLength) {
cursorStart += prefixLength;
cursorEnd += prefixLength;
}
if (value.split(options.value.decimalSeparator).length > 2) {
value = value.split("").with(value.lastIndexOf(options.value.decimalSeparator), "").join("");
}
if (inputElement) {
inputElement.setSelectionRange(cursorStart + offset, cursorEnd + offset);
}
});
if (value.endsWith(options.value.decimalSeparator)) {
formattedValue.value = value;
prevValue = formattedValue.value;
});
return;
}
const newRawValue = getRawValue(value, options.value);
const isNumericValue = eventData && digitSet.includes(eventData);
const isMinus = cursorEnd === 1 && cursorStart === 1 && eventData === minus;
const isDoubleMinus = isMinus && prevValue.value.startsWith(minus);
const isMinusWithin = newRawValue.includes(minus) && !newRawValue.startsWith(minus);
const isReservedSymbol = eventData !== rawDecimalMark && eventData !== comma;
if (
(!isNumericValue && isReservedSymbol && !isMinus && eventData.length === 1) ||
isDoubleMinus ||
isMinusWithin
) {
inputElement.value = formattedValue.value;
await nextTick();
inputElement.setSelectionRange(cursorStart, cursorEnd);
return;
}
const newFormattedValue = getFormattedValue(newRawValue, options.value);
if (Number.isNaN(newFormattedValue) || newFormattedValue.includes("NaN")) {
inputElement.value = prevValue.value;
return;
}
formattedValue.value = newFormattedValue;
rawValue.value = getRawValue(newFormattedValue, options.value);
inputElement.value = formattedValue.value;
await setInputCursor(newFormattedValue, inputElement, cursorStart, cursorEnd);
prevValue.value = formattedValue.value;
}
return { rawValue, formattedValue, setValue };
async function setInputCursor(
newValue: string,
inputElement: HTMLInputElement,
prevCursorStart: number | null,
prevCursorEnd: number | null,
) {
const hasValueInputValue = prevCursorStart === 1 && prevCursorEnd === 1;
const currentValueOffsetLength = newValue
.split("")
.filter((value: string) => value === options.value.thousandsSeparator).length;
const prevValueOffsetLength = prevValue.value
.split("")
.filter((value) => value === options.value.thousandsSeparator).length;
const prefixLength = options.value.prefix.length;
const offset = currentValueOffsetLength - prevValueOffsetLength;
await nextTick();
if (offset < 0 && inputElement) {
inputElement.setSelectionRange(prevCursorStart, prevCursorEnd);
return;
}
if (newValue.length === prevCursorEnd || !prevCursorStart || !prevCursorEnd) return;
let newCursorStart = prevCursorStart;
let newCursorEnd = prevCursorEnd;
if (hasValueInputValue && prefixLength) {
newCursorStart += prefixLength;
newCursorEnd += prefixLength;
}
if (inputElement) {
inputElement.setSelectionRange(newCursorStart + offset, newCursorEnd + offset);
}
}
return { rawValue: readonly(rawValue), formattedValue: readonly(formattedValue), setValue };
}
import type { FormatOptions } from "./types.ts";
const isNumberValueRegExp = /^[\d,.\s-]+$/;
const rawDecimalMark = ".";
const minus = "-";
export function getRawValue(value: string | number, options: FormatOptions): string {
export function getRawValue(
value: string,
options: Pick<FormatOptions, "prefix" | "decimalSeparator" | "thousandsSeparator">,
): Intl.StringNumericLiteral {
const { thousandsSeparator, decimalSeparator, prefix } = options;
value = String(value).endsWith(decimalSeparator)
? String(value).replace(decimalSeparator, "")
: String(value);
value = value.endsWith(decimalSeparator) ? value.replace(decimalSeparator, "") : value;
const rawValueWithPrefix = value
.replaceAll(thousandsSeparator, "")
.replaceAll(" ", "")
.replace(decimalSeparator, rawDecimalMark);
return rawValueWithPrefix.replace(prefix, "");
return rawValueWithPrefix.replace(prefix, "") as Intl.StringNumericLiteral;
}
export function getFormattedValue(value: string | number, options: FormatOptions): string {
const {
thousandsSeparator,
decimalSeparator,
minFractionDigits,
maxFractionDigits,
prefix,
positiveOnly,
} = options;
export function getFormattedValue(value: string, options: FormatOptions): string {
const { thousandsSeparator, decimalSeparator, prefix, positiveOnly } = options;
const invalidValuesRegExp = new RegExp("[^\\d,\\d.\\s-" + decimalSeparator + "]", "g");
const doubleValueRegExp = new RegExp("([,\\.\\s\\-" + decimalSeparator + "])+", "g");
const minFractionDigits = Math.abs(options.minFractionDigits);
const maxFractionDigits = Math.abs(options.maxFractionDigits);
const actualMinFractionDigit =
minFractionDigits <= maxFractionDigits ? minFractionDigits : maxFractionDigits;
const isValidMinFractionDigits = minFractionDigits <= maxFractionDigits;
const actualMinFractionDigit = isValidMinFractionDigits ? minFractionDigits : maxFractionDigits;
// slice to first decimal mark
value = String(value)
.replaceAll(rawDecimalMark, decimalSeparator)
.split(decimalSeparator)
.slice(0, 2)
.map((value: string, index: number) =>
index ? value.replaceAll(thousandsSeparator, "") : value,
)
.join(decimalSeparator);
value = String(value)
.replace(invalidValuesRegExp, "")
.replace(doubleValueRegExp, "$1")
.replaceAll(decimalSeparator, rawDecimalMark)
.trim();
const isNumber = isNumberValueRegExp.test(value);
const isFloat = value.endsWith(rawDecimalMark) || value.endsWith(".0");
const isMinus = value === minus;
if (isMinus && positiveOnly) {
value = "";
}
if (value.includes(minus)) {
let isFirstMinus = value.startsWith(minus);
value = value.replaceAll(minus, (match) => {
if (isFirstMinus) {
isFirstMinus = false;
return match;
}
return "";
});
}
if (!value || !isNumber || isFloat || isMinus) {
return `${prefix}${value.replaceAll(rawDecimalMark, decimalSeparator)}`;
}
const intlNumberOptions: Intl.NumberFormatOptions = {

@@ -92,13 +41,4 @@ minimumFractionDigits: actualMinFractionDigit,

const rawValue = getRawValue(value, {
decimalSeparator,
thousandsSeparator,
prefix,
minFractionDigits: 0,
maxFractionDigits: 2,
positiveOnly: false,
});
const formattedValue = intlNumber
.formatToParts((rawValue || 0) as unknown as number)
.formatToParts(value as Intl.StringNumericLiteral)
.map((part) => {

@@ -108,6 +48,2 @@ if (part.type === "group") part.value = thousandsSeparator;

if (part.type === "fraction") {
part.value = part.value.padEnd(maxFractionDigits, "0");
}
return part;

@@ -114,0 +50,0 @@ });

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc