bootstrap-vue-next
Version:
Seamless integration of Vue 3, Bootstrap 5, and TypeScript for modern, type-safe UI development
441 lines (440 loc) • 15.7 kB
JavaScript
import { h as useFocus, o as onKeyStroke, z as useToNumber } from "./dist-B10a-gZ8.mjs";
import { i as getSafeDocument } from "./dom-AhkaSoh8.mjs";
import { t as useDefaults } from "./useDefaults-BKgBaqOV.mjs";
import { t as useId$1 } from "./useId-BKZFSYm8.mjs";
import { a as CODE_PAGEUP, i as CODE_PAGEDOWN, n as CODE_HOME, s as CODE_UP, t as CODE_DOWN } from "./constants-BSIK14yA.mjs";
import { t as useRtl } from "./useRtl-DpwU_RM8.mjs";
import { computed, createCommentVNode, createElementBlock, createElementVNode, defineComponent, guardReactiveProps, mergeModels, mergeProps, normalizeClass, normalizeProps, onUnmounted, openBlock, renderSlot, toDisplayString, unref, useModel, useTemplateRef } from "vue";
//#region src/components/BFormSpinbutton/BFormSpinbutton.vue?vue&type=script&setup=true&lang.ts
var _hoisted_1 = [
"lang",
"tabindex",
"title"
];
var _hoisted_2 = [
"name",
"form",
"value"
];
var _hoisted_3 = [
"id",
"dir",
"tabindex",
"aria-label",
"aria-invalid",
"aria-required",
"aria-valuemin",
"aria-valuemax",
"aria-valuenow",
"aria-valuetext"
];
var defaultValues = {
min: 1,
max: 100,
step: 1,
repeatDelay: 500,
repeatInterval: 100,
repeatThreshold: 10,
repeatMultiplier: 4
};
//#endregion
//#region src/components/BFormSpinbutton/BFormSpinbutton.vue
var BFormSpinbutton_default = /* @__PURE__ */ defineComponent({
__name: "BFormSpinbutton",
props: /* @__PURE__ */ mergeModels({
ariaControls: { default: void 0 },
ariaLabel: { default: void 0 },
disabled: {
type: Boolean,
default: false
},
form: { default: void 0 },
formatterFn: {
type: Function,
default: void 0
},
id: { default: void 0 },
inline: {
type: Boolean,
default: false
},
labelDecrement: { default: "Decrement" },
labelIncrement: { default: "Increment" },
locale: { default: void 0 },
max: { default: defaultValues.max },
min: { default: defaultValues.min },
name: { default: void 0 },
placeholder: { default: void 0 },
readonly: {
type: Boolean,
default: false
},
repeatDelay: { default: defaultValues.repeatDelay },
repeatInterval: { default: defaultValues.repeatInterval },
repeatStepMultiplier: { default: defaultValues.repeatMultiplier },
repeatThreshold: { default: defaultValues.repeatThreshold },
required: {
type: Boolean,
default: false
},
size: { default: void 0 },
state: {
type: [Boolean, null],
default: null
},
step: { default: defaultValues.step },
vertical: {
type: Boolean,
default: false
},
wrap: {
type: Boolean,
default: false
}
}, {
"modelValue": { default: null },
"modelModifiers": {}
}),
emits: /* @__PURE__ */ mergeModels(["change"], ["update:modelValue"]),
setup(__props, { emit: __emit }) {
const KEY_CODES = [
CODE_UP,
CODE_DOWN,
CODE_HOME,
"End",
CODE_PAGEUP,
CODE_PAGEDOWN
];
const props = useDefaults(__props, "BFormSpinbutton");
const emit = __emit;
const modelValue = useModel(__props, "modelValue");
const element = useTemplateRef("_element");
const { focused } = useFocus(element);
const computedId = useId$1(() => props.id, "spinbutton");
const computedClasses = computed(() => ({
"disabled": props.disabled,
"readonly": props.readonly,
"focus": focused.value,
"d-inline-flex": props.inline || props.vertical,
"d-flex": !props.inline && !props.vertical,
"align-items-stretch": !props.vertical,
"flex-column": props.vertical,
[`form-control-${props.size}`]: props.size !== void 0
}));
const computedSpinClasses = computed(() => ({
"d-flex": props.vertical,
"align-self-center": !props.vertical,
"align-items-center": props.vertical,
"border-top": props.vertical,
"border-bottom": props.vertical,
"border-start": !props.vertical,
"border-end": !props.vertical
}));
let $_autoDelayTimer;
let $_autoRepeatTimer;
let $_keyIsDown = false;
const stepNumber = useToNumber(() => props.step);
const computedStep = computed(() => Number.isNaN(stepNumber.value) ? defaultValues.step : stepNumber.value);
const minNumber = useToNumber(() => props.min);
const computedMin = computed(() => Number.isNaN(minNumber.value) ? defaultValues.min : minNumber.value);
const maxNumber = useToNumber(() => props.max);
const computedMax = computed(() => {
const step = computedStep.value;
const min = computedMin.value;
return Math.floor((maxNumber.value - min) / step) * step + min;
});
const repeatDelayNumber = useToNumber(() => props.repeatDelay, {
nanToZero: true,
method: "parseInt"
});
const computedDelay = computed(() => repeatDelayNumber.value > 0 ? repeatDelayNumber.value : defaultValues.repeatDelay);
const repeatIntervalNumber = useToNumber(() => props.repeatInterval, {
nanToZero: true,
method: "parseInt"
});
const computedInterval = computed(() => repeatIntervalNumber.value > 0 ? repeatIntervalNumber.value : defaultValues.repeatInterval);
const repeatThresholdNumber = useToNumber(() => props.repeatThreshold, {
nanToZero: true,
method: "parseInt"
});
const computedThreshold = computed(() => Math.max(Number.isNaN(repeatThresholdNumber.value) ? defaultValues.repeatThreshold : repeatThresholdNumber.value, 1));
const repeatStepMultiplierNumber = useToNumber(() => props.repeatStepMultiplier, {
nanToZero: true,
method: "parseInt"
});
const computedStepMultiplier = computed(() => Math.max(Number.isNaN(repeatStepMultiplierNumber.value) ? defaultValues.repeatMultiplier : repeatStepMultiplierNumber.value, 1));
const computedPrecision = computed(() => {
const step = computedStep.value;
return Math.floor(step) === step ? 0 : (step.toString().split(".")[1] || "").length;
});
const computedMultiplier = computed(() => Math.pow(10, computedPrecision.value || 0));
const valueAsFixed = computed(() => modelValue.value === null ? "" : modelValue.value.toFixed(computedPrecision.value));
const { isRtl, locale: globalLocale } = useRtl();
const computedLocale = computed(() => {
const locales = [(props.locale ?? globalLocale?.value) || "locale"];
return new Intl.NumberFormat(locales).resolvedOptions().locale;
});
const defaultFormatter = () => new Intl.NumberFormat(computedLocale.value, {
style: "decimal",
useGrouping: false,
minimumIntegerDigits: 1,
minimumFractionDigits: computedPrecision.value,
maximumFractionDigits: computedPrecision.value,
notation: "standard"
}).format;
const computedFormatter = computed(() => props.formatterFn ?? defaultFormatter());
const stepValue = (direction) => {
let { value } = modelValue;
if (!props.disabled && value !== null) {
const step = computedStep.value * direction;
const min = computedMin.value;
const max = computedMax.value;
const multiplier = computedMultiplier.value;
const { wrap } = props;
value = Math.round((value - min) / step) * step + min + step;
value = Math.round(value * multiplier) / multiplier;
modelValue.value = value > max ? wrap ? min : max : value < min ? wrap ? max : min : value;
}
};
const stepUp = (multiplier = 1) => {
if (modelValue.value === null) {
modelValue.value = computedMin.value;
return;
}
stepValue(1 * multiplier);
};
const stepDown = (multiplier = 1) => {
if (modelValue.value === null) {
modelValue.value = props.wrap ? computedMax.value : computedMin.value;
return;
}
stepValue(-1 * multiplier);
};
const stopEvent = (event) => {
event.preventDefault();
event.stopImmediatePropagation();
};
onKeyStroke(KEY_CODES, (event) => {
const { code, altKey, ctrlKey, metaKey } = event;
if (props.disabled || props.readonly || altKey || ctrlKey || metaKey) return;
stopEvent(event);
if ($_keyIsDown) return;
resetTimers();
if (["ArrowUp", "ArrowDown"].includes(code)) {
$_keyIsDown = true;
if (code === "ArrowUp") {
handleStepRepeat(event, stepUp);
return;
}
if (code === "ArrowDown") handleStepRepeat(event, stepDown);
return;
}
if (code === "PageUp") {
stepUp(computedStepMultiplier.value);
return;
}
if (code === "PageDown") {
stepDown(computedStepMultiplier.value);
return;
}
if (code === "Home") {
modelValue.value = computedMin.value;
return;
}
if (code === "End") modelValue.value = computedMax.value;
}, {
target: element,
eventName: "keydown"
});
onKeyStroke(KEY_CODES, (event) => {
const { altKey, ctrlKey, metaKey } = event;
if (props.disabled || props.readonly || altKey || ctrlKey || metaKey) return;
stopEvent(event);
resetTimers();
$_keyIsDown = false;
emit("change", modelValue.value);
}, {
target: element,
eventName: "keyup"
});
const handleStepRepeat = (event, stepper) => {
const { type } = event || {};
if (!props.disabled && !props.readonly) {
if (isMouseEvent(event)) {
if (type === "mousedown" && event.button) return;
}
resetTimers();
stepper(1);
const threshold = computedThreshold.value;
const multiplier = computedStepMultiplier.value;
const delay = computedDelay.value;
const interval = computedInterval.value;
$_autoDelayTimer = setTimeout(() => {
let count = 0;
$_autoRepeatTimer = setInterval(() => {
stepper(count < threshold ? 1 : multiplier);
count++;
}, interval);
}, delay);
}
};
const isMouseEvent = (evt) => evt.type === "mouseup" || evt.type === "mousedown";
const onMouseup = (event) => {
if (isMouseEvent(event)) {
if (event.type === "mouseup" && event.button) return;
}
stopEvent(event);
resetTimers();
setMouseup("removeEventListener");
emit("change", modelValue.value);
};
const setMouseup = (operation) => {
const doc = getSafeDocument();
if (doc === null) return;
if (operation === "addEventListener") {
doc.body.addEventListener("mouseup", onMouseup);
doc.body.addEventListener("touchend", onMouseup, { passive: false });
} else {
doc.body.removeEventListener("mouseup", onMouseup);
doc.body.removeEventListener("touchend", onMouseup);
}
};
const resetTimers = () => {
clearTimeout($_autoDelayTimer);
clearInterval($_autoRepeatTimer);
$_autoDelayTimer = void 0;
$_autoRepeatTimer = void 0;
};
const buttons = computed(() => {
const incrementSvgAttrs = {
svg: {
xmlns: "http://www.w3.org/2000/svg",
width: "16",
height: "16",
fill: "currentColor",
class: "bi bi-plus",
viewBox: "0 0 16 16"
},
path: { d: "M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z" }
};
const decrementSvgAttrs = {
svg: {
xmlns: "http://www.w3.org/2000/svg",
width: "16",
height: "16",
fill: "currentColor",
class: "bi bi-dash",
viewBox: "0 0 16 16"
},
path: { d: "M4 8a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7A.5.5 0 0 1 4 8z" }
};
const sharedButtonAttrs = {
"class": [
{ "py-0": !props.vertical },
"btn",
"btn-sm",
"border-0",
"rounded-0"
],
"tabindex": "-1",
"type": "button",
"disabled": props.disabled || props.readonly,
"aria-disabled": props.disabled || props.readonly ? true : void 0,
"aria-controls": computedId.value
};
const sharedSvgAttrs = {
"aria-hidden": true,
"scale": focused.value ? 1.5 : 1.25
};
const handler = (event, stepper) => {
if (!props.disabled && !props.readonly) {
stopEvent(event);
setMouseup("addEventListener");
focused.value = true;
handleStepRepeat(event, stepper);
}
};
const incrementAttrs = {
button: {
...sharedButtonAttrs,
"aria-label": props.labelIncrement || void 0,
"aria-keyshortcuts": "ArrowUp"
},
svg: {
...sharedSvgAttrs,
...incrementSvgAttrs.svg
},
path: { ...incrementSvgAttrs.path },
slot: { name: "increment" },
handler: (e) => handler(e, stepUp)
};
const decrementAttrs = {
button: {
...sharedButtonAttrs,
"aria-label": props.labelDecrement || void 0,
"aria-keyshortcuts": "ArrowDown"
},
svg: {
...sharedSvgAttrs,
...decrementSvgAttrs.svg
},
path: { ...decrementSvgAttrs.path },
slot: { name: "decrement" },
handler: (e) => handler(e, stepDown)
};
return {
top: { ...props.vertical ? incrementAttrs : decrementAttrs },
bottom: { ...!props.vertical ? incrementAttrs : decrementAttrs }
};
});
onUnmounted(() => {
setMouseup("removeEventListener");
});
return (_ctx, _cache) => {
return openBlock(), createElementBlock("div", {
ref: "_element",
class: normalizeClass(["b-form-spinbutton form-control", computedClasses.value]),
role: "group",
lang: computedLocale.value,
tabindex: unref(props).disabled ? void 0 : "-1",
title: unref(props).ariaLabel,
onClick: _cache[4] || (_cache[4] = ($event) => focused.value = true)
}, [
renderSlot(_ctx.$slots, buttons.value.top.slot.name, { hasFocus: unref(focused) }, () => [createElementVNode("button", mergeProps(buttons.value.top.button, {
onMousedown: _cache[0] || (_cache[0] = (...args) => buttons.value.top.handler && buttons.value.top.handler(...args)),
onTouchstart: _cache[1] || (_cache[1] = (...args) => buttons.value.top.handler && buttons.value.top.handler(...args))
}), [(openBlock(), createElementBlock("svg", normalizeProps(guardReactiveProps(buttons.value.top.svg)), [createElementVNode("path", normalizeProps(guardReactiveProps(buttons.value.top.path)), null, 16)], 16))], 16)]),
unref(props).name && !unref(props).disabled ? (openBlock(), createElementBlock("input", {
key: "hidden",
type: "hidden",
name: unref(props).name,
form: unref(props).form,
value: valueAsFixed.value
}, null, 8, _hoisted_2)) : createCommentVNode("", true),
createElementVNode("output", {
id: unref(computedId),
key: "output",
class: normalizeClass(["flex-grow-1", computedSpinClasses.value]),
dir: unref(isRtl) ?? false ? "rtl" : "ltr",
tabindex: unref(props).disabled ? void 0 : "0",
role: "spinbutton",
"aria-live": "off",
"aria-label": unref(props).ariaLabel || void 0,
"aria-invalid": unref(props).state === false || !modelValue.value !== null && unref(props).required ? true : void 0,
"aria-required": unref(props).required ? true : void 0,
"aria-valuemin": computedMin.value,
"aria-valuemax": computedMax.value,
"aria-valuenow": modelValue.value !== null ? modelValue.value : void 0,
"aria-valuetext": modelValue.value !== null ? computedFormatter.value(modelValue.value) : void 0
}, [createElementVNode("bdi", null, toDisplayString((modelValue.value !== null ? computedFormatter.value(modelValue.value) : unref(props).placeholder) || ""), 1)], 10, _hoisted_3),
renderSlot(_ctx.$slots, buttons.value.bottom.slot.name, { hasFocus: unref(focused) }, () => [createElementVNode("button", mergeProps(buttons.value.bottom.button, {
onMousedown: _cache[2] || (_cache[2] = (...args) => buttons.value.bottom.handler && buttons.value.bottom.handler(...args)),
onTouchstart: _cache[3] || (_cache[3] = (...args) => buttons.value.bottom.handler && buttons.value.bottom.handler(...args))
}), [(openBlock(), createElementBlock("svg", normalizeProps(guardReactiveProps(buttons.value.bottom.svg)), [createElementVNode("path", normalizeProps(guardReactiveProps(buttons.value.bottom.path)), null, 16)], 16))], 16)])
], 10, _hoisted_1);
};
}
});
//#endregion
export { BFormSpinbutton_default as t };
//# sourceMappingURL=BFormSpinbutton-BLO0Yf36.mjs.map