UNPKG

bootstrap-vue-next

Version:

Seamless integration of Vue 3, Bootstrap 5, and TypeScript for modern, type-safe UI development

1,862 lines 66.1 kB
import { S as tableKeyboardNavigationKey } from "./keys-BgLwJbLV.js";
import { S as useToNumber } from "./dist-DKc2ivHS.js";
import { i as getSafeDocument } from "./dom-BdUQrX99.js";
import { t as useDefaults } from "./useDefaults-BzP4qZBu.js";
import { t as useId$1 } from "./useId-Fh-Arhb7.js";
import { a as pick, o as set, t as deepEqual } from "./object-C7YmCGEm.js";
import "./constants-Cap5sNf8.js";
import { n as startCase, r as titleCase } from "./stringUtils-CVySsg3y.js";
import { t as useDebounceFn } from "./debounce-Xj7wsAmR.js";
import { t as BTableSimple_default } from "./BTableSimple-2Z7ssnuG.js";
import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createSlots, createTextVNode, createVNode, defineComponent, getCurrentInstance, guardReactiveProps, inject, mergeModels, mergeProps, normalizeClass, normalizeProps, onMounted, openBlock, provide, readonly, renderList, renderSlot, resolveDynamicComponent, toDisplayString, toRef, toValue, unref, useModel, useSlots, vShow, watch, withCtx, withDirectives } from "vue";
//#region src/types/TableTypes.ts
var isTableItem = (value) => typeof value === "object" && value !== null;
var isTableField = (value) => typeof value === "object" && value !== null && "key" in value;
//#endregion
//#region src/components/BTable/BTbody.vue
var BTbody_default = /* @__PURE__ */ defineComponent({
	__name: "BTbody",
	props: { variant: { default: null } },
	setup(__props) {
		const props = useDefaults(__props, "BTbody");
		const computedClasses = computed(() => ({ [`thead-${props.variant}`]: props.variant !== null }));
		return (_ctx, _cache) => {
			return openBlock(), createElementBlock("tbody", { class: normalizeClass(computedClasses.value) }, [renderSlot(_ctx.$slots, "default")], 2);
		};
	}
});
//#endregion
//#region src/components/BTable/BTd.vue?vue&type=script&setup=true&lang.ts
var _hoisted_1$3 = [
	"colspan",
	"rowspan",
	"data-label"
];
var _hoisted_2$3 = { key: 0 };
//#endregion
//#region src/components/BTable/BTd.vue
var BTd_default = /* @__PURE__ */ defineComponent({
	__name: "BTd",
	props: {
		colspan: { default: void 0 },
		rowspan: { default: void 0 },
		stackedHeading: { default: void 0 },
		stickyColumn: {
			type: Boolean,
			default: false
		},
		variant: { default: null }
	},
	setup(__props) {
		const props = useDefaults(__props, "BTd");
		const computedClasses = computed(() => ({
			[`table-${props.variant}`]: props.variant !== null,
			"b-table-sticky-column": props.stickyColumn,
			"table-b-table-default": props.stickyColumn && props.variant === null
		}));
		return (_ctx, _cache) => {
			return openBlock(), createElementBlock("td", {
				class: normalizeClass(computedClasses.value),
				colspan: unref(props).colspan,
				rowspan: unref(props).rowspan,
				"data-label": unref(props).stackedHeading
			}, [unref(props).stackedHeading ? (openBlock(), createElementBlock("div", _hoisted_2$3, [renderSlot(_ctx.$slots, "default")])) : renderSlot(_ctx.$slots, "default", {}, void 0, void 0, 1)], 10, _hoisted_1$3);
		};
	}
});
//#endregion
//#region src/components/BTable/BTfoot.vue
var BTfoot_default = /* @__PURE__ */ defineComponent({
	__name: "BTfoot",
	props: { variant: { default: null } },
	setup(__props) {
		const props = useDefaults(__props, "BTfoot");
		const computedClasses = computed(() => ({ [`table-${props.variant}`]: props.variant !== null }));
		return (_ctx, _cache) => {
			return openBlock(), createElementBlock("tfoot", { class: normalizeClass(computedClasses.value) }, [renderSlot(_ctx.$slots, "default")], 2);
		};
	}
});
//#endregion
//#region src/components/BTable/BTh.vue?vue&type=script&setup=true&lang.ts
var _hoisted_1$2 = [
	"scope",
	"colspan",
	"rowspan",
	"data-label"
];
var _hoisted_2$2 = { key: 0 };
//#endregion
//#region src/components/BTable/BTh.vue
var BTh_default = /* @__PURE__ */ defineComponent({
	__name: "BTh",
	props: {
		colspan: { default: void 0 },
		rowspan: { default: void 0 },
		stackedHeading: { default: void 0 },
		stickyColumn: {
			type: Boolean,
			default: false
		},
		variant: { default: null },
		scope: { default: void 0 }
	},
	setup(__props) {
		const props = useDefaults(__props, "BTh");
		const computedClasses = computed(() => ({
			[`table-${props.variant}`]: props.variant !== null,
			"b-table-sticky-column": props.stickyColumn,
			"table-b-table-default": props.stickyColumn && props.variant === null
		}));
		const localScope = computed(() => props.scope ? props.scope : props.colspan ? "colgroup" : props.rowspan ? "rowgroup" : "col");
		return (_ctx, _cache) => {
			return openBlock(), createElementBlock("th", {
				scope: localScope.value,
				class: normalizeClass(computedClasses.value),
				colspan: unref(props).colspan,
				rowspan: unref(props).rowspan,
				"data-label": unref(props).stackedHeading
			}, [unref(props).stackedHeading !== void 0 ? (openBlock(), createElementBlock("div", _hoisted_2$2, [renderSlot(_ctx.$slots, "default")])) : renderSlot(_ctx.$slots, "default", {}, void 0, void 0, 1)], 10, _hoisted_1$2);
		};
	}
});
//#endregion
//#region src/components/BTable/BThead.vue
var BThead_default = /* @__PURE__ */ defineComponent({
	__name: "BThead",
	props: { variant: { default: null } },
	setup(__props) {
		const props = useDefaults(__props, "BThead");
		const computedClasses = computed(() => ({ [`table-${props.variant}`]: props.variant !== null }));
		return (_ctx, _cache) => {
			return openBlock(), createElementBlock("thead", { class: normalizeClass(computedClasses.value) }, [renderSlot(_ctx.$slots, "default")], 2);
		};
	}
});
//#endregion
//#region src/components/BTable/BTr.vue
var BTr_default = /* @__PURE__ */ defineComponent({
	__name: "BTr",
	props: { variant: { default: null } },
	setup(__props) {
		const props = useDefaults(__props, "BTr");
		const computedClasses = computed(() => ({ [`table-${props.variant}`]: props.variant !== null }));
		return (_ctx, _cache) => {
			return openBlock(), createElementBlock("tr", { class: normalizeClass(computedClasses.value) }, [renderSlot(_ctx.$slots, "default")], 2);
		};
	}
});
//#endregion
//#region src/utils/tableUtils.ts
var getTableFieldHeadLabel = (field) => typeof field === "string" ? titleCase(field) : field.label !== void 0 ? field.label : titleCase(field.key);
var getWithGetter = (item, key) => {
	if (typeof key === "function") return key(item);
	return item[key];
};
var getByFieldKey = (item, field) => typeof item === "object" && item !== null ? getWithGetter(item, field.accessor ?? field.key) : item;
var formatItem = (item, field) => {
	const val = getByFieldKey(item, field);
	return typeof field.formatter === "function" ? field.formatter({
		value: val,
		key: field.key,
		item
	}) : val;
};
var bTableSimpleProps = Object.freeze(Object.keys({
	bordered: 0,
	borderless: 0,
	borderVariant: 0,
	captionTop: 0,
	dark: 0,
	fixed: 0,
	hover: 0,
	id: 0,
	noBorderCollapse: 0,
	outlined: 0,
	responsive: 0,
	small: 0,
	stacked: 0,
	stickyHeader: 0,
	striped: 0,
	stripedColumns: 0,
	variant: 0,
	tableAttrs: 0,
	tableClass: 0
}));
var bTableLiteProps = Object.freeze(Object.keys({
	align: 0,
	caption: 0,
	detailsTdClass: 0,
	fieldColumnClass: 0,
	fields: 0,
	footClone: 0,
	footRowVariant: 0,
	footVariant: 0,
	headRowVariant: 0,
	headVariant: 0,
	items: 0,
	labelStacked: 0,
	modelValue: 0,
	primaryKey: 0,
	tbodyClass: 0,
	tbodyTrAttrs: 0,
	tbodyTrClass: 0,
	tfootClass: 0,
	expandedItems: 0,
	tfootTrClass: 0,
	theadClass: 0,
	theadTrClass: 0
}));
var getDataLabelAttr = (props, label) => props.stacked && props.labelStacked !== true ? { "data-label": label } : void 0;
//#endregion
//#region src/utils/filterEvent.ts
var TABLE_TAG_NAMES = [
	"TD",
	"TH",
	"TR"
];
var eventFilter = [
	"a",
	"a *",
	"button",
	"button *",
	"input:not(.disabled):not([disabled])",
	"select:not(.disabled):not([disabled])",
	"textarea:not(.disabled):not([disabled])",
	"[role=\"link\"]",
	"[role=\"link\"] *",
	"[role=\"button\"]",
	"[role=\"button\"] *",
	"[tabindex]:not(.disabled):not([disabled])"
].join(",");
var filterEvent = (event) => {
	if (!event || !event.target) return false;
	const el = event.target;
	if ("disabled" in el && el.disabled || TABLE_TAG_NAMES.indexOf(el.tagName) !== -1) return false;
	if (el.closest(".dropdown-menu")) return true;
	const label = el.tagName === "LABEL" ? el : el.closest("label");
	if (label) {
		const doc = getSafeDocument();
		const labelFor = label.getAttribute("for");
		const input = labelFor ? doc?.getElementById(labelFor) : label.querySelector("input, select, textarea");
		if (input && !input.disabled) return true;
	}
	return el.matches(eventFilter);
};
//#endregion
//#region src/composables/useTableLiteHelpers.ts
var useTableFieldsMapper = ({ fields, items, stackedProps }) => {
	const computedFields = computed(() => {
		const fieldsValue = toValue(fields);
		const itemsValue = toValue(items);
		const stacked = {
			stacked: toValue(stackedProps.stacked),
			labelStacked: toValue(stackedProps.labelStacked)
		};
		if (!fieldsValue.length && itemsValue.length) {
			const [firstItem] = itemsValue;
			if (firstItem && (isTableItem(firstItem) || Array.isArray(firstItem))) return { items: Object.keys(firstItem).map((k) => {
				const label = startCase(k);
				return {
					key: k,
					label,
					tdAttr: getDataLabelAttr(stacked, label)
				};
			}) };
			return {
				items: [{ key: "" }],
				opts: { noHeader: true }
			};
		}
		return { items: fieldsValue.map((f) => {
			if (isTableField(f)) {
				const label = f.label ?? startCase(f.key);
				const dataLabelAttr = getDataLabelAttr(stacked, label);
				const tdAttr = typeof f.tdAttr === "function" ? (obj) => ({
					...dataLabelAttr,
					...f.tdAttr(obj)
				}) : dataLabelAttr || f.tdAttr ? {
					...dataLabelAttr,
					...f.tdAttr
				} : void 0;
				return {
					...f,
					tdAttr
				};
			}
			const label = startCase(f);
			return {
				key: f,
				label,
				tdAttr: getDataLabelAttr(stacked, label)
			};
		}) };
	});
	const total = computed(() => computedFields.value.items.length);
	return {
		total,
		showHeaders: computed(() => !(total.value > 0 && computedFields.value.opts?.noHeader === true)),
		fields: computed(() => computedFields.value.items)
	};
};
var useItemTracker = ({ allItems, selectedItems, primaryKey }) => {
	const isActivated = computed(() => selectedItems.value.length > 0);
	const pKey = readonly(toRef(primaryKey));
	const get = (item) => {
		if (typeof item === "object" && item !== null && pKey.value) return getWithGetter(item, pKey.value);
		return item;
	};
	const add = (item) => {
		const value = get(item);
		selectedItems.value = [...selectedItems.value, value];
	};
	const set = (items) => {
		selectedItems.value = pKey.value ? items.map(get) : items;
	};
	const setAll = () => set([...toValue(allItems)]);
	const remove = (item) => {
		const value = get(item);
		selectedItems.value = selectedItems.value.filter((i) => i !== value);
	};
	const clear = () => {
		selectedItems.value = [];
	};
	const has = (item) => {
		const value = get(item);
		return selectedItems.value.includes(value);
	};
	watch(pKey, () => {
		clear();
	});
	const objectsMap = computed(() => {
		if (!pKey.value) return /* @__PURE__ */ new Map();
		return new Map(toValue(allItems).map((item) => [get(item), item]));
	});
	const getFromPrimaryKey = (value) => {
		if (!pKey.value) return void 0;
		return objectsMap.value.get(value);
	};
	return {
		getFromPrimaryKey,
		resolvedItems: computed(() => {
			if (!pKey.value) return selectedItems.value;
			const arr = [];
			selectedItems.value.forEach((item) => {
				const resolved = getFromPrimaryKey(item);
				if (resolved !== void 0) arr.push(resolved);
			});
			return arr;
		}),
		isActivated,
		get,
		add,
		remove,
		clear,
		set,
		has,
		setAll
	};
};
var useItemExpansion = ({ allItems, primaryKey, expandedItems }) => {
	const utils = useItemTracker({
		primaryKey,
		allItems,
		selectedItems: expandedItems
	});
	const toggle = (item) => {
		if (utils.has(item)) utils.remove(item);
		else utils.add(item);
	};
	return {
		...utils,
		toggle
	};
};
var useTableKeyboardNavigation = ({ items, id }, events) => {
	const keyboardNavigation = inject(tableKeyboardNavigationKey, null);
	const instance = getCurrentInstance();
	const hasEventHandler = (eventName) => {
		const props = instance?.vnode.props;
		if (!props) return false;
		return !!(props[`on${eventName}`] || props[`on${eventName}Once`]);
	};
	const hasHeadClickedHandler = computed(() => hasEventHandler("HeadClicked"));
	const hasRowClickedHandler = computed(() => hasEventHandler("RowClicked"));
	const shouldHeaderBeFocusable = (field) => keyboardNavigation ? !!(keyboardNavigation.headerNavigation.value && field.sortable === true) : hasHeadClickedHandler.value;
	const shouldRowBeFocusable = computed(() => keyboardNavigation ? !!(keyboardNavigation.rowNavigation.value && toValue(items).length > 0) : !!(hasRowClickedHandler.value && toValue(items).length > 0));
	const headerClicked = (field, event, isFooter = false) => {
		events.onHeadClicked({
			key: field.key,
			field,
			event,
			isFooter
		});
	};
	const handleHeaderKeydown = (field, event, isFooter = false) => {
		const { target, code } = event;
		if (target && target.tagName !== "TH" && getSafeDocument()?.activeElement === target) return;
		if (code === "Enter" || code === "NumpadEnter" || code === "Space") {
			event.preventDefault();
			headerClicked(field, event, isFooter);
		}
	};
	const handleRowKeydown = (item, itemIndex, event) => {
		const { target, code, shiftKey } = event;
		if (target && target.tagName !== "TR" && getSafeDocument()?.activeElement === target) return;
		if (code === "Enter" || code === "NumpadEnter" || code === "Space") {
			event.preventDefault();
			events.onRowClicked({
				item,
				index: itemIndex,
				event
			});
			return;
		}
		if (code === "ArrowDown" || code === "ArrowUp" || code === "Home" || code === "End") {
			event.preventDefault();
			handleRowNavigation(code, shiftKey, itemIndex);
		}
	};
	const handleRowNavigation = (code, shiftKey, currentIndex) => {
		const doc = getSafeDocument();
		const rows = doc === null ? [] : Array.from(doc.querySelectorAll(`#${toValue(id)} tbody tr[tabindex]`));
		if (rows.length === 0) return;
		let targetIndex = currentIndex;
		if (code === "ArrowDown") {
			if (shiftKey) targetIndex = rows.length - 1;
			else targetIndex = Math.min(currentIndex + 1, rows.length - 1);
		} else if (code === "ArrowUp") {
			if (shiftKey) targetIndex = 0;
			else targetIndex = Math.max(currentIndex - 1, 0);
		} else if (code === "End") targetIndex = rows.length - 1;
		else if (code === "Home") targetIndex = 0;
		if (targetIndex !== currentIndex && rows[targetIndex]) rows[targetIndex]?.focus();
	};
	const handleMiddleClick = (item, itemIndex, event) => {
		if (event.button === 1 && !filterEvent(event)) events.onRowMiddleClicked({
			item,
			index: itemIndex,
			event
		});
	};
	return {
		shouldHeaderBeFocusable,
		headerClicked,
		handleHeaderKeydown,
		shouldRowBeFocusable,
		handleRowKeydown,
		handleMiddleClick
	};
};
//#endregion
//#region src/components/BTable/BTableLite.vue?vue&type=script&setup=true&lang.ts
var _hoisted_1$1 = { key: 0 };
var _hoisted_2$1 = {
	key: 0,
	class: "b-table-stacked-label"
};
var _hoisted_3$1 = { class: "d-inline-flex flex-nowrap align-items-center gap-1" };
var _hoisted_4 = { key: 3 };
//#endregion
//#region src/components/BTable/BTableLite.vue
var BTableLite_default = /* @__PURE__ */ defineComponent({
	__name: "BTableLite",
	props: /*@__PURE__*/ mergeModels({
		align: { default: void 0 },
		caption: { default: void 0 },
		detailsTdClass: { default: void 0 },
		fieldColumnClass: {
			type: [
				Function,
				String,
				Object,
				Array
			],
			default: void 0
		},
		fields: { default: () => [] },
		footClone: {
			type: Boolean,
			default: false
		},
		footRowVariant: { default: void 0 },
		footVariant: { default: void 0 },
		headRowVariant: { default: void 0 },
		headVariant: { default: void 0 },
		items: { default: () => [] },
		labelStacked: {
			type: Boolean,
			default: false
		},
		modelValue: { default: void 0 },
		primaryKey: {
			type: [String, Function],
			default: void 0
		},
		tbodyClass: { default: void 0 },
		tbodyTrAttrs: {
			type: [Function, Object],
			default: void 0
		},
		tbodyTrClass: {
			type: [
				Function,
				String,
				Array,
				Object
			],
			default: void 0
		},
		tfootClass: { default: void 0 },
		tfootTrClass: { default: void 0 },
		theadClass: { default: void 0 },
		theadTrClass: { default: void 0 },
		bordered: {
			type: Boolean,
			default: void 0
		},
		borderless: {
			type: Boolean,
			default: void 0
		},
		borderVariant: { default: void 0 },
		captionTop: {
			type: Boolean,
			default: void 0
		},
		dark: {
			type: Boolean,
			default: void 0
		},
		fixed: {
			type: Boolean,
			default: void 0
		},
		hover: {
			type: Boolean,
			default: void 0
		},
		id: { default: void 0 },
		noBorderCollapse: {
			type: Boolean,
			default: void 0
		},
		outlined: {
			type: Boolean,
			default: void 0
		},
		responsive: {
			type: [Boolean, String],
			default: void 0
		},
		small: {
			type: Boolean,
			default: void 0
		},
		stacked: {
			type: [Boolean, String],
			default: void 0
		},
		stickyHeader: {
			type: [
				Boolean,
				String,
				Number
			],
			default: void 0
		},
		striped: {
			type: Boolean,
			default: void 0
		},
		stripedColumns: {
			type: Boolean,
			default: void 0
		},
		variant: { default: void 0 },
		tableAttrs: {},
		tableClass: { default: void 0 }
	}, {
		"expandedItems": { default: () => [] },
		"expandedItemsModifiers": {}
	}),
	emits: /*@__PURE__*/ mergeModels([
		"head-clicked",
		"row-clicked",
		"row-dblclicked",
		"row-contextmenu",
		"row-hovered",
		"row-unhovered",
		"row-middle-clicked"
	], ["update:expandedItems"]),
	setup(__props, { expose: __expose, emit: __emit }) {
		const props = useDefaults(__props, "BTableLite");
		const emit = __emit;
		const slots = useSlots();
		const expandedItems = useModel(__props, "expandedItems");
		const computedId = useId$1(() => props.id);
		const expandedItemsController = useItemExpansion({
			allItems: () => props.items,
			primaryKey: toRef(() => props.primaryKey),
			expandedItems
		});
		const keyboardController = useTableKeyboardNavigation({
			items: () => props.items,
			id: computedId
		}, {
			onHeadClicked: (obj) => {
				emit("head-clicked", obj);
			},
			onRowClicked: (obj) => {
				emit("row-clicked", obj);
			},
			onRowMiddleClicked: (obj) => {
				emit("row-middle-clicked", obj);
			}
		});
		const { fields: computedFields, total: computedFieldsTotal, showHeaders: showComputedHeaders } = useTableFieldsMapper({
			fields: () => props.fields,
			items: () => props.items,
			stackedProps: {
				labelStacked: () => props.labelStacked,
				stacked: () => props.stacked
			}
		});
		const calculatedFooterSlot = (key) => slots[`foot(${key})`] ? `foot(${key})` : slots["foot()"] ? "foot()" : slots[`head(${key})`] ? `head(${key})` : "head()";
		const computedTableClasses = computed(() => [props.tableClass, { [`align-${props.align}`]: props.align !== void 0 }]);
		const getFieldColumnClasses = (field) => [
			field.class,
			field.thClass,
			{ "b-table-sticky-column": field.stickyColumn },
			props.fieldColumnClass ? typeof props.fieldColumnClass === "function" ? props.fieldColumnClass(field) : props.fieldColumnClass : null
		];
		const getFieldRowClasses = (field, tr) => [
			field.class,
			typeof field.tdClass === "function" ? field.tdClass(getByFieldKey(tr, field), field.key, tr) : field.tdClass,
			(isTableItem(tr) ? tr._cellVariants?.[field.key] : false) ? `table-${tr._cellVariants?.[field.key]}` : null,
			{ "b-table-sticky-column": field.stickyColumn }
		];
		const getRowClasses = (item, type) => props.tbodyTrClass ? typeof props.tbodyTrClass === "function" ? props.tbodyTrClass(item, type) : props.tbodyTrClass : null;
		const itemAttributes = (item, field) => field.tdAttr && typeof field.tdAttr === "function" ? field.tdAttr({
			value: getByFieldKey(item, field),
			key: field.key,
			item
		}) : field.tdAttr;
		const callThAttr = (item, field, type) => field.thAttr && typeof field.thAttr === "function" ? field.thAttr({
			value: getByFieldKey(item, field),
			key: field.key,
			item,
			type
		}) : field.thAttr;
		const callTbodyTrAttrs = (item, type) => props.tbodyTrAttrs ? typeof props.tbodyTrAttrs === "function" ? props.tbodyTrAttrs(item, type) : props.tbodyTrAttrs : null;
		const generateTableRowId = (primaryKeyValue) => `${computedId.value}__row_${primaryKeyValue}`;
		const getCellComponent = (field) => {
			if (field?.isRowHeader) return BTh_default;
			return BTd_default;
		};
		const footerProps = computed(() => ({
			variant: props.footVariant ?? props.headVariant,
			class: props.tfootClass ?? props.theadClass
		}));
		const computedSimpleProps = computed(() => ({
			...pick(props, bTableSimpleProps),
			tableClass: computedTableClasses.value,
			id: computedId.value
		}));
		__expose({ expansion: {
			...expandedItemsController,
			expandedItems: readonly(expandedItems)
		} });
		return (_ctx, _cache) => {
			return openBlock(), createBlock(BTableSimple_default, normalizeProps(guardReactiveProps(computedSimpleProps.value)), {
				default: withCtx(() => [
					slots["table-colgroup"] ? (openBlock(), createElementBlock("colgroup", _hoisted_1$1, [renderSlot(_ctx.$slots, "table-colgroup", { fields: unref(computedFields) })])) : createCommentVNode("", true),
					withDirectives(createVNode(BThead_default, {
						variant: unref(props).headVariant,
						class: normalizeClass(unref(props).theadClass)
					}, {
						default: withCtx(() => [
							renderSlot(_ctx.$slots, "thead-top", {
								columns: unref(computedFieldsTotal),
								fields: unref(computedFields)
							}),
							createVNode(BTr_default, {
								variant: unref(props).headRowVariant,
								class: normalizeClass(unref(props).theadTrClass)
							}, {
								default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(unref(computedFields), (field) => {
									return openBlock(), createBlock(BTh_default, mergeProps({
										key: field.key,
										scope: field.scope,
										class: getFieldColumnClasses(field),
										title: field.headerTitle,
										variant: field.variant,
										abbr: field.headerAbbr,
										style: field.thStyle,
										tabindex: unref(keyboardController).shouldHeaderBeFocusable(field) ? "0" : void 0
									}, { ref_for: true }, callThAttr(null, field, "top"), {
										onClick: ($event) => unref(keyboardController).headerClicked(field, $event),
										onKeydown: ($event) => unref(keyboardController).handleHeaderKeydown(field, $event)
									}), {
										default: withCtx(() => [renderSlot(_ctx.$slots, slots[`head(${field.key})`] ? `head(${field.key})` : "head()", {
											label: field.label,
											column: field.key,
											field,
											isFoot: false
										}, () => [createTextVNode(toDisplayString(unref(getTableFieldHeadLabel)(field)), 1)])]),
										_: 2
									}, 1040, [
										"scope",
										"class",
										"title",
										"variant",
										"abbr",
										"style",
										"tabindex",
										"onClick",
										"onKeydown"
									]);
								}), 128))]),
								_: 3
							}, 8, ["variant", "class"]),
							slots["thead-sub"] ? (openBlock(), createBlock(BTr_default, { key: 0 }, {
								default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(unref(computedFields), (field) => {
									return openBlock(), createBlock(BTd_default, {
										key: field.key,
										scope: "col",
										variant: field.variant,
										class: normalizeClass([field.class, field.thClass])
									}, {
										default: withCtx(() => [renderSlot(_ctx.$slots, "thead-sub", {
											items: unref(props).items,
											fields: unref(computedFields),
											field
										}, () => [createTextVNode(toDisplayString(field.label), 1)])]),
										_: 2
									}, 1032, ["variant", "class"]);
								}), 128))]),
								_: 3
							})) : createCommentVNode("", true)
						]),
						_: 3
					}, 8, ["variant", "class"]), [[vShow, unref(showComputedHeaders)]]),
					createVNode(BTbody_default, { class: normalizeClass(unref(props).tbodyClass) }, {
						default: withCtx(() => [renderSlot(_ctx.$slots, "custom-body", {
							fields: unref(computedFields),
							items: unref(props).items,
							columns: unref(computedFieldsTotal)
						}, () => [
							!unref(props).stacked && slots["top-row"] ? (openBlock(), createBlock(BTr_default, mergeProps({
								key: 0,
								class: getRowClasses(null, "row-top")
							}, callTbodyTrAttrs(null, "row-top")), {
								default: withCtx(() => [renderSlot(_ctx.$slots, "top-row", {
									columns: unref(computedFieldsTotal),
									fields: unref(computedFields)
								})]),
								_: 3
							}, 16, ["class"])) : createCommentVNode("", true),
							(openBlock(true), createElementBlock(Fragment, null, renderList(unref(props).items, (item, itemIndex) => {
								return openBlock(), createElementBlock(Fragment, { key: unref(props).primaryKey && unref(isTableItem)(item) && unref(getWithGetter)(item, unref(props).primaryKey) ? unref(getWithGetter)(item, unref(props).primaryKey) : itemIndex }, [createVNode(BTr_default, mergeProps({
									id: unref(props).primaryKey && unref(isTableItem)(item) && unref(getWithGetter)(item, unref(props).primaryKey) ? generateTableRowId(unref(getWithGetter)(item, unref(props).primaryKey)) : void 0,
									class: getRowClasses(item, "row"),
									variant: unref(isTableItem)(item) ? item._rowVariant : void 0,
									tabindex: unref(keyboardController).shouldRowBeFocusable.value ? "0" : void 0
								}, { ref_for: true }, callTbodyTrAttrs(item, "row"), {
									onClick: ($event) => !unref(filterEvent)($event) && emit("row-clicked", {
										item,
										index: itemIndex,
										event: $event
									}),
									onDblclick: ($event) => !unref(filterEvent)($event) && emit("row-dblclicked", {
										item,
										index: itemIndex,
										event: $event
									}),
									onContextmenu: ($event) => !unref(filterEvent)($event) && emit("row-contextmenu", {
										item,
										index: itemIndex,
										event: $event
									}),
									onMouseenter: ($event) => !unref(filterEvent)($event) && emit("row-hovered", {
										item,
										index: itemIndex,
										event: $event
									}),
									onMouseleave: ($event) => !unref(filterEvent)($event) && emit("row-unhovered", {
										item,
										index: itemIndex,
										event: $event
									}),
									onMousedown: ($event) => unref(keyboardController).handleMiddleClick(item, itemIndex, $event),
									onKeydown: ($event) => unref(keyboardController).handleRowKeydown(item, itemIndex, $event)
								}), {
									default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(unref(computedFields), (field) => {
										return openBlock(), createBlock(resolveDynamicComponent(getCellComponent(field)), mergeProps({
											key: field.key,
											variant: (unref(isTableItem)(item) ? item._cellVariants?.[field.key] : false) ? null : field.variant,
											class: getFieldRowClasses(field, item)
										}, { ref_for: true }, {
											...field.isRowHeader ? { scope: "row" } : void 0,
											...itemAttributes(item, field)
										}), {
											default: withCtx(() => [unref(props).stacked && unref(props).labelStacked ? (openBlock(), createElementBlock("label", _hoisted_2$1, toDisplayString(unref(getTableFieldHeadLabel)(field)), 1)) : createCommentVNode("", true), renderSlot(_ctx.$slots, slots[`cell(${field.key})`] ? `cell(${field.key})` : "cell()", {
												value: unref(formatItem)(item, field),
												unformatted: unref(getByFieldKey)(item, field),
												index: itemIndex,
												item,
												field,
												items: unref(props).items,
												toggleExpansion: () => unref(expandedItemsController).toggle(item),
												expansionShowing: unref(expandedItemsController).has(item)
											}, () => [!slots[`cell(${field.key})`] && !slots["cell()"] ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [createTextVNode(toDisplayString(unref(formatItem)(item, field)), 1)], 64)) : createCommentVNode("", true)])]),
											_: 2
										}, 1040, ["variant", "class"]);
									}), 128))]),
									_: 2
								}, 1040, [
									"id",
									"class",
									"variant",
									"tabindex",
									"onClick",
									"onDblclick",
									"onContextmenu",
									"onMouseenter",
									"onMouseleave",
									"onMousedown",
									"onKeydown"
								]), unref(expandedItemsController).has(item) && slots["row-expansion"] ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [createVNode(BTr_default, {
									"aria-hidden": "true",
									role: "presentation",
									class: "d-none"
								}), createVNode(BTr_default, mergeProps({
									class: getRowClasses(item, "row-expansion"),
									variant: unref(isTableItem)(item) ? item._rowVariant : void 0
								}, { ref_for: true }, callTbodyTrAttrs(item, "row-expansion")), {
									default: withCtx(() => [createVNode(BTd_default, {
										colspan: unref(computedFieldsTotal),
										class: normalizeClass(__props.detailsTdClass)
									}, {
										default: withCtx(() => [renderSlot(_ctx.$slots, "row-expansion", {
											item,
											toggleExpansion: () => unref(expandedItemsController).toggle(item),
											fields: unref(computedFields),
											index: itemIndex
										})]),
										_: 2
									}, 1032, ["colspan", "class"])]),
									_: 2
								}, 1040, ["class", "variant"])], 64)) : createCommentVNode("", true)], 64);
							}), 128)),
							!unref(props).stacked && slots["bottom-row"] ? (openBlock(), createBlock(BTr_default, mergeProps({
								key: 1,
								class: ["bottom-row", getRowClasses(null, "row-bottom")]
							}, callTbodyTrAttrs(null, "row-bottom")), {
								default: withCtx(() => [renderSlot(_ctx.$slots, "bottom-row", {
									columns: unref(computedFieldsTotal),
									fields: unref(computedFields)
								})]),
								_: 3
							}, 16, ["class"])) : createCommentVNode("", true)
						])]),
						_: 3
					}, 8, ["class"]),
					unref(props).footClone ? (openBlock(), createBlock(BTfoot_default, normalizeProps(mergeProps({ key: 1 }, footerProps.value)), {
						default: withCtx(() => [createVNode(BTr_default, {
							variant: unref(props).footRowVariant ?? unref(props).headRowVariant,
							class: normalizeClass(unref(props).tfootTrClass ?? unref(props).theadTrClass)
						}, {
							default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(unref(computedFields), (field) => {
								return openBlock(), createBlock(BTh_default, mergeProps({
									key: field.key,
									scope: "col",
									class: getFieldColumnClasses(field),
									title: field.headerTitle,
									abbr: field.headerAbbr,
									style: field.thStyle,
									variant: field.variant,
									tabindex: unref(keyboardController).shouldHeaderBeFocusable(field) ? "0" : void 0
								}, { ref_for: true }, callThAttr(null, field, "bottom"), {
									onClick: ($event) => unref(keyboardController).headerClicked(field, $event, true),
									onKeydown: ($event) => unref(keyboardController).handleHeaderKeydown(field, $event, true)
								}), {
									default: withCtx(() => [createElementVNode("div", _hoisted_3$1, [createElementVNode("div", null, [renderSlot(_ctx.$slots, calculatedFooterSlot(field.key), {
										label: field.label,
										column: field.key,
										field,
										isFoot: true
									}, () => [createTextVNode(toDisplayString(unref(getTableFieldHeadLabel)(field)), 1)])])])]),
									_: 2
								}, 1040, [
									"class",
									"title",
									"abbr",
									"style",
									"variant",
									"tabindex",
									"onClick",
									"onKeydown"
								]);
							}), 128))]),
							_: 3
						}, 8, ["variant", "class"])]),
						_: 3
					}, 16)) : slots["custom-foot"] ? (openBlock(), createBlock(BTfoot_default, normalizeProps(mergeProps({ key: 2 }, footerProps.value)), {
						default: withCtx(() => [renderSlot(_ctx.$slots, "custom-foot", {
							fields: unref(computedFields),
							items: unref(props).items,
							columns: unref(computedFieldsTotal)
						})]),
						_: 3
					}, 16)) : createCommentVNode("", true),
					slots["table-caption"] || unref(props).caption ? (openBlock(), createElementBlock("caption", _hoisted_4, [renderSlot(_ctx.$slots, "table-caption", {}, () => [createTextVNode(toDisplayString(unref(props).caption), 1)])])) : createCommentVNode("", true)
				]),
				_: 3
			}, 16);
		};
	}
});
//#endregion
//#region src/composables/useTableHelpers.ts
var useTableMapper = ({ fields, items, stackedProps, provider, events, pagination }) => {
	const sortByModelResolved = readonly(toRef(pagination.sort.by));
	const isSortableResolved = readonly(toRef(pagination.sort.isSortable));
	const filterResolved = readonly(toRef(pagination.filter.filter));
	const usesProviderResolved = readonly(toRef(provider.usesProvider));
	const isFilterableTable = computed(() => filterResolved.value !== void 0);
	const computedFields = computed(() => toValue(fields).map((el) => {
		if (!isTableField(el)) {
			const label = startCase(el);
			return {
				key: el,
				label,
				tdAttr: getDataLabelAttr({
					stacked: toValue(stackedProps.stacked),
					labelStacked: toValue(stackedProps.labelStacked)
				}, label)
			};
		}
		const value = sortByModelResolved.value?.find((sb) => el.key === sb.key);
		const sortValue = !el.sortable || isSortableResolved.value === false ? void 0 : value === void 0 ? "none" : value.order === "desc" ? "descending" : value.order === "asc" ? "ascending" : "none";
		return {
			...el,
			thAttr: {
				"aria-sort": sortValue,
				...el.thAttr
			},
			thClass: [el.thClass, { "b-table-sort-icon-left": toValue(pagination.sort.iconLeft) && sortValue !== void 0 }]
		};
	}));
	const getFormatter = (value) => typeof value.sortByFormatted === "function" ? value.sortByFormatted : value.formatter;
	const getFilterFormatter = (value) => typeof value.filterByFormatted === "function" ? value.filterByFormatted : value.formatter;
	const getStringValue = (ob, key) => {
		if (!isTableItem(ob)) return String(ob);
		const sortField = computedFields.value.find((el) => {
			if (isTableField(el)) return el.key === key;
			return false;
		});
		const val = isTableField(sortField) && sortField.accessor ? getWithGetter(ob, sortField.accessor) : getWithGetter(ob, key);
		if (isTableField(sortField) && !!sortField.sortByFormatted) {
			const formatter = getFormatter(sortField);
			if (formatter) return String(formatItem(ob, {
				...sortField,
				formatter
			}));
		}
		return typeof val === "object" && val !== null ? JSON.stringify(val) : val?.toString() ?? "";
	};
	const fieldByKey = computed(() => {
		const map = /* @__PURE__ */ new Map();
		for (const f of computedFields.value) if (isTableField(f)) map.set(f.key, f);
		return map;
	});
	const computedItems = computed(() => {
		const filterableValue = toValue(pagination.filter.filterable);
		const filterFunctionValue = unref(pagination.filter.filterFunction);
		const itemsValue = toValue(items);
		const sortByItems = sortByModelResolved.value?.filter((el) => !!el.order);
		const mapItem = (item) => {
			if (typeof item === "object" && item !== null && Object.keys(item).some((key) => key.includes("."))) {
				let newItem = {};
				for (const key in item) if (key.includes(".")) newItem = set(newItem, key, item[key]);
				else newItem[key] = item[key];
				return newItem;
			}
			return item;
		};
		const filterItem = (item) => {
			if (!isTableItem(item)) return true;
			return Object.entries(item).some(([key, val]) => {
				if (val === null || val === void 0 || key[0] === "_" || !filterableValue?.includes(key) && !!filterableValue?.length) return false;
				if (typeof filterFunctionValue === "function") return filterFunctionValue(item, filterResolved.value);
				const realVal = () => {
					const filterField = computedFields.value.find((el) => {
						if (isTableField(el)) return el.key === key;
						return false;
					});
					if (isTableField(filterField) && !!filterField.filterByFormatted) {
						const formatter = getFilterFormatter(filterField);
						if (formatter) return String(formatter({
							value: val,
							key: String(filterField.key),
							item
						}));
					}
					return typeof val === "object" ? JSON.stringify(Object.values(val)) : val.toString();
				};
				return realVal().toLowerCase().includes(filterResolved.value?.toLowerCase() ?? "");
			});
		};
		const noProviderFilteringValue = toValue(provider.noProviderFiltering);
		const mappedItems = itemsValue.reduce((acc, val) => {
			const item = mapItem(val);
			if (!(isFilterableTable.value && (!usesProviderResolved.value || noProviderFilteringValue)) || filterItem(item)) acc.push(item);
			return acc;
		}, []);
		if (sortByItems?.length && (isSortableResolved.value === true && !usesProviderResolved.value && !toValue(pagination.sort.noLocalSorting) || isSortableResolved.value === true && usesProviderResolved.value && toValue(provider.noProviderSorting))) {
			const sortCompareValue = unref(pagination.sort.sortCompare);
			const sortNullLastValue = toValue(pagination.sort.sortNullLast);
			return mappedItems.sort((a, b) => {
				for (let i = 0; i < sortByItems.length; i++) {
					const value = sortByItems[i];
					if (value === void 0) continue;
					const { key, order } = value;
					const field = fieldByKey.value.get(key);
					const comparer = field?.sortCompare || sortCompareValue;
					if (sortNullLastValue && !comparer) {
						const getItemVal = (item) => {
							if (!isTableItem(item)) return void 0;
							return isTableField(field) && field.accessor ? getWithGetter(item, field.accessor) : getWithGetter(item, key);
						};
						const aIsNull = getItemVal(a) == null;
						const bIsNull = getItemVal(b) == null;
						if (aIsNull && bIsNull) continue;
						if (aIsNull) return 1;
						if (bIsNull) return -1;
					}
					const comparison = comparer ? comparer(a, b, key) : getStringValue(a, key).localeCompare(getStringValue(b, key), void 0, { numeric: true });
					if (comparison !== 0) return order === "asc" ? comparison : -comparison;
				}
				return 0;
			});
		}
		return mappedItems;
	});
	const computedDisplayItems = computed(() => {
		const perPageNumber = toValue(pagination.perPage);
		const currentPageNumber = toValue(pagination.currentPage);
		if (Number.isNaN(perPageNumber) || usesProviderResolved.value && !toValue(provider.noProviderPaging)) return computedItems.value;
		return computedItems.value.slice((currentPageNumber - 1) * (perPageNumber || Number.POSITIVE_INFINITY), currentPageNumber * (perPageNumber || Number.POSITIVE_INFINITY));
	});
	watch(filterResolved, () => {
		pagination.currentPage.value = 1;
	});
	watch(computedDisplayItems, (v) => {
		events.onChange([...v]);
	});
	return {
		items: computedItems,
		displayItems: computedDisplayItems,
		getStringValue,
		fields: computedFields,
		isFilterableTable
	};
};
var useTableKeyboardNavigationInjector = ({ isSortable, selectable, noSelectOnClick }) => {
	const keyboardRowNavigation = computed(() => !!(toValue(selectable) && !toValue(noSelectOnClick)));
	const keyboardHeaderNavigation = computed(() => !!toValue(isSortable));
	provide(tableKeyboardNavigationKey, {
		rowNavigation: keyboardRowNavigation,
		headerNavigation: keyboardHeaderNavigation
	});
};
var useTableSelectedItems = ({ selectable, selectMode, selectedItems, events, primaryKey, allItems }) => {
	const selectableResolved = readonly(toRef(selectable));
	const selectModeResolved = readonly(toRef(selectMode));
	const allItemsResolved = computed(() => toValue(allItems));
	const utils = useItemTracker({
		allItems: allItemsResolved,
		primaryKey,
		selectedItems
	});
	watch(selectedItems, (newValue, oldValue) => {
		const previousSelection = new Set(oldValue);
		const nextSelection = new Set(newValue);
		Array.from(oldValue).filter((item) => !nextSelection.has(item)).forEach((item) => {
			events.onRowUnselected(item);
		});
		Array.from(newValue).filter((item) => !previousSelection.has(item)).forEach((item) => {
			events.onRowSelected(item);
		});
	});
	const handleRowSelection = ({ item, index, shiftClicked = false, ctrlClicked = false, metaClicked = false }) => {
		if (!selectableResolved.value) return;
		if (selectModeResolved.value === "single" || selectModeResolved.value === "multi") {
			if (shiftClicked || ctrlClicked) return;
			if (utils.has(item)) utils.remove(item);
			else if (selectModeResolved.value === "single") utils.set([item]);
			else utils.add(item);
		} else if (ctrlClicked || metaClicked) {
			if (utils.has(item)) utils.remove(item);
			else utils.add(item);
		} else if (shiftClicked) {
			const lastSelectedItem = selectedItems.value[selectedItems.value.length - 1];
			const lastSelectedIndex = allItemsResolved.value.findIndex((i) => utils.get(i) === lastSelectedItem);
			if (lastSelectedIndex === -1) {
				utils.set([item]);
				return;
			}
			const selectStartIndex = Math.min(lastSelectedIndex, index);
			const selectEndIndex = Math.max(lastSelectedIndex, index);
			const items = allItemsResolved.value.slice(selectStartIndex, selectEndIndex + 1);
			utils.set(items);
		} else utils.set([item]);
	};
	return {
		...utils,
		handleRowSelection,
		clear: () => {
			if (!selectableResolved.value) return;
			utils.clear();
		},
		setAll: () => {
			if (!selectableResolved.value || selectModeResolved.value === "single") return;
			utils.setAll();
		},
		add: (item) => {
			if (!selectableResolved.value || utils.has(item)) return;
			if (selectModeResolved.value === "single") utils.set([item]);
			else utils.add(item);
		},
		remove: (item) => {
			if (!selectableResolved.value) return;
			utils.remove(item);
		},
		has: (item) => {
			if (!selectableResolved.value) return false;
			return utils.has(item);
		}
	};
};
var useTableProvider = ({ items, provider, busy, currentPage, debounce, perPage, noProvider, noProviderFiltering, noProviderPaging, noProviderSorting, filter, sortBy, events }) => {
	const providerResolved = readonly(toRef(provider));
	const currentPageResolved = readonly(toRef(currentPage));
	const perPageResolved = readonly(toRef(perPage));
	const sortByResolved = readonly(toRef(sortBy));
	const filterResolved = readonly(toRef(filter));
	const usesProvider = computed(() => providerResolved.value !== void 0);
	let abortController = null;
	const callItemsProvider = async () => {
		if (!usesProvider.value || providerResolved.value === void 0) return;
		if (abortController) abortController.abort();
		abortController = new AbortController();
		const { signal } = abortController;
		busy.value = true;
		try {
			const response = providerResolved.value({
				currentPage: currentPageResolved.value,
				filter: filterResolved.value,
				sortBy: sortByResolved.value,
				perPage: perPageResolved.value,
				signal
			});
			const returnValue = response instanceof Promise ? await response : response;
			if (signal.aborted) return;
			if (returnValue === void 0) return;
			items.value = returnValue;
		} catch (error) {
			if (error instanceof Error && error.name === "AbortError") return;
			throw error;
		} finally {
			if (!signal.aborted) busy.value = false;
		}
	};
	const debouncedCallItemsProvider = useDebounceFn(callItemsProvider, debounce.wait, { maxWait: debounce.maxWait });
	const providerPropsWatch = async (prop, val, oldVal) => {
		if (deepEqual(val, oldVal)) return;
		const inNoProvider = (key) => toValue(noProvider)?.includes(key) === true;
		const noProvideWhenPaging = (prop === "currentPage" || prop === "perPage") && (inNoProvider("paging") || toValue(noProviderPaging) === true);
		const noProvideWhenFiltering = prop === "filter" && (inNoProvider("filtering") || toValue(noProviderFiltering) === true);
		const noProvideWhenSorting = (prop === "sortBy" || prop === "sortDesc") && (inNoProvider("sorting") || toValue(noProviderSorting) === true);
		if (noProvideWhenPaging || noProvideWhenFiltering || noProvideWhenSorting) return;
		if (usesProvider.value === true) await debouncedCallItemsProvider();
		if (!(prop === "currentPage" || prop === "perPage")) events.onFiltered();
	};
	watch(filterResolved, async (filter, oldFilter) => {
		await providerPropsWatch("filter", filter, oldFilter);
	});
	watch(currentPageResolved, async (val, oldVal) => {
		await providerPropsWatch("currentPage", val, oldVal);
	});
	watch(perPageResolved, async (val, oldVal) => {
		await providerPropsWatch("perPage", val, oldVal);
	});
	watch(sortByResolved, async (val, oldVal) => {
		await providerPropsWatch("sortBy", val, oldVal);
	}, { deep: true });
	watch(providerResolved, async (newValue) => {
		if (newValue === void 0) {
			items.value = [];
			return;
		}
		await callItemsProvider();
	});
	onMounted(async () => {
		await callItemsProvider();
	});
	return {
		usesProvider,
		callItemsProvider
	};
};
var useTableSort = ({ fields, sortBy, initialSortDirection, multisort, mustSort, events }) => {
	const isSortable = computed(() => sortBy.value !== void 0 || toValue(fields).some((field) => typeof field === "object" && field !== null && field.sortable === true));
	const handleFieldSorting = (field) => {
		if (!isSortable.value) return;
		const fieldKey = typeof field === "object" && field !== null ? field.key : field;
		const fieldSortable = typeof field === "object" && field !== null ? field.sortable : false;
		if (!(isSortable.value === true && fieldSortable === true)) return;
		const getLastSortDirection = () => {
			return [...sortBy.value ?? []].reverse().find((sort) => sort.order !== void 0 && sort.key !== fieldKey)?.order ?? "asc";
		};
		const getInitialSortDirection = () => {
			if (typeof field === "object" && field !== null && field.initialSortDirection) {
				if (field.initialSortDirection === "last") return getLastSortDirection();
				return field.initialSortDirection;
			}
			const initialSortDirectionValue = toValue(initialSortDirection);
			if (initialSortDirectionValue) {
				if (initialSortDirectionValue === "last") return getLastSortDirection();
				return initialSortDirectionValue;
			}
			return "asc";
		};
		const resolveOrder = (val) => {
			const mustSortValue = toValue(mustSort);
			if (val === void 0) return getInitialSortDirection();
			const initial = getInitialSortDirection();
			const must = mustSortValue === true || !!mustSortValue && mustSortValue.includes(fieldKey);
			if (val === "asc") {
				if (initial === "desc") return must ? "desc" : void 0;
				return "desc";
			}
			if (val === "desc") {
				if (initial === "desc") return "asc";
				return must ? "asc" : void 0;
			}
		};
		const index = sortBy.value?.findIndex((el) => el.key === fieldKey) ?? -1;
		const originalValue = sortBy.value?.[index];
		const updatedValue = index === -1 || !originalValue ? {
			key: fieldKey,
			order: getInitialSortDirection()
		} : { ...originalValue };
		/**
		* @returns the updated value to emit for sorted
		*/
		const handleMultiSort = () => {
			const tmp = [...sortBy.value ?? []];
			const val = updatedValue;
			if (index === -1) tmp.push(val);
			else {
				const order = resolveOrder(val.order);
				if (order) {
					val.order = order;
					tmp.splice(index, 1, val);
				} else {
					val.order = void 0;
					tmp.splice(index, 1);
				}
			}
			sortBy.value = tmp;
			return val;
		};
		/**
		* @returns the updated value to emit for sorted
		*/
		const handleSingleSort = () => {
			const order = index === -1 ? updatedValue.order : resolveOrder(updatedValue.order);
			const val = {
				...updatedValue,
				order
			};
			sortBy.value = order ? [val] : [];
			return val;
		};
		events.onSorted(toValue(multisort) === true ? handleMultiSort() : handleSingleSort());
	};
	return {
		isSortable,
		handleFieldSorting
	};
};
//#endregion
//#region src/components/BTable/BTable.vue?vue&type=script&setup=true&lang.ts
var _hoisted_1 = {
	key: 0,
	class: "visually-hidden"
};
var _hoisted_2 = {
	role: "alert",
	"aria-live": "polite"
};
var _hoisted_3 = { class: "text-center my-2" };
//#endregion
//#region src/components/BTable/BTable.vue
var BTable_default = /* @__PURE__ */ defineComponent({
	__name: "BTable",
	props: /*@__PURE__*/ mergeModels({
		provider: {
			type: Function,
			default: void 0
		},
		noProvider: { default: void 0 },
		noProviderPaging: {
			type: Boolean,
			default: false
		},
		noProviderSorting: {
			type: Boolean,
			default: false
		},
		noProviderFiltering: {
			type: Boolean,
			default: false
		},
		sortCompare: {
			type: Function,
			default: void 0
		},
		mustSort: {
			type: [Boolean, Array],
			default: false
		},
		initialSortDirection: { default: "asc" },
		selectable: {
			type: Boolean,
			default: false
		},
		multisort: {
			type: Boolean,
			default: false
		},
		stickySelect: {
			type: Boolean,
			default: false
		},
		selectHead: {
			type: [Boolean, String],
			default: true
		},
		selectMode: { default: "multi" },
		selectionVariant: { default: "primary" },
		perPage: { default: Number.POSITIVE_INFINITY },
		filter: { default: void 0 },
		filterFunction: {
			type: Function,
			default: void 0
		},
		filterable: { default: void 0 },
		labelSortAsc: { default: "Click to sort ascending" },
		labelSortClear: { default: "Click to clear sorting" },
		labelSortDesc: { default: "Click to sort descending" },
		noFooterSorting: {
			type: Boolean,
			default: false
		},
		noLocalSorting: {
			type: Boolean,
			default: false
		},
		noSelectOnClick: {
			type: Boolean,
			default: false
		},
		sortNullLast: {
			type: Boolean,
			default: false
		},
		noSortableIcon: {
			type: Boolean,
			default: false
		},
		sortIconLeft: {
			type: Boolean,
			default: false
		},
		emptyFilteredText: { default: "There are no records matching your request" },
		emptyText: { default: "There are no records to show" },
		showEmpty: {
			type: Boolean,
			default: false
		},
		align: { default: void 0 },
		caption: { default: void 0 },
		detailsTdClass: { default: void 0 },
		fieldColumnClass: {
			type: [
				Function,
				String,
				Object,
				Array
			],
			default: void 0
		},
		fields: { default: () => [] },
		footClone: {
			type: Boolean,
			default: void 0
		},
		footRowVariant: { default: void 0 },
		footVariant: { default: void 0 },
		headRowVariant: { default: void 0 },
		headVariant: { default: void 0 },
		labelStacked: {
			type: Boolean,
			default: void 0
		},
		modelValue: { default: void 0 },
		expandedItems: {},
		primaryKey: {
			type: [String, Function],
			default: void 0
		},
		tbodyClass: { default: void 0 },
		tbodyTrAttrs: {},
		tbodyTrClass: {
			type: [
				Function,
				String,
				Array,
				Object
			],
			default: void 0
		},
		tfootClass: { default: void 0 },
		tfootTrClass: { default: void 0 },
		theadClass: { default: void 0 },
		theadTrClass: { default: void 0 },
		bordered: {
			type: Boolean,
			default: void 0
		},
		borderless: {
			type: Boolean,
			default: void 0
		},
		borderVariant: { default: void 0 },
		captionTop: {
			type: Boolean,
			default: void 0
		},
		dark: {
			type: Boolean,
			default: void 0
		},
		fixed: {
			type: Boolean,
			default: void 0
		},
		hover: {
			type: Boolean,
			default: void 0
		},
		id: { default: void 0 },
		noBorderCollapse: {
			type: Boolean,
			default: void 0
		},
		outlined: {
			type: Boolean,
			default: void 0
		},
		responsive: {
			type: [Boolean, String],
			default: void 0
		},
		small: {
			type: Boolean,
			default: void 0
		},
		stacked: {
			type: [Boolean, String],
			default: void 0
		},
		stickyHeader: {
			type: [
				Boolean,
				String,
				Number
			],
			default: void 0
		},
		striped: {
			type: Boolean,
			default: void 0
		},
		stripedColumns: {
			type: Boolean,
			default: void 0
		},
		variant: { default: void 0 },
		tableAttrs: {},
		debounce: { default: 0 },
		debounceMaxWait: { default: NaN }
	}, {
		"sortBy": { default: void 0 },
		"sortByModifiers": {},
		"busy": {
			type: Boolean,
			default: false
		},
		"busyModifiers": {},
		"selectedItems": { default: () => [] },
		"selectedItemsModifiers": {},
		"expandedItems": { default: () => [] },
		"expandedItemsModifiers": {},
		"items": { default: () => [] },
		"itemsModifiers": {},
		"currentPage": { default: 1 },
		"currentPageModifiers": {}
	}),
	emits: /*@__PURE__*/ mergeModels([
		"filtered",
		"row-selected",
		"row-unselected",
		"sorted",
		"change",
		"context-changed",
		"head-clicked",
		"row-clicked",
		"row-dblclicked",
		"row-contextmenu",
		"row-hovered",
		"row-unhovered",
		"row-middle-clicked"
	], [
		"update:sortBy",
		"update:busy",
		"update:selectedItems",
		"update:expandedItems",
		"update:items",
		"update:currentPage"
	]),
	setup(__props, { expose: __expose, emit: __emit }) {
		const props = useDefaults(__props, "BTable");
		const emit = __emit;
		const slots = useSlots();
		const dynamicCellSlots = computed(() => Object.keys(slots).filter((key) => key.startsWith("cell(")));
		const dynamicFootSlots = computed(() => Object.keys(slots).filter((key) => key.startsWith("foot(")));
		const sortByModel = useModel(__props, "sortBy");
		const busyModel = useModel(__props, "busy");
		const selectedItemsModel = useModel(__props, "selectedItems");
		const expandedItems = useModel(__props, "expandedItems");
		const itemsModel = useModel(__props, "items");
		const currentPage = useModel(__props, "currentPage");
		const computedId = useId$1(() => props.id);
		const perPageNumber = useToNumber(() => props.perPage, { method: "parseInt" });
		const debounceNumber = useToNumber(() => props.debounce ?? 0, { nanToZero: true });
		const debounceMaxWaitNumber = useToNumber(() => props.debounceMaxWait ?? NaN);
		const currentPageNumber = useToNumber(currentPage, { method: "parseInt" });
		const writableCurrentPageNumber = computed({
			get: () => currentPageNumber.value,
			set: (v) => {
				currentPage.value = v;
			}
		});
		const sortController = useTableSort({
			fields: () => props.fields,
			sortBy: sortByModel,
			events: { onSorted: (v) => {
				emit("sorted", v);
			} },
			initialSortDirection: () => props.initialSortDirection,
			mustSort: () => props.mustSort,
			multisort: () => props.multisort
		});
		const providerController = useTableProvider({
			items: itemsModel,
			events: { onFiltered: () => {
				emit("filtered", computedItems.value);
			} },
			busy: busyModel,
			provider: toRef(() => props.provider),
			debounce: {
				maxWait: debounceMaxWaitNumber,
				wait: debounceNumber
			},
			currentPage: readonly(writableCurrentPageNumber),
			perPage: perPageNumber,
			filter: () => props.filter,
			noProvider: () => props.noProvider,
			noProviderFiltering: () => props.noProviderFiltering,
			noProviderPaging: () => props.noProviderPaging,
			noProviderSorting: () => props.noProviderSorting,
			sortBy: sortByModel
		});
		const expandedItemsController = useItemExpansion({
			allItems: itemsModel,
			primaryKey: toRef(() => props.primaryKey),
			expandedItems
		});
		const { items: computedItems, displayItems: computedDisplayItems, getStringValue, fields: computedFields, isFilterableTable } = useTableMapper({
			fields: () => props.fields,
			provider: {
				noProviderFiltering: () => props.noProviderFiltering,
				noProviderPaging: () => props.noProviderPaging,
				noProviderSorting: () => props.noProviderSorting,
				usesProvider: providerController.usesProvider
			},
			events: { onChange: (v) => {
				emit("change", v);
			} },
			items: itemsModel,
			pagination: {
				perPage: perPageNumber,
				currentPage: writableCurrentPageNumber,
				filter: {
					filter: () => props.filter,
					filterFunction: toRef(() => props.filterFunction),
					filterable: () => props.filterable
				},
				sort: {
					iconLeft: () => props.sortIconLeft,
					isSortable: sortController.isSortable,
					noLocalSorting: () => props.noLocalSorting,
					by: sortByModel,
					sortCompare: toRef(() => props.sortCompare),
					sortNullLast: () => props.sortNullLast
				}
			},
			stackedProps: {
				stacked: () => props.stacked,
				labelStacked: () => props.labelStacked
			}
		});
		const selectedItemsController = useTableSelectedItems({
			selectable: () => props.selectable,
			primaryKey: toRef(() => props.primaryKey),
			selectedItems: selectedItemsModel,
			allItems: computedItems,
			selectMode: () => props.selectMode,
			events: {
				onRowSelected: (item) => {
					emit("row-selected", item);
				},
				onRowUnselected: (item) => {
					emit("row-unselected", item);
				}
			}
		});
		useTableKeyboardNavigationInjector({
			isSortable: sortController.isSortable,
			selectable: () => props.selectable,
			noSelectOnClick: () => props.noSelectOnClick
		});
		const tableClasses = computed(() => ({
			"b-table-busy": busyModel.value,
			"b-table-selectable": props.selectable,
			"user-select-none": props.selectable && !props.noSelectOnClick && selectedItemsController.isActivated.value,
			"b-table-fixed": props.fixed,
			"b-table-no-border-collapse": props.noBorderCollapse,
			"b-table-no-sort-icon": props.noSortableIcon
		}));
		const getBusyRowClasses = computed(() => [props.tbodyTrClass ? typeof props.tbodyTrClass === "function" ? props.tbodyTrClass(null, "table-busy") : props.tbodyTrClass : null]);
		const getFieldColumnClasses = (field) => [{ "b-table-sortable-column": sortController.isSortable.value && field.sortable }];
		const getRowClasses = (item, type) => [{ [`selected table-${props.selectionVariant}`]: props.selectable && !!item && selectedItemsController.has(item) }, props.tbodyTrClass ? typeof props.tbodyTrClass === "function" ? props.tbodyTrClass(item, type) : props.tbodyTrClass : null];
		const boundBTableLiteEmits = {
			onHeadClicked: ({ key, field, event, isFooter = false }) => {
				emit("head-clicked", {
					key,
					field,
					event,
					isFooter
				});
				if (!isFooter || !props.noFooterSorting) sortController.handleFieldSorting(field);
			},
			onRowClicked: ({ item, index, event }) => {
				if (!props.noSelectOnClick) selectedItemsController.handleRowSelection({
					item,
					index,
					shiftClicked: event.shiftKey,
					ctrlClicked: event.ctrlKey,
					metaClicked: event.metaKey
				});
				emit("row-clicked", {
					item,
					index,
					event
				});
			},
			onRowDblclicked: (...args) => emit("row-dblclicked", ...args),
			onRowContextmenu: (...args) => emit("row-contextmenu", ...args),
			onRowHovered: (...args) => emit("row-hovered", ...args),
			onRowUnhovered: (...args) => emit("row-unhovered", ...args),
			onRowMiddleClicked: (...args) => emit("row-middle-clicked", ...args)
		};
		const computedLiteProps = computed(() => ({
			...pick(props, [...bTableLiteProps, ...bTableSimpleProps]),
			tableAttrs: { ariaBusy: busyModel.value },
			items: computedDisplayItems.value,
			fields: computedFields.value,
			tableClass: tableClasses.value,
			tbodyTrClass: getRowClasses,
			fieldColumnClass: getFieldColumnClasses,
			id: computedId.value,
			...boundBTableLiteEmits
		}));
		const emptySlotScope = computed(() => ({
			emptyFilteredText: props.emptyFilteredText,
			emptyText: props.emptyText,
			fields: computedFields.value,
			items: computedItems.value
		}));
		const showEmptyFiltered = computed(() => isFilterableTable.value && props.filter !== void 0 && props.filter !== "");
		const getSortLabel = (field) => {
			if (!sortController.isSortable.value || !field.sortable) return "";
			const currentSort = sortByModel.value?.find((s) => s.key === field.key);
			if (!currentSort || currentSort.order === void 0) return props.labelSortAsc;
			if (currentSort.order === "asc") return props.labelSortDesc;
			const mustSortValue = props.mustSort;
			if (mustSortValue || Array.isArray(mustSortValue) && mustSortValue.includes(field.key)) return props.labelSortAsc;
			return props.labelSortClear;
		};
		watch([
			() => props.filter,
			sortByModel,
			writableCurrentPageNumber,
			perPageNumber
		], ([filter, sortBy, currentPage, perPage]) => {
			emit("context-changed", {
				filter,
				sortBy,
				currentPage,
				perPage
			});
		}, { deep: true });
		__expose({
			expansion: {
				...expandedItemsController,
				expandedItems: readonly(expandedItems)
			},
			selection: {
				...selectedItemsController,
				selectedItems: readonly(selectedItemsModel)
			},
			items: computedItems,
			displayItems: computedDisplayItems,
			getStringValue,
			refresh: providerController.callItemsProvider
		});
		return (_ctx, _cache) => {
			return openBlock(), createBlock(BTableLite_default, mergeProps(computedLiteProps.value, {
				"expanded-items": expandedItems.value,
				"onUpdate:expandedItems": _cache[0] || (_cache[0] = ($event) => expandedItems.value = $event)
			}), createSlots({
				"custom-body": withCtx((scope) => [busyModel.value && slots["table-busy"] ? (openBlock(), createBlock(BTr_default, {
					key: 0,
					class: normalizeClass(["b-table-busy-slot", getBusyRowClasses.value])
				}, {
					default: withCtx(() => [createVNode(BTd_default, { colspan: scope.fields.length }, {
						default: withCtx(() => [renderSlot(_ctx.$slots, "table-busy")]),
						_: 3
					}, 8, ["colspan"])]),
					_: 2
				}, 1032, ["class"])) : !busyModel.value && unref(props).showEmpty === true && unref(computedItems).length === 0 ? (openBlock(), createBlock(BTr_default, {
					key: 1,
					class: "b-table-empty-row"
				}, {
					default: withCtx(() => [createVNode(BTd_default, { colspan: unref(computedFields).length }, {
						default: withCtx(() => [createElementVNode("div", _hoisted_2, [createElementVNode("div", _hoisted_3, [showEmptyFiltered.value ? renderSlot(_ctx.$slots, "empty-filtered", normalizeProps(guardReactiveProps(emptySlotScope.value)), () => [createTextVNode(toDisplayString(unref(props).emptyFilteredText), 1)], void 0, 0) : renderSlot(_ctx.$slots, "empty", normalizeProps(guardReactiveProps(emptySlotScope.value)), () => [createTextVNode(toDisplayString(unref(props).emptyText), 1)], void 0, 1)])])]),
						_: 3
					}, 8, ["colspan"])]),
					_: 3
				})) : createCommentVNode("", true)]),
				_: 2
			}, [
				slots["table-colgroup"] ? {
					name: "table-colgroup",
					fn: withCtx((scope) => [renderSlot(_ctx.$slots, "table-colgroup", normalizeProps(guardReactiveProps(scope)))]),
					key: "0"
				} : void 0,
				slots["thead-top"] ? {
					name: "thead-top",
					fn: withCtx((scope) => [renderSlot(_ctx.$slots, "thead-top", mergeProps(scope, {
						clearSelected: unref(selectedItemsController).clear,
						selectAllRows: unref(selectedItemsController).setAll,
						fields: unref(computedFields)
					}))]),
					key: "1"
				} : void 0,
				slots["thead-sub"] ? {
					name: "thead-sub",
					fn: withCtx((scope) => [renderSlot(_ctx.$slots, "thead-sub", mergeProps(scope, { fields: unref(computedFields) }))]),
					key: "2"
				} : void 0,
				slots["top-row"] ? {
					name: "top-row",
					fn: withCtx((scope) => [renderSlot(_ctx.$slots, "top-row", mergeProps(scope, { fields: unref(computedFields) }))]),
					key: "3"
				} : void 0,
				slots["row-expansion"] ? {
					name: "row-expansion",
					fn: withCtx((scope) => [renderSlot(_ctx.$slots, "row-expansion", mergeProps(scope, {
						fields: unref(computedFields),
						selectRow: () => unref(selectedItemsController).add(scope.item),
						unselectRow: () => unref(selectedItemsController).remove(scope.item),
						rowSelected: unref(selectedItemsController).has(scope.item)
					}))]),
					key: "4"
				} : void 0,
				slots["bottom-row"] ? {
					name: "bottom-row",
					fn: withCtx((scope) => [renderSlot(_ctx.$slots, "bottom-row", mergeProps(scope, { fields: unref(computedFields) }))]),
					key: "5"
				} : void 0,
				slots["custom-foot"] ? {
					name: "custom-foot",
					fn: withCtx((scope) => [renderSlot(_ctx.$slots, "custom-foot", mergeProps(scope, { fields: unref(computedFields) }))]),
					key: "6"
				} : void 0,
				slots["table-caption"] ? {
					name: "table-caption",
					fn: withCtx(() => [renderSlot(_ctx.$slots, "table-caption")]),
					key: "7"
				} : void 0,
				renderList(dynamicCellSlots.value, (name) => {
					return {
						name,
						fn: withCtx((scope) => [renderSlot(_ctx.$slots, name, mergeProps(scope, {
							selectRow: () => unref(selectedItemsController).add(scope.item),
							unselectRow: () => unref(selectedItemsController).remove(scope.item),
							rowSelected: unref(selectedItemsController).has(scope.item)
						}))])
					};
				}),
				renderList(dynamicFootSlots.value, (name) => {
					return {
						name,
						fn: withCtx((scope) => [renderSlot(_ctx.$slots, name, mergeProps(scope, {
							selectAllRows: unref(selectedItemsController).setAll,
							clearSelected: unref(selectedItemsController).clear
						}))])
					};
				}),
				renderList(unref(computedFields), (field) => {
					return {
						name: `head(${String(field.key)})`,
						fn: withCtx((scope) => [renderSlot(_ctx.$slots, slots[`head(${String(field.key)})`] ? `head(${String(field.key)})` : "head()", mergeProps(scope, {
							selectAllRows: unref(selectedItemsController).setAll,
							clearSelected: unref(selectedItemsController).clear
						}), () => [createTextVNode(toDisplayString(unref(getTableFieldHeadLabel)(field)) + " ", 1), unref(sortController).isSortable.value && field.sortable ? (openBlock(), createElementBlock("span", _hoisted_1, toDisplayString(getSortLabel(field)), 1)) : createCommentVNode("", true)])])
					};
				})
			]), 1040, ["expanded-items"]);
		};
	}
});
//#endregion
export { BTh_default as a, BTbody_default as c, BThead_default as i, BTableLite_default as n, BTfoot_default as o, BTr_default as r, BTd_default as s, BTable_default as t };

//# sourceMappingURL=BTable-BZxX17YU.js.map