jb-number-input
Version:
number input web component
242 lines (241 loc) • 12.7 kB
JavaScript
import { JBInputWebComponent as e } from "jb-input";
import { enToFaDigits as t, faToEnDigits as r } from "jb-core";
import { JBDictionary as n, i18n as a } from "jb-core/i18n";
function o(e) {
if (null == e || null == e || 0 == e.trim().length) return !1;
{
let t = !isNaN(Number(e));
if (!t) {
const n = r(e);
t = !isNaN(Number(n));
}
return t;
}
}
const s = new n({
fa: {
numberValidation: "مقدار وارد شده میبایست عدد باشد",
increaseValue: "افزایش مقدار",
decreaseValue: "کاهش مقدار"
},
en: {
numberValidation: "Your entered value must be number",
increaseValue: "Increase value",
decreaseValue: "Decrease value"
}
}), u = {
validator: ({ value: e }) => 0 == e.trim().length || o(e),
message: s.get(a, "numberValidation")
};
var i = class n extends e {
#e = {
maxValue: null,
minValue: null,
decimalPrecision: null,
acceptNegative: !0
};
get minValue() {
return this.#e.minValue;
}
set minValue(e) {
if (null == e) return void (this.#e.minValue = null);
const t = Number(e);
Number.isNaN(t) ? console.error("min value is not a valid number") : this.#e.minValue = t;
}
get maxValue() {
return this.#e.maxValue;
}
set maxValue(e) {
if (null == e) return void (this.#e.maxValue = null);
const t = Number(e);
Number.isNaN(t) ? console.error("max value is not a valid number") : this.#e.maxValue = t;
}
get decimalPrecision() {
return this.#e.decimalPrecision;
}
set decimalPrecision(e) {
if (null == e) return void (this.#e.decimalPrecision = null);
const t = Number(e);
Number.isNaN(t) ? console.error("decimalPrecision value is not a valid number") : this.#e.decimalPrecision = t;
}
get acceptNegative() {
return this.#e.acceptNegative;
}
set acceptNegative(e) {
this.#e.acceptNegative = Boolean(e);
}
#t = 1;
get step() {
return this.#t;
}
set step(e) {
null != e ? Number.isNaN(Number(e)) ? console.error("step must be a number") : this.#t = e : this.#t = null;
}
#r = !1;
get showThousandSeparator() {
return this.#r;
}
set showThousandSeparator(e) {
const t = Boolean(e);
t !== this.#r && (this.#r = t, this.value = `${this.value}`);
}
#n = ",";
get thousandSeparator() {
return this.#n;
}
set thousandSeparator(e) {
this.#n !== e && (this.#n = String(e), this.value = `${this.value}`);
}
#a = "arabext" == a.locale.numberingSystem;
get showPersianNumber() {
return this.#a;
}
set showPersianNumber(e) {
this.#a = Boolean(e), this.value = `${this.value}`;
}
#o = "";
get invalidNumberReplacement() {
return this.#o;
}
set invalidNumberReplacement(e) {
this.#o = String(e);
}
#s = !1;
get showControlButton() {
return this.#s;
}
set showControlButton(e) {
e != this.#s && (this.#s = e, !0 === e ? this.#u() : !1 === e && this.#i());
}
constructor() {
super(), this.#l();
}
#b() {
this.elements.input.addEventListener("beforeinput", this.#c.bind(this)), this.addEventListener("keydown", this.#d.bind(this));
}
#l() {
const e = document.createElement("template");
e.innerHTML = "<style>.jb-input-web-component{--jb-input-input-direction:var(--input-direction)}.jb-input-web-component .number-control-wrapper .number-control-buttons{cursor:pointer;height:100%;display:flex}.jb-input-web-component .number-control-wrapper .number-control-buttons .number-control-button{all:unset;box-sizing:border-box;cursor:pointer;width:var(--button-width);text-align:center;height:100%}.jb-input-web-component .number-control-wrapper .number-control-buttons .number-control-button:disabled{cursor:default}.jb-input-web-component .number-control-wrapper .number-control-buttons .number-control-button:focus-visible{outline:2px solid var(--jb-number-input-focus-ring-color,Highlight);outline-offset:2px}.jb-input-web-component .number-control-wrapper .number-control-buttons .increase-number-button{background:var(--increase-button-bg);border:var(--increase-button-border);border-radius:var(--increase-button-border-radius);box-sizing:border-box}.jb-input-web-component .number-control-wrapper .number-control-buttons .increase-number-button .increase-icon{stroke:var(--increase-button-color);stroke-width:.875rem;width:100%;height:100%;display:block}.jb-input-web-component .number-control-wrapper .number-control-buttons .increase-number-button:hover .increase-icon{stroke:var(--increase-button-color-hover)}.jb-input-web-component .number-control-wrapper .number-control-buttons .decrease-number-button{border:var(--decrease-button-border);border-radius:var(--decrease-button-border-radius);background:var(--decrease-button-bg);box-sizing:border-box}.jb-input-web-component .number-control-wrapper .number-control-buttons .decrease-number-button .decrease-icon{stroke:var(--decrease-button-color);stroke-width:.875rem;width:100%;height:100%;display:block}.jb-input-web-component .number-control-wrapper .number-control-buttons .decrease-number-button:hover .decrease-icon{stroke:var(--decrease-button-color-hover)} :host{--button-width:var(--jb-number-input-button-width,2.25rem);--increase-button-border-radius:var(--jb-number-input-increase-button-border-radius,0);--decrease-button-border-radius:var(--jb-number-input-decrease-button-border-radius,0);--increase-button-color:var(--jb-number-input-increase-button-color,var(--jb-neutral-7));--increase-button-color-hover:var(--jb-number-input-increase-button-color-hover,oklch(from var(--jb-green) calc(l + .07) calc(c + .07) h));--decrease-button-color:var(--jb-number-input-decrease-button-color,var(--jb-neutral-7));--decrease-button-color-hover:var(--jb-number-input-decrease-button-color-hover,oklch(from var(--jb-red) calc(l + .07) calc(c + .07) h));--increase-button-bg:var(--jb-number-input-increase-button-bg,transparent);--decrease-button-bg:var(--jb-number-input-decrease-button-bg,transparent);--input-direction:var(--jb-number-input-input-direction,ltr);--increase-button-border:var(--jb-number-input-increase-button-border,none);--decrease-button-border:var(--jb-number-input-decrease-button-border,none)}</style>", this.shadowRoot?.appendChild(e.content.cloneNode(!0)), this.validation.addValidationListGetter(this.#m.bind(this)), this.elements.input.inputMode = "numeric", this.numberInputElements = { controlButtons: null }, this.#b(), this.addStandardValueCallback(this.#h.bind(this));
}
static get numberInputObservedAttributes() {
return [
"thousand-separator",
"step",
"show-persian-number",
"min",
"max",
"decimal-precision",
"accept-negative",
"show-control-button"
];
}
static get observedAttributes() {
return [...e.observedAttributes, ...n.numberInputObservedAttributes];
}
attributeChangedCallback(e, t, r) {
[...n.numberInputObservedAttributes, "type"].includes(e) ? this.#p(e, r) : (this.onAttributeChange(e, r), "disabled" === e && this.numberInputElements?.controlButtons?.querySelectorAll("button").forEach((e) => {
e.disabled = this.disabled;
}));
}
#h(e, n, a, o) {
return function(e, n, a, o) {
if ("-" == e && 1 == n.acceptNegative) return {
displayValue: e,
value: "-0"
};
let s = e;
a.useThousandSeparator && (s = s.replace(new RegExp(`${a.thousandSeparator}`, "g"), ""));
const u = "-" == s[0];
s = r(s).replace(/[^0-9.]/g, ""), u && n.acceptNegative && (s = "-" + s);
let i = Number(s);
isNaN(i) && (s = s.replace(/\u06F0/g, "0").replace(/\u06F1/g, "1").replace(/\u06F2/g, "2").replace(/\u06F3/g, "3").replace(/\u06F4/g, "4").replace(/\u06F5/g, "5").replace(/\u06F6/g, "6").replace(/\u06F7/g, "7").replace(/\u06F8/g, "8").replace(/\u06F9/g, "9"), i = parseFloat(s), isNaN(i) && (s = a.invalidNumberReplacement)), "INPUT" !== o && 0 !== s.length && (null !== n.maxValue && void 0 !== n.maxValue && i > n.maxValue && (i = n.maxValue, s = `${n.maxValue}`), null !== n.minValue && void 0 !== n.minValue && i < n.minValue && (i = n.minValue, s = `${n.minValue}`)), "INPUT" !== o && s.endsWith(".") && (s = s.substring(0, s.length - 1));
const [l, b] = s.split("."), c = b ? b.length : 0;
if (n && null !== n.decimalPrecision && null != n.decimalPrecision && c && c > n.decimalPrecision) {
const e = new RegExp(`^-?\\d+(?:\\.\\d{0,${n.decimalPrecision}})?`), t = s.match(e);
t && t[0] && (s = t[0]);
}
l.startsWith("0") && l.length > 1 && (s = s.substring(1)), l.startsWith("-") && "0" == l.charAt(1) && l.length > 2 && (s = "-" + s.substring(2)), "INPUT" !== o && b && b.endsWith("0") && (s = s.replace(/(\.\d*?[1-9])0+|\.0+$/, "$1"));
const d = {
displayValue: s,
value: s
};
return a.useThousandSeparator && (d.displayValue = s.replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, a.thousandSeparator)), a.showPersianNumber && (d.displayValue = t(d.displayValue)), d;
}(e, this.#e, {
invalidNumberReplacement: this.#o,
thousandSeparator: this.#n,
useThousandSeparator: this.showThousandSeparator,
showPersianNumber: this.#a
}, o);
}
#p(e, t) {
switch (e) {
case "thousand-separator":
"" == t || "true" == t || "false" == t ? this.showThousandSeparator = "" == t || "true" === t : (this.#r = !0, this.#n = t);
break;
case "step":
this.step = Number(t);
break;
case "show-persian-number":
this.showPersianNumber = "" == t || "true" === t;
break;
case "min":
this.minValue = t;
break;
case "max":
this.maxValue = t;
break;
case "decimal-precision":
this.decimalPrecision = t;
break;
case "accept-negative":
"" != t && "true" != t && "false" != t || (this.acceptNegative = "" == t || "true" === t);
break;
case "show-control-button": "" != t && "true" != t && "false" != t || (this.showControlButton = "" == t || "true" === t);
}
}
#m() {
return [u];
}
#v() {
const e = new Event("change", { cancelable: !1 });
this.dispatchEvent(e);
}
#g(e, t) {
const r = `${e}`.split(".")[1], n = `${t}`.split(".")[1], a = r ? Math.pow(10, r.length + 1) : 1, o = n ? Math.pow(10, n.length + 1) : 1, s = Math.max(a, o);
return (e * s + t * s) / s;
}
increaseNumber(e = !1) {
const t = Number(this.value);
if (Number.isNaN(t)) return;
const r = this.#t ?? 1, n = this.#g(t, r);
this.value = `${n}`, this.validation.checkValidity({ showError: !0 }), e && this.#v();
}
decreaseNumber(e = !1) {
const t = parseFloat(this.value);
if (Number.isNaN(t)) return;
const r = this.#t ?? 1;
let n = this.#g(t, -1 * r);
n < 0 && !this.#e?.acceptNegative && (n = 0), this.value = `${n}`, this.validation.checkValidity({ showError: !0 }), e && this.#v();
}
#u() {
const e = document.createElement("div");
e.classList.add("number-control-wrapper"), e.innerHTML = `\n <div class="number-control-buttons">\n <button class="increase-number-button number-control-button" type="button" aria-label="${s.get(a, "increaseValue")}">\n <svg class="increase-icon" viewBox="0 0 120 120" aria-hidden="true">\n <path stroke-linecap="round" d="M60,40 L60,80"></path>\n <path stroke-linecap="round" d="M40,60 L80,60"></path>\n </svg>\n </button>\n <button class="decrease-number-button number-control-button" type="button" aria-label="${s.get(a, "decreaseValue")}">\n <svg class="decrease-icon" viewBox="0 0 120 120" aria-hidden="true">\n <path stroke-linecap="round" d="M40,60 L80,60"></path>\n </svg>\n </button>\n </div>\n `, e.querySelectorAll("button").forEach((e) => {
e.disabled = this.disabled;
}), e.querySelector(".increase-number-button").addEventListener("click", this.increaseNumber.bind(this, !0)), e.querySelector(".decrease-number-button").addEventListener("click", this.decreaseNumber.bind(this, !0)), this.elements.slots.endSection.appendChild(e), this.numberInputElements.controlButtons = e;
}
#i() {
this.numberInputElements.controlButtons && this.numberInputElements.controlButtons.remove();
}
#d(e) {
const t = e.key;
"ArrowUp" == t && (this.increaseNumber(!0), e.preventDefault()), "ArrowDown" == t && (this.decreaseNumber(!0), e.preventDefault());
}
#c(e) {
const t = e.target.selectionEnd || 0, r = e.target.selectionStart || 0;
let n = !1;
"deleteContentBackward" === e.inputType || o(e.data) || (n = !0, "." != e.data || 0 === this.#e.decimalPrecision || -1 != this.value.indexOf(".") || 0 == t || 0 == r || null !== this.#e.decimalPrecision && this.value.substring(t).length > this.#e.decimalPrecision || (n = !1), this.#e.acceptNegative && "-" == e.data?.[0] && 0 == r && (n = !1)), n && e.preventDefault();
}
};
customElements.get("jb-number-input") || window.customElements.define("jb-number-input", i);
export { i as JBNumberInputWebComponent };
//# sourceMappingURL=jb-number-input.js.map