vs-datatable 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,2 @@
1
+ # vs-datatable
2
+ A lightweight Vue 3 datatable component with sorting, slots, and nested object support.
Binary file
package/dist/index.css ADDED
@@ -0,0 +1 @@
1
+ @media only screen and (min-width: 1199px){.pagination .page-item .page-link[data-v-126f4cdf]{padding:4px 8px!important;font-size:12px!important;line-height:1!important}}@media only screen and (max-width: 768px){.pagination .page-item .page-link[data-v-126f4cdf]{padding:4px 8px!important;font-size:10px!important;line-height:1!important}}.loader[data-v-6ad4d2c7]{position:relative;width:85px;height:50px;background-repeat:no-repeat;background-image:linear-gradient(#CC9933 50px,transparent 0),linear-gradient(#CC9933 50px,transparent 0),linear-gradient(#CC9933 50px,transparent 0),linear-gradient(#CC9933 50px,transparent 0),linear-gradient(#CC9933 50px,transparent 0),linear-gradient(#CC9933 50px,transparent 0);background-position:0px center,15px center,30px center,45px center,60px center,75px center,90px center;animation:rikSpikeRoll-6ad4d2c7 .65s linear infinite alternate}@keyframes rikSpikeRoll-6ad4d2c7{0%{background-size:10px 3px}16%{background-size:10px 50px,10px 3px,10px 3px,10px 3px,10px 3px,10px 3px}33%{background-size:10px 30px,10px 50px,10px 3px,10px 3px,10px 3px,10px 3px}50%{background-size:10px 10px,10px 30px,10px 50px,10px 3px,10px 3px,10px 3px}66%{background-size:10px 3px,10px 10px,10px 30px,10px 50px,10px 3px,10px 3px}83%{background-size:10px 3px,10px 3px,10px 10px,10px 30px,10px 50px,10px 3px}to{background-size:10px 3px,10px 3px,10px 3px,10px 10px,10px 30px,10px 50px}}.sort-container[data-v-48b15b64]{display:inline-flex;flex-direction:column;align-items:center;line-height:1}.sort-icon[data-v-48b15b64]{font-size:.62rem;color:#aaa;margin:-5px 0}.sort-icon.active-asc[data-v-48b15b64],.sort-icon.active-desc[data-v-48b15b64]{color:#daa520}.sort-badge[data-v-48b15b64]{font-size:.65rem;line-height:1;padding:.15rem .3rem;display:inline-flex;align-items:center;justify-content:center}.vs-table{border-collapse:separate;border-spacing:0}.vs-table thead{background-color:#f8f9fa}.vs-table thead th{font-weight:600;vertical-align:middle;padding:.75rem}.vs-table tbody tr{transition:background-color .2s ease}.vs-table tbody tr:hover{background-color:#e9ecef}.vs-table tbody tr td{padding:.65rem .75rem;vertical-align:middle}.vs-table .sort-icon{font-size:.75rem;vertical-align:middle}
@@ -0,0 +1,407 @@
1
+ import { defineComponent as H, computed as p, createElementBlock as i, openBlock as r, createElementVNode as o, createCommentVNode as k, normalizeClass as w, Fragment as R, renderList as L, toDisplayString as y, normalizeStyle as E, useAttrs as K, ref as A, resolveComponent as Q, createBlock as J, withCtx as W, renderSlot as M, createVNode as D, unref as X, withModifiers as Y, withDirectives as ee, vModelCheckbox as te, createTextVNode as se } from "vue";
2
+ import './index.css';const ae = { ref: "vsPagination" }, oe = ["id"], le = { class: "page-item" }, ne = ["disabled"], re = {
3
+ key: 0,
4
+ class: "page-item d-flex"
5
+ }, ie = {
6
+ key: 0,
7
+ class: "page-link disabled"
8
+ }, de = ["id", "onClick"], ce = {
9
+ key: 1,
10
+ class: "page-item d-flex"
11
+ }, ue = {
12
+ key: 0,
13
+ class: "page-link me-2 disabled"
14
+ }, pe = { class: "page-item" }, ve = ["disabled"], fe = /* @__PURE__ */ H({
15
+ __name: "VsPagination",
16
+ props: {
17
+ modelValue: {},
18
+ totalRecords: {},
19
+ rowsPerPage: {},
20
+ tablename: {},
21
+ maxVisible: {},
22
+ paginationClass: {}
23
+ },
24
+ emits: ["update:modelValue", "page-changed"],
25
+ setup(e, { emit: b }) {
26
+ const t = e, c = b, h = t.maxVisible ?? 3, d = p({
27
+ get: () => t.modelValue,
28
+ set: (m) => {
29
+ c("update:modelValue", m), c("page-changed", m);
30
+ }
31
+ }), x = p(() => d.value <= Math.floor(h / 2) ? 1 : d.value >= u.value - Math.floor(h / 2) ? Math.max(u.value - h + 1, 1) : d.value - Math.floor(h / 2)), $ = p(() => Math.min(x.value + h - 1, u.value)), u = p(() => Math.ceil(t.totalRecords / t.rowsPerPage)), P = p(() => {
32
+ const m = [];
33
+ for (let g = x.value; g <= $.value; g++)
34
+ m.push(g);
35
+ return m;
36
+ }), V = (m) => {
37
+ m >= 1 && m <= u.value && (d.value = m);
38
+ }, I = () => {
39
+ d.value > 1 && d.value--;
40
+ }, C = () => {
41
+ d.value < u.value && d.value++;
42
+ };
43
+ return (m, g) => (r(), i("div", ae, [
44
+ o("ul", {
45
+ class: "pagination pagination-sm mb-0 justify-content-center text-center",
46
+ id: e.tablename + "-paginate-parent"
47
+ }, [
48
+ o("li", le, [
49
+ o("button", {
50
+ onClick: I,
51
+ type: "button",
52
+ class: w([e.tablename + "-paginate-navigators page-link", { disabled: d.value === 1 }]),
53
+ disabled: d.value === 1
54
+ }, " << ", 10, ne)
55
+ ]),
56
+ x.value > 1 ? (r(), i("li", re, [
57
+ o("button", {
58
+ type: "button",
59
+ class: "page-link me-2",
60
+ onClick: g[0] || (g[0] = (_) => V(1))
61
+ }, "1"),
62
+ x.value > 2 ? (r(), i("span", ie, "...")) : k("", !0)
63
+ ])) : k("", !0),
64
+ (r(!0), i(R, null, L(P.value, (_) => (r(), i("li", {
65
+ key: _,
66
+ class: "page-item"
67
+ }, [
68
+ o("button", {
69
+ type: "button",
70
+ class: w([d.value === _ ? "active" : "", "page-link", e.tablename + "-paginate-button"]),
71
+ id: e.tablename + "-navigateButton-" + _,
72
+ onClick: (T) => V(_)
73
+ }, y(_), 11, de)
74
+ ]))), 128)),
75
+ $.value < u.value ? (r(), i("li", ce, [
76
+ $.value < u.value - 1 ? (r(), i("span", ue, "...")) : k("", !0),
77
+ o("button", {
78
+ type: "button",
79
+ class: "page-link",
80
+ onClick: g[1] || (g[1] = (_) => V(u.value))
81
+ }, y(u.value), 1)
82
+ ])) : k("", !0),
83
+ o("li", pe, [
84
+ o("button", {
85
+ onClick: C,
86
+ type: "button",
87
+ class: w([e.tablename + "-paginate-navigators page-link", { disabled: d.value === u.value }]),
88
+ disabled: d.value === u.value
89
+ }, " >> ", 10, ve)
90
+ ])
91
+ ], 8, oe)
92
+ ], 512));
93
+ }
94
+ }), G = (e, b) => {
95
+ const t = e.__vccOpts || e;
96
+ for (const [c, h] of b)
97
+ t[c] = h;
98
+ return t;
99
+ }, he = /* @__PURE__ */ G(fe, [["__scopeId", "data-v-126f4cdf"]]), me = { class: "flex-fill position-relative" }, ge = { class: "input-group" }, be = ["placeholder", "value"], _e = /* @__PURE__ */ H({
100
+ __name: "VsSearch",
101
+ props: {
102
+ modelValue: {},
103
+ placeholder: {}
104
+ },
105
+ emits: ["update:modelValue", "input-typed"],
106
+ setup(e, { emit: b }) {
107
+ const t = b, c = (h) => {
108
+ const d = h.target;
109
+ t("update:modelValue", d.value), t("input-typed", d.value);
110
+ };
111
+ return (h, d) => (r(), i("div", me, [
112
+ o("div", ge, [
113
+ d[0] || (d[0] = o("div", {
114
+ class: "input-group-text position-absolute top-0 bottom-0 bg-none border-0",
115
+ style: { "z-index": "1020" }
116
+ }, [
117
+ o("i", { class: "fa fa-search opacity-5" })
118
+ ], -1)),
119
+ o("input", {
120
+ type: "text",
121
+ class: "form-control ps-35px",
122
+ placeholder: e.placeholder,
123
+ value: e.modelValue,
124
+ onInput: c
125
+ }, null, 40, be)
126
+ ])
127
+ ]));
128
+ }
129
+ }), ke = /* @__PURE__ */ H({
130
+ __name: "Loader",
131
+ props: {
132
+ height: { default: "50px" }
133
+ },
134
+ setup(e) {
135
+ return (b, t) => (r(), i("div", null, [
136
+ o("div", {
137
+ class: "loader",
138
+ style: E({ height: e.height })
139
+ }, null, 4)
140
+ ]));
141
+ }
142
+ }), ye = /* @__PURE__ */ G(ke, [["__scopeId", "data-v-6ad4d2c7"]]), xe = (e, b = "") => `
143
+ <svg width="60pt" height="60pt" id="Layer__${e}" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 70 70">
144
+ <defs>
145
+ <linearGradient id="no-data__rfq_${e}" x1="40.1" y1="64.17" x2="40.1" y2="5.83" gradientUnits="userSpaceOnUse">
146
+ <stop offset="0" stop-color="#969698" stop-opacity="0.1" />
147
+ <stop offset="1" stop-color="#869ac0" stop-opacity="0.25" />
148
+ </linearGradient>
149
+ <linearGradient id="no-data__rfq-2_${e}" x1="176.51" y1="-169.09" x2="196.67" y2="-169.09" gradientTransform="matrix(0.73, 0, 0, -0.73, -125.67, -73.17)" gradientUnits="userSpaceOnUse">
150
+ <stop offset="0" stop-color="#969698" />
151
+ <stop offset="1" stop-color="#869ac0" />
152
+ </linearGradient>
153
+ <linearGradient id="no-data__rfq-3_${e}" x1="187.34" y1="-148.34" x2="227.34" y2="-148.34" xlink:href="#no-data__rfq-2_${e}" />
154
+ </defs>
155
+ <path d="M61.25,20.42H46.67V5.83Z" fill="#929aa5" opacity="0.5" style="isolation:isolate" />
156
+ <path d="M19,5.83H46.67L61.25,20.42V64.17H19ZM54,27H26.25V29.9H54Zm0,6.56H26.25v2.92H54ZM26.25,40.1H54V43H26.25Zm0,6.57H54v2.91H26.25Z" fill-rule="evenodd" fill="url(#no-data__rfq_${e})" />
157
+ <path d="M3,53.35,13.62,42.78l4.12,4.13L7.17,57.48,3,53.35Z" fill-rule="evenodd" fill="url(#no-data__rfq-2_${e})" />
158
+ <path d="M37.19,35A11.67,11.67,0,1,0,25.52,46.67,11.68,11.68,0,0,0,37.19,35Zm2.91,0A14.58,14.58,0,1,0,25.52,49.58,14.58,14.58,0,0,0,40.1,35Z" fill-rule="evenodd" fill="url(#no-data__rfq-3_${e})" />
159
+ </svg>
160
+ <div class="fs-5 fw-700 text-fmdqgray">${b}</div>
161
+ `, we = { class: "card-body p-4 vs-table-card-body" }, $e = {
162
+ key: 0,
163
+ class: "input-group mb-4"
164
+ }, Ve = { class: "flex-fill position-relative" }, Pe = { class: "input-group" }, Ce = {
165
+ ref: "tableResponsiveRef",
166
+ class: "table-responsive"
167
+ }, Oe = {
168
+ key: 0,
169
+ style: { width: "5%" }
170
+ }, Se = { class: "form-check mb-2px" }, Me = ["id", "checked"], Re = ["for"], Le = ["onClick"], He = { class: "d-inline-flex align-items-center gap-1" }, Ie = {
171
+ key: 0,
172
+ class: "sort-container flex-column"
173
+ }, Te = {
174
+ key: 1,
175
+ class: "badge bg-secondary sort-badge"
176
+ }, Be = { key: 0 }, Ze = {
177
+ colspan: "100%",
178
+ class: "text-center"
179
+ }, qe = { key: 1 }, Ue = {
180
+ colspan: "100%",
181
+ class: "text-center"
182
+ }, Ae = ["innerHTML"], De = ["onClick"], Ge = { class: "form-check mb-2px" }, Ne = ["id", "value"], ze = ["for"], Ee = { class: "d-md-flex align-items-center mt-1" }, je = {
183
+ key: 0,
184
+ class: "me-md-auto text-md-left text-center mb-2 mb-md-0"
185
+ }, Fe = {
186
+ key: 1,
187
+ class: "me-md-auto"
188
+ }, Ke = /* @__PURE__ */ H({
189
+ __name: "VsDataTable",
190
+ props: {
191
+ rows: { default: () => [] },
192
+ itemSelected: { default: null },
193
+ tablename: { default: "default-table" },
194
+ sort: {},
195
+ serverItemsLength: {},
196
+ serverOptions: { default: null },
197
+ showHeader: { type: Boolean, default: !0 },
198
+ headerText: { default: "" },
199
+ loading: { type: Boolean, default: !1 },
200
+ columns: {},
201
+ showSearch: { type: Boolean, default: !0 },
202
+ tableClass: {},
203
+ rowClass: {},
204
+ showRowEntries: { type: Boolean, default: !0 }
205
+ },
206
+ emits: ["update:itemSelected", "update:serverItemsLength", "update:serverOptions", "input-typed", "page-updated", "sort-changed", "row-click"],
207
+ setup(e, { emit: b }) {
208
+ const t = e, c = b, h = K(), d = p(() => !!h.onRowClick);
209
+ function x(s, l) {
210
+ return l.split(".").reduce((n, a) => n?.[a], s) ?? "";
211
+ }
212
+ const $ = (s) => t.serverOptions?.sort?.some((l) => l.field === s), u = (s) => {
213
+ const l = t.serverOptions?.sort?.find((n) => n.field === s);
214
+ return l ? l.priority ?? null : null;
215
+ }, P = (s) => t.serverOptions?.sort?.find((l) => l.field === s)?.order ?? null, V = p(() => {
216
+ const s = t.serverOptions?.sort ?? [];
217
+ if (!s.length) return t.rows;
218
+ const l = (n, a) => a.split(".").reduce((v, f) => v?.[f], n) ?? "";
219
+ return [...t.rows].sort((n, a) => {
220
+ for (const { field: v, order: f } of s) {
221
+ const q = l(n, v), U = l(a, v);
222
+ if (q !== U)
223
+ return f === "asc" ? q > U ? 1 : -1 : q < U ? 1 : -1;
224
+ }
225
+ return 0;
226
+ });
227
+ }), I = (s, l) => {
228
+ if (!t.serverOptions) return;
229
+ let n = [...t.serverOptions.sort || []];
230
+ const a = n.findIndex((v) => v.field === s);
231
+ l.shiftKey ? a === -1 ? n.push({ field: s, order: "asc" }) : n[a]?.order === "asc" ? n[a].order = "desc" : n.splice(a, 1) : a === -1 ? n = [{ field: s, order: "asc" }] : n[a]?.order === "asc" ? n = [{ field: s, order: "desc" }] : n = [], n = n.map((v, f) => ({ ...v, priority: f + 1 })), c("update:serverOptions", { ...t.serverOptions, sort: n }), c("sort-changed", { sort: n });
232
+ }, C = A(""), m = (s) => c("input-typed", s), g = A(10), _ = p({
233
+ get: () => t.serverOptions?.rowsPerPage ?? g.value,
234
+ set: (s) => {
235
+ t.serverOptions ? c("update:serverOptions", { ...t.serverOptions, rowsPerPage: s }) : g.value = s;
236
+ }
237
+ }), T = A(1), B = p({
238
+ get: () => t.serverItemsLength !== void 0 ? t.serverItemsLength : t.rows.length,
239
+ set: (s) => {
240
+ t.serverItemsLength !== void 0 && c("update:serverItemsLength", s);
241
+ }
242
+ }), O = p({
243
+ get: () => t.serverOptions?.page ?? T.value,
244
+ set: (s) => {
245
+ t.serverOptions ? c("update:serverOptions", { ...t.serverOptions, page: s }) : T.value = s;
246
+ }
247
+ }), j = (s) => {
248
+ t.serverOptions && c("update:serverOptions", { ...t.serverOptions, page: s }), c("page-updated", s);
249
+ }, Z = p(() => {
250
+ const s = t.serverOptions?.rowsPerPage ?? 10, l = (O.value - 1) * s + 1, n = Math.min(O.value * s, B.value);
251
+ return { start: l, end: n };
252
+ }), S = p({
253
+ get: () => t.itemSelected || [],
254
+ set: (s) => c("update:itemSelected", s)
255
+ }), N = p(() => t.itemSelected !== null), z = p(() => t.rows.length > 0 && S.value.length === t.rows.length), F = () => {
256
+ S.value = z.value ? [] : [...t.rows];
257
+ };
258
+ return (s, l) => {
259
+ const n = Q("card");
260
+ return r(), J(n, { class: "vs-table-card mb-3" }, {
261
+ default: W(() => [
262
+ o("div", we, [
263
+ e.showSearch ? (r(), i("div", $e, [
264
+ o("div", Ve, [
265
+ o("div", Pe, [
266
+ D(_e, {
267
+ modelValue: C.value,
268
+ "onUpdate:modelValue": l[0] || (l[0] = (a) => C.value = a),
269
+ onInputTyped: m,
270
+ placeholder: "Search products"
271
+ }, null, 8, ["modelValue"]),
272
+ l[4] || (l[4] = o("div", {
273
+ class: "input-group-text position-absolute top-0 bottom-0 bg-none border-0",
274
+ style: { "z-index": "1020" }
275
+ }, [
276
+ o("i", { class: "fa fa-search opacity-5" })
277
+ ], -1))
278
+ ])
279
+ ]),
280
+ M(s.$slots, "filterArea", {}, void 0, !0)
281
+ ])) : k("", !0),
282
+ o("div", Ce, [
283
+ o("table", {
284
+ class: w(["table table-hover text-nowrap vs-table", e.tableClass])
285
+ }, [
286
+ o("thead", null, [
287
+ o("tr", null, [
288
+ N.value ? (r(), i("th", Oe, [
289
+ o("div", Se, [
290
+ o("input", {
291
+ type: "checkbox",
292
+ class: "form-check-input",
293
+ id: e.tablename + "-main-checkbox",
294
+ checked: z.value,
295
+ onChange: F
296
+ }, null, 40, Me),
297
+ o("label", {
298
+ class: "form-check-label pt-1px",
299
+ for: e.tablename + "-main-checkbox"
300
+ }, null, 8, Re)
301
+ ])
302
+ ])) : k("", !0),
303
+ (r(!0), i(R, null, L(e.columns, (a) => (r(), i("th", {
304
+ key: a.field,
305
+ onClick: (v) => a.sortable ? I(a.field, v) : null,
306
+ style: E({ width: a.width + "%", cursor: a.sortable ? "pointer" : "default" }),
307
+ class: "border-top-0 pt-0 pb-2"
308
+ }, [
309
+ M(s.$slots, `header-${a.field}`, {}, () => [
310
+ o("div", He, [
311
+ o("span", null, y(a.label), 1),
312
+ a.sortable ? (r(), i("span", Ie, [
313
+ o("i", {
314
+ class: w(["fa fa-sort-up sort-icon", { "active-asc": $(a.field) && P(a.field) === "asc" }])
315
+ }, null, 2),
316
+ o("i", {
317
+ class: w(["fa fa-sort-down sort-icon", { "active-desc": $(a.field) && P(a.field) === "desc" }])
318
+ }, null, 2)
319
+ ])) : k("", !0),
320
+ u(a.field) !== null ? (r(), i("span", Te, y(u(a.field)), 1)) : k("", !0)
321
+ ])
322
+ ], !0)
323
+ ], 12, Le))), 128))
324
+ ])
325
+ ]),
326
+ o("tbody", null, [
327
+ e.loading ? (r(), i("tr", Be, [
328
+ o("td", Ze, [
329
+ D(ye)
330
+ ])
331
+ ])) : V.value.length ? (r(!0), i(R, { key: 2 }, L(V.value, (a, v) => (r(), i("tr", {
332
+ key: v,
333
+ class: w([e.rowClass, { "cursor-pointer": d.value }]),
334
+ onClick: (f) => s.$emit("row-click", a, v)
335
+ }, [
336
+ N.value ? (r(), i("td", {
337
+ key: 0,
338
+ onClick: l[2] || (l[2] = Y(() => {
339
+ }, ["stop"]))
340
+ }, [
341
+ o("div", Ge, [
342
+ ee(o("input", {
343
+ type: "checkbox",
344
+ class: "form-check-input",
345
+ id: e.tablename + "-checkbox-" + a.id,
346
+ value: a,
347
+ "onUpdate:modelValue": l[1] || (l[1] = (f) => S.value = f)
348
+ }, null, 8, Ne), [
349
+ [te, S.value]
350
+ ]),
351
+ o("label", {
352
+ class: "form-check-label pt-1px",
353
+ for: e.tablename + "-checkbox-" + a.id
354
+ }, null, 8, ze)
355
+ ])
356
+ ])) : k("", !0),
357
+ (r(!0), i(R, null, L(e.columns, (f) => (r(), i("td", {
358
+ key: f.field,
359
+ class: "align-middle"
360
+ }, [
361
+ M(s.$slots, `cell-${f.field}`, {
362
+ item: a,
363
+ value: x(a, f.field)
364
+ }, () => [
365
+ se(y(x(a, f.field)), 1)
366
+ ], !0)
367
+ ]))), 128))
368
+ ], 10, De))), 128)) : (r(), i("tr", qe, [
369
+ o("td", Ue, [
370
+ M(s.$slots, "no-data", {}, () => [
371
+ o("div", {
372
+ innerHTML: X(xe)("vs-table-no_data", "No data available")
373
+ }, null, 8, Ae)
374
+ ], !0)
375
+ ])
376
+ ]))
377
+ ])
378
+ ], 2)
379
+ ], 512),
380
+ o("div", Ee, [
381
+ e.showRowEntries ? (r(), i("div", je, " Showing " + y(Z.value.start < 1 ? 0 : Z.value.start) + " to " + y(Z.value.end) + " of " + y(B.value) + " entries ", 1)) : (r(), i("div", Fe)),
382
+ D(he, {
383
+ modelValue: O.value,
384
+ "onUpdate:modelValue": l[3] || (l[3] = (a) => O.value = a),
385
+ totalRecords: B.value,
386
+ rowsPerPage: _.value,
387
+ maxVisible: 3,
388
+ tablename: e.tablename,
389
+ class: "text-center",
390
+ onPageChanged: j
391
+ }, null, 8, ["modelValue", "totalRecords", "rowsPerPage", "tablename"])
392
+ ])
393
+ ])
394
+ ]),
395
+ _: 3
396
+ });
397
+ };
398
+ }
399
+ }), Qe = /* @__PURE__ */ G(Ke, [["__scopeId", "data-v-48b15b64"]]), We = {
400
+ install(e) {
401
+ e.component("VsDataTable", Qe);
402
+ }
403
+ };
404
+ export {
405
+ Qe as VsDataTable,
406
+ We as default
407
+ };
@@ -0,0 +1,21 @@
1
+ (function(b,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],e):(b=typeof globalThis<"u"?globalThis:b||self,e(b.VsDataTable={},b.Vue))})(this,(function(b,e){"use strict";var O=document.createElement("style");O.textContent=`@media only screen and (min-width: 1199px){.pagination .page-item .page-link[data-v-126f4cdf]{padding:4px 8px!important;font-size:12px!important;line-height:1!important}}@media only screen and (max-width: 768px){.pagination .page-item .page-link[data-v-126f4cdf]{padding:4px 8px!important;font-size:10px!important;line-height:1!important}}.loader[data-v-6ad4d2c7]{position:relative;width:85px;height:50px;background-repeat:no-repeat;background-image:linear-gradient(#CC9933 50px,transparent 0),linear-gradient(#CC9933 50px,transparent 0),linear-gradient(#CC9933 50px,transparent 0),linear-gradient(#CC9933 50px,transparent 0),linear-gradient(#CC9933 50px,transparent 0),linear-gradient(#CC9933 50px,transparent 0);background-position:0px center,15px center,30px center,45px center,60px center,75px center,90px center;animation:rikSpikeRoll-6ad4d2c7 .65s linear infinite alternate}@keyframes rikSpikeRoll-6ad4d2c7{0%{background-size:10px 3px}16%{background-size:10px 50px,10px 3px,10px 3px,10px 3px,10px 3px,10px 3px}33%{background-size:10px 30px,10px 50px,10px 3px,10px 3px,10px 3px,10px 3px}50%{background-size:10px 10px,10px 30px,10px 50px,10px 3px,10px 3px,10px 3px}66%{background-size:10px 3px,10px 10px,10px 30px,10px 50px,10px 3px,10px 3px}83%{background-size:10px 3px,10px 3px,10px 10px,10px 30px,10px 50px,10px 3px}to{background-size:10px 3px,10px 3px,10px 3px,10px 10px,10px 30px,10px 50px}}.sort-container[data-v-48b15b64]{display:inline-flex;flex-direction:column;align-items:center;line-height:1}.sort-icon[data-v-48b15b64]{font-size:.62rem;color:#aaa;margin:-5px 0}.sort-icon.active-asc[data-v-48b15b64],.sort-icon.active-desc[data-v-48b15b64]{color:#daa520}.sort-badge[data-v-48b15b64]{font-size:.65rem;line-height:1;padding:.15rem .3rem;display:inline-flex;align-items:center;justify-content:center}.vs-table{border-collapse:separate;border-spacing:0}.vs-table thead{background-color:#f8f9fa}.vs-table thead th{font-weight:600;vertical-align:middle;padding:.75rem}.vs-table tbody tr{transition:background-color .2s ease}.vs-table tbody tr:hover{background-color:#e9ecef}.vs-table tbody tr td{padding:.65rem .75rem;vertical-align:middle}.vs-table .sort-icon{font-size:.75rem;vertical-align:middle}
2
+ /*$vite$:1*/`,document.head.appendChild(O);const R={ref:"vsPagination"},D=["id"],T={class:"page-item"},H=["disabled"],I={key:0,class:"page-item d-flex"},q={key:0,class:"page-link disabled"},Z=["id","onClick"],U={key:1,class:"page-item d-flex"},A={key:0,class:"page-link me-2 disabled"},G={class:"page-item"},j=["disabled"],F=e.defineComponent({__name:"VsPagination",props:{modelValue:{},totalRecords:{},rowsPerPage:{},tablename:{},maxVisible:{},paginationClass:{}},emits:["update:modelValue","page-changed"],setup(t,{emit:x}){const a=t,i=x,m=a.maxVisible??3,r=e.computed({get:()=>a.modelValue,set:f=>{i("update:modelValue",f),i("page-changed",f)}}),u=e.computed(()=>r.value<=Math.floor(m/2)?1:r.value>=d.value-Math.floor(m/2)?Math.max(d.value-m+1,1):r.value-Math.floor(m/2)),k=e.computed(()=>Math.min(u.value+m-1,d.value)),d=e.computed(()=>Math.ceil(a.totalRecords/a.rowsPerPage)),y=e.computed(()=>{const f=[];for(let g=u.value;g<=k.value;g++)f.push(g);return f}),_=f=>{f>=1&&f<=d.value&&(r.value=f)},w=()=>{r.value>1&&r.value--},V=()=>{r.value<d.value&&r.value++};return(f,g)=>(e.openBlock(),e.createElementBlock("div",R,[e.createElementVNode("ul",{class:"pagination pagination-sm mb-0 justify-content-center text-center",id:t.tablename+"-paginate-parent"},[e.createElementVNode("li",T,[e.createElementVNode("button",{onClick:w,type:"button",class:e.normalizeClass([t.tablename+"-paginate-navigators page-link",{disabled:r.value===1}]),disabled:r.value===1}," << ",10,H)]),u.value>1?(e.openBlock(),e.createElementBlock("li",I,[e.createElementVNode("button",{type:"button",class:"page-link me-2",onClick:g[0]||(g[0]=h=>_(1))},"1"),u.value>2?(e.openBlock(),e.createElementBlock("span",q,"...")):e.createCommentVNode("",!0)])):e.createCommentVNode("",!0),(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(y.value,h=>(e.openBlock(),e.createElementBlock("li",{key:h,class:"page-item"},[e.createElementVNode("button",{type:"button",class:e.normalizeClass([r.value===h?"active":"","page-link",t.tablename+"-paginate-button"]),id:t.tablename+"-navigateButton-"+h,onClick:N=>_(h)},e.toDisplayString(h),11,Z)]))),128)),k.value<d.value?(e.openBlock(),e.createElementBlock("li",U,[k.value<d.value-1?(e.openBlock(),e.createElementBlock("span",A,"...")):e.createCommentVNode("",!0),e.createElementVNode("button",{type:"button",class:"page-link",onClick:g[1]||(g[1]=h=>_(d.value))},e.toDisplayString(d.value),1)])):e.createCommentVNode("",!0),e.createElementVNode("li",G,[e.createElementVNode("button",{onClick:V,type:"button",class:e.normalizeClass([t.tablename+"-paginate-navigators page-link",{disabled:r.value===d.value}]),disabled:r.value===d.value}," >> ",10,j)])],8,D)],512))}}),B=(t,x)=>{const a=t.__vccOpts||t;for(const[i,m]of x)a[i]=m;return a},K=B(F,[["__scopeId","data-v-126f4cdf"]]),Q={class:"flex-fill position-relative"},J={class:"input-group"},W=["placeholder","value"],X=e.defineComponent({__name:"VsSearch",props:{modelValue:{},placeholder:{}},emits:["update:modelValue","input-typed"],setup(t,{emit:x}){const a=x,i=m=>{const r=m.target;a("update:modelValue",r.value),a("input-typed",r.value)};return(m,r)=>(e.openBlock(),e.createElementBlock("div",Q,[e.createElementVNode("div",J,[r[0]||(r[0]=e.createElementVNode("div",{class:"input-group-text position-absolute top-0 bottom-0 bg-none border-0",style:{"z-index":"1020"}},[e.createElementVNode("i",{class:"fa fa-search opacity-5"})],-1)),e.createElementVNode("input",{type:"text",class:"form-control ps-35px",placeholder:t.placeholder,value:t.modelValue,onInput:i},null,40,W)])]))}}),Y=B(e.defineComponent({__name:"Loader",props:{height:{default:"50px"}},setup(t){return(x,a)=>(e.openBlock(),e.createElementBlock("div",null,[e.createElementVNode("div",{class:"loader",style:e.normalizeStyle({height:t.height})},null,4)]))}}),[["__scopeId","data-v-6ad4d2c7"]]),ee=(t,x="")=>`
3
+ <svg width="60pt" height="60pt" id="Layer__${t}" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 70 70">
4
+ <defs>
5
+ <linearGradient id="no-data__rfq_${t}" x1="40.1" y1="64.17" x2="40.1" y2="5.83" gradientUnits="userSpaceOnUse">
6
+ <stop offset="0" stop-color="#969698" stop-opacity="0.1" />
7
+ <stop offset="1" stop-color="#869ac0" stop-opacity="0.25" />
8
+ </linearGradient>
9
+ <linearGradient id="no-data__rfq-2_${t}" x1="176.51" y1="-169.09" x2="196.67" y2="-169.09" gradientTransform="matrix(0.73, 0, 0, -0.73, -125.67, -73.17)" gradientUnits="userSpaceOnUse">
10
+ <stop offset="0" stop-color="#969698" />
11
+ <stop offset="1" stop-color="#869ac0" />
12
+ </linearGradient>
13
+ <linearGradient id="no-data__rfq-3_${t}" x1="187.34" y1="-148.34" x2="227.34" y2="-148.34" xlink:href="#no-data__rfq-2_${t}" />
14
+ </defs>
15
+ <path d="M61.25,20.42H46.67V5.83Z" fill="#929aa5" opacity="0.5" style="isolation:isolate" />
16
+ <path d="M19,5.83H46.67L61.25,20.42V64.17H19ZM54,27H26.25V29.9H54Zm0,6.56H26.25v2.92H54ZM26.25,40.1H54V43H26.25Zm0,6.57H54v2.91H26.25Z" fill-rule="evenodd" fill="url(#no-data__rfq_${t})" />
17
+ <path d="M3,53.35,13.62,42.78l4.12,4.13L7.17,57.48,3,53.35Z" fill-rule="evenodd" fill="url(#no-data__rfq-2_${t})" />
18
+ <path d="M37.19,35A11.67,11.67,0,1,0,25.52,46.67,11.68,11.68,0,0,0,37.19,35Zm2.91,0A14.58,14.58,0,1,0,25.52,49.58,14.58,14.58,0,0,0,40.1,35Z" fill-rule="evenodd" fill="url(#no-data__rfq-3_${t})" />
19
+ </svg>
20
+ <div class="fs-5 fw-700 text-fmdqgray">${x}</div>
21
+ `,te={class:"card-body p-4 vs-table-card-body"},ae={key:0,class:"input-group mb-4"},oe={class:"flex-fill position-relative"},ne={class:"input-group"},le={ref:"tableResponsiveRef",class:"table-responsive"},se={key:0,style:{width:"5%"}},re={class:"form-check mb-2px"},ie=["id","checked"],de=["for"],ce=["onClick"],pe={class:"d-inline-flex align-items-center gap-1"},me={key:0,class:"sort-container flex-column"},fe={key:1,class:"badge bg-secondary sort-badge"},ge={key:0},xe={colspan:"100%",class:"text-center"},he={key:1},be={colspan:"100%",class:"text-center"},ue=["innerHTML"],ke=["onClick"],_e={class:"form-check mb-2px"},ye=["id","value"],Ve=["for"],Ee={class:"d-md-flex align-items-center mt-1"},Ce={key:0,class:"me-md-auto text-md-left text-center mb-2 mb-md-0"},Be={key:1,class:"me-md-auto"},z=B(e.defineComponent({__name:"VsDataTable",props:{rows:{default:()=>[]},itemSelected:{default:null},tablename:{default:"default-table"},sort:{},serverItemsLength:{},serverOptions:{default:null},showHeader:{type:Boolean,default:!0},headerText:{default:""},loading:{type:Boolean,default:!1},columns:{},showSearch:{type:Boolean,default:!0},tableClass:{},rowClass:{},showRowEntries:{type:Boolean,default:!0}},emits:["update:itemSelected","update:serverItemsLength","update:serverOptions","input-typed","page-updated","sort-changed","row-click"],setup(t,{emit:x}){const a=t,i=x,m=e.useAttrs(),r=e.computed(()=>!!m.onRowClick);function u(o,l){return l.split(".").reduce((s,n)=>s?.[n],o)??""}const k=o=>a.serverOptions?.sort?.some(l=>l.field===o),d=o=>{const l=a.serverOptions?.sort?.find(s=>s.field===o);return l?l.priority??null:null},y=o=>a.serverOptions?.sort?.find(l=>l.field===o)?.order??null,_=e.computed(()=>{const o=a.serverOptions?.sort??[];if(!o.length)return a.rows;const l=(s,n)=>n.split(".").reduce((c,p)=>c?.[p],s)??"";return[...a.rows].sort((s,n)=>{for(const{field:c,order:p}of o){const v=l(s,c),P=l(n,c);if(v!==P)return p==="asc"?v>P?1:-1:v<P?1:-1}return 0})}),w=(o,l)=>{if(!a.serverOptions)return;let s=[...a.serverOptions.sort||[]];const n=s.findIndex(c=>c.field===o);l.shiftKey?n===-1?s.push({field:o,order:"asc"}):s[n]?.order==="asc"?s[n].order="desc":s.splice(n,1):n===-1?s=[{field:o,order:"asc"}]:s[n]?.order==="asc"?s=[{field:o,order:"desc"}]:s=[],s=s.map((c,p)=>({...c,priority:p+1})),i("update:serverOptions",{...a.serverOptions,sort:s}),i("sort-changed",{sort:s})},V=e.ref(""),f=o=>i("input-typed",o),g=e.ref(10),h=e.computed({get:()=>a.serverOptions?.rowsPerPage??g.value,set:o=>{a.serverOptions?i("update:serverOptions",{...a.serverOptions,rowsPerPage:o}):g.value=o}}),N=e.ref(1),$=e.computed({get:()=>a.serverItemsLength!==void 0?a.serverItemsLength:a.rows.length,set:o=>{a.serverItemsLength!==void 0&&i("update:serverItemsLength",o)}}),E=e.computed({get:()=>a.serverOptions?.page??N.value,set:o=>{a.serverOptions?i("update:serverOptions",{...a.serverOptions,page:o}):N.value=o}}),Ne=o=>{a.serverOptions&&i("update:serverOptions",{...a.serverOptions,page:o}),i("page-updated",o)},S=e.computed(()=>{const o=a.serverOptions?.rowsPerPage??10,l=(E.value-1)*o+1,s=Math.min(E.value*o,$.value);return{start:l,end:s}}),C=e.computed({get:()=>a.itemSelected||[],set:o=>i("update:itemSelected",o)}),M=e.computed(()=>a.itemSelected!==null),L=e.computed(()=>a.rows.length>0&&C.value.length===a.rows.length),$e=()=>{C.value=L.value?[]:[...a.rows]};return(o,l)=>{const s=e.resolveComponent("card");return e.openBlock(),e.createBlock(s,{class:"vs-table-card mb-3"},{default:e.withCtx(()=>[e.createElementVNode("div",te,[t.showSearch?(e.openBlock(),e.createElementBlock("div",ae,[e.createElementVNode("div",oe,[e.createElementVNode("div",ne,[e.createVNode(X,{modelValue:V.value,"onUpdate:modelValue":l[0]||(l[0]=n=>V.value=n),onInputTyped:f,placeholder:"Search products"},null,8,["modelValue"]),l[4]||(l[4]=e.createElementVNode("div",{class:"input-group-text position-absolute top-0 bottom-0 bg-none border-0",style:{"z-index":"1020"}},[e.createElementVNode("i",{class:"fa fa-search opacity-5"})],-1))])]),e.renderSlot(o.$slots,"filterArea",{},void 0,!0)])):e.createCommentVNode("",!0),e.createElementVNode("div",le,[e.createElementVNode("table",{class:e.normalizeClass(["table table-hover text-nowrap vs-table",t.tableClass])},[e.createElementVNode("thead",null,[e.createElementVNode("tr",null,[M.value?(e.openBlock(),e.createElementBlock("th",se,[e.createElementVNode("div",re,[e.createElementVNode("input",{type:"checkbox",class:"form-check-input",id:t.tablename+"-main-checkbox",checked:L.value,onChange:$e},null,40,ie),e.createElementVNode("label",{class:"form-check-label pt-1px",for:t.tablename+"-main-checkbox"},null,8,de)])])):e.createCommentVNode("",!0),(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(t.columns,n=>(e.openBlock(),e.createElementBlock("th",{key:n.field,onClick:c=>n.sortable?w(n.field,c):null,style:e.normalizeStyle({width:n.width+"%",cursor:n.sortable?"pointer":"default"}),class:"border-top-0 pt-0 pb-2"},[e.renderSlot(o.$slots,`header-${n.field}`,{},()=>[e.createElementVNode("div",pe,[e.createElementVNode("span",null,e.toDisplayString(n.label),1),n.sortable?(e.openBlock(),e.createElementBlock("span",me,[e.createElementVNode("i",{class:e.normalizeClass(["fa fa-sort-up sort-icon",{"active-asc":k(n.field)&&y(n.field)==="asc"}])},null,2),e.createElementVNode("i",{class:e.normalizeClass(["fa fa-sort-down sort-icon",{"active-desc":k(n.field)&&y(n.field)==="desc"}])},null,2)])):e.createCommentVNode("",!0),d(n.field)!==null?(e.openBlock(),e.createElementBlock("span",fe,e.toDisplayString(d(n.field)),1)):e.createCommentVNode("",!0)])],!0)],12,ce))),128))])]),e.createElementVNode("tbody",null,[t.loading?(e.openBlock(),e.createElementBlock("tr",ge,[e.createElementVNode("td",xe,[e.createVNode(Y)])])):_.value.length?(e.openBlock(!0),e.createElementBlock(e.Fragment,{key:2},e.renderList(_.value,(n,c)=>(e.openBlock(),e.createElementBlock("tr",{key:c,class:e.normalizeClass([t.rowClass,{"cursor-pointer":r.value}]),onClick:p=>o.$emit("row-click",n,c)},[M.value?(e.openBlock(),e.createElementBlock("td",{key:0,onClick:l[2]||(l[2]=e.withModifiers(()=>{},["stop"]))},[e.createElementVNode("div",_e,[e.withDirectives(e.createElementVNode("input",{type:"checkbox",class:"form-check-input",id:t.tablename+"-checkbox-"+n.id,value:n,"onUpdate:modelValue":l[1]||(l[1]=p=>C.value=p)},null,8,ye),[[e.vModelCheckbox,C.value]]),e.createElementVNode("label",{class:"form-check-label pt-1px",for:t.tablename+"-checkbox-"+n.id},null,8,Ve)])])):e.createCommentVNode("",!0),(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(t.columns,p=>(e.openBlock(),e.createElementBlock("td",{key:p.field,class:"align-middle"},[e.renderSlot(o.$slots,`cell-${p.field}`,{item:n,value:u(n,p.field)},()=>[e.createTextVNode(e.toDisplayString(u(n,p.field)),1)],!0)]))),128))],10,ke))),128)):(e.openBlock(),e.createElementBlock("tr",he,[e.createElementVNode("td",be,[e.renderSlot(o.$slots,"no-data",{},()=>[e.createElementVNode("div",{innerHTML:e.unref(ee)("vs-table-no_data","No data available")},null,8,ue)],!0)])]))])],2)],512),e.createElementVNode("div",Ee,[t.showRowEntries?(e.openBlock(),e.createElementBlock("div",Ce," Showing "+e.toDisplayString(S.value.start<1?0:S.value.start)+" to "+e.toDisplayString(S.value.end)+" of "+e.toDisplayString($.value)+" entries ",1)):(e.openBlock(),e.createElementBlock("div",Be)),e.createVNode(K,{modelValue:E.value,"onUpdate:modelValue":l[3]||(l[3]=n=>E.value=n),totalRecords:$.value,rowsPerPage:h.value,maxVisible:3,tablename:t.tablename,class:"text-center",onPageChanged:Ne},null,8,["modelValue","totalRecords","rowsPerPage","tablename"])])])]),_:3})}}}),[["__scopeId","data-v-48b15b64"]]),we={install(t){t.component("VsDataTable",z)}};b.VsDataTable=z,b.default=we,Object.defineProperties(b,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}));
package/package.json ADDED
@@ -0,0 +1,74 @@
1
+ {
2
+ "name": "vs-datatable",
3
+ "version": "0.1.0",
4
+ "description": "A lightweight Vue 3 datatable component with sorting, slots, and nested object support.",
5
+ "type": "module",
6
+ "private": false,
7
+ "license": "MIT",
8
+ "author": "Oregunwa Segun",
9
+ "homepage": "https://github.com/oregs/vs-datatable",
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/oregs/vs-datatable.git"
13
+ },
14
+ "bugs": {
15
+ "url": "https://github.com/oregs/vs-datatable/issues"
16
+ },
17
+ "keywords": [
18
+ "vue",
19
+ "datatable",
20
+ "table",
21
+ "vue3",
22
+ "component"
23
+ ],
24
+ "main": "./dist/vs-datatable.umd.js",
25
+ "module": "./dist/vs-datatable.es.js",
26
+ "types": "./dist/index.d.ts",
27
+ "exports": {
28
+ ".": {
29
+ "import": "./dist/vs-datatable.es.js",
30
+ "require": "./dist/vs-datatable.umd.js"
31
+ },
32
+ "./style.css": "./dist/style.css",
33
+ "./style.scss": "./src/styles/index.scss"
34
+ },
35
+ "files": [
36
+ "dist",
37
+ "src/styles"
38
+ ],
39
+ "scripts": {
40
+ "dev": "vite",
41
+ "build": "pnpm run type-check && pnpm run build-only",
42
+ "preview": "vite preview",
43
+ "build-only": "vite build",
44
+ "type-check": "vue-tsc --build",
45
+ "lint": "eslint . --fix",
46
+ "format": "prettier --write src/"
47
+ },
48
+ "peerDependencies": {
49
+ "vue": "^3.2.0"
50
+ },
51
+ "devDependencies": {
52
+ "@tsconfig/node22": "^22.0.2",
53
+ "@types/jsdom": "^21.1.7",
54
+ "@types/node": "^22.16.5",
55
+ "@typescript-eslint/utils": "^8.44.1",
56
+ "@vitejs/plugin-vue": "^6.0.1",
57
+ "@vitest/eslint-plugin": "^1.3.13",
58
+ "@vue/eslint-config-prettier": "^10.2.0",
59
+ "@vue/eslint-config-typescript": "^14.6.0",
60
+ "@vue/tsconfig": "^0.8.1",
61
+ "eslint": "^9.36.0",
62
+ "eslint-plugin-vue": "^10.5.0",
63
+ "sass-embedded": "^1.93.2",
64
+ "typescript": "~5.8.0",
65
+ "vite": "^7.0.6",
66
+ "vite-plugin-lib-inject-css": "^2.2.2",
67
+ "vitest": "^3.2.4",
68
+ "vue-tsc": "^3.0.4"
69
+ },
70
+ "dependencies": {
71
+ "@fortawesome/fontawesome-free": "^7.0.1",
72
+ "bootstrap": "^5.3.8"
73
+ }
74
+ }
@@ -0,0 +1,7 @@
1
+ // 1. Override Bootstrap variables BEFORE importing
2
+ $primary: #4CAF50; // Example: change primary color (green)
3
+ $table-cell-padding-y: 0.5rem;
4
+ $table-cell-padding-x: 0.75rem;
5
+
6
+ // 2. Import all Bootstrap
7
+ @import "bootstrap/scss/bootstrap";
@@ -0,0 +1,2 @@
1
+ @import "bootstrap/scss/bootstrap";
2
+ @import "./datatable.scss";
@@ -0,0 +1,40 @@
1
+ // Import only what you need from bootstrap (optional, leaner)
2
+ @import "bootstrap/scss/functions";
3
+ @import "bootstrap/scss/variables";
4
+ @import "bootstrap/scss/mixins";
5
+
6
+ // Example custom styles for the table
7
+ .vs-table {
8
+ border-collapse: separate;
9
+ border-spacing: 0;
10
+
11
+ thead {
12
+ background-color: $gray-100;
13
+ th {
14
+ font-weight: 600;
15
+ vertical-align: middle;
16
+ padding: 0.75rem;
17
+ }
18
+ }
19
+
20
+ tbody {
21
+ tr {
22
+ transition: background-color 0.2s ease;
23
+
24
+ &:hover {
25
+ background-color: $gray-200;
26
+ }
27
+
28
+ td {
29
+ padding: 0.65rem 0.75rem;
30
+ vertical-align: middle;
31
+ }
32
+ }
33
+ }
34
+
35
+ // Example: custom sort icon
36
+ .sort-icon {
37
+ font-size: 0.75rem;
38
+ vertical-align: middle;
39
+ }
40
+ }