tablevu 0.3.0-beta.2 → 0.3.0-beta.3

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.
@@ -85,6 +85,7 @@
85
85
  Ready: 0,
86
86
  Loading: 1
87
87
  };
88
+
88
89
  const tablevu = {
89
90
  props: {
90
91
  settings: { type: Object, default: null },
@@ -92,14 +93,13 @@
92
93
  group: { type: [String, Object] },
93
94
  search: { type: String },
94
95
  filter: { type: [Array, Object] },
95
- command: { type: Array, default: () => [] },
96
96
  rowid: { type: String },
97
97
  onRowClick: { type: Function },
98
98
  onRowDblClick: { type: Function },
99
99
  class: { type: String, default: 'table' },
100
100
  style: { type: String, default: null }
101
101
  },
102
- emits: ['onRowClick', 'onRowDblClick'],
102
+ emits: ['onRowClick', 'onRowDblClick', 'selectionChange', 'columnVisibilityChange'],
103
103
  setup(props, { attrs, slots, emit, expose }) {
104
104
  let rows = [];
105
105
  let rowg = [];
@@ -109,16 +109,16 @@
109
109
  const spec = vue.reactive({
110
110
  caption: null,
111
111
  group: {
112
- value: (props.settings && props.settings.group) ? props.settings.group.value : props.group ? props.group : null,
113
- content: (props.settings && props.settings.group) ? props.settings.group.content : null,
112
+ value: (props.settings && props.settings.group) ? props.settings.group.value : props.group ? props.group : undefined,
113
+ content: (props.settings && props.settings.group) ? props.settings.group.content : undefined,
114
114
  expandAll: true,
115
115
  class: 'table-light'
116
116
  },
117
117
  page: {
118
118
  count: 0,
119
- size: (props.settings && props.settings.page) ? props.settings.page.size : 0,
119
+ size: (props.settings && props.settings.page) ? (props.settings.page.size || 0) : 0,
120
120
  current: 0,
121
- type: null
121
+ type: undefined
122
122
  },
123
123
  sort: (props.settings && props.settings.sort) ? props.settings.sort : [],
124
124
  columns: (props.settings && props.settings.columns) ? props.settings.columns : [],
@@ -131,7 +131,11 @@
131
131
  time: null,
132
132
  search: null,
133
133
  filter: null,
134
- onData: (props.settings && props.settings.onData) ? props.settings.onData : undefined
134
+ onData: (props.settings && props.settings.onData) ? props.settings.onData : undefined,
135
+ selectedRows: [],
136
+ columnWidths: {},
137
+ columnOrder: [],
138
+ columnVisibility: {}
135
139
  });
136
140
  if (props.data) {
137
141
  if (Array.isArray(props.data)) {
@@ -167,32 +171,6 @@
167
171
  spec.filter = null;
168
172
  refresh();
169
173
  }, { deep: true });
170
- vue.watch(() => props.command, (n, o) => {
171
- if (n && n.length > 0) {
172
- const c = props.command[n.length - 1];
173
- if (c && c.name) {
174
- switch (c.name.toLowerCase()) {
175
- case 'refresh':
176
- refresh();
177
- break;
178
- case 'first':
179
- first();
180
- break;
181
- case 'prior':
182
- prior();
183
- break;
184
- case 'next':
185
- next();
186
- break;
187
- case 'last':
188
- last();
189
- break;
190
- default: console.log('Unknown command');
191
- }
192
- }
193
- props.command.length = 0;
194
- }
195
- }, { deep: true });
196
174
  function prepareGroup(g, r) {
197
175
  grps = [];
198
176
  rowg = [];
@@ -231,28 +209,26 @@
231
209
  rowg.push(n);
232
210
  }
233
211
  }
234
- function first() { page(1); }
212
+ function first() { loadPage(1); }
235
213
  function prior() {
236
214
  if (spec.page.current > 1) {
237
- page(spec.page.current - 1);
215
+ loadPage(spec.page.current - 1);
238
216
  }
239
217
  else {
240
- page(spec.page.current);
218
+ loadPage(spec.page.current);
241
219
  }
242
220
  }
243
- function next() { page(spec.page.current + 1); }
244
- function last() { page(spec.page.count); }
245
- function go() {
246
- let p;
247
- let g = spec.page.current;
248
- do {
249
- p = prompt(undefined, String(spec.page.current));
250
- g = parseInt(p || '0');
251
- } while (p && isNaN(g));
252
- if (g && g > 0 && g != spec.page.current)
253
- page(g);
221
+ function next() { loadPage(spec.page.current + 1); }
222
+ function last() { loadPage(spec.page.count); }
223
+ // Navigate to specific page number
224
+ function page(currentPage) {
225
+ if (currentPage < 1)
226
+ currentPage = 1;
227
+ if (currentPage > spec.page.count && spec.page.count > 0)
228
+ currentPage = spec.page.count;
229
+ loadPage(currentPage);
254
230
  }
255
- function refresh() { page(spec.page.current); }
231
+ function refresh() { loadPage(spec.page.current); }
256
232
  function orderby(ind, dir) {
257
233
  if (spec.sort && spec.sort.length > 0) {
258
234
  let l = spec.sort.findIndex(f => f.index == ind);
@@ -276,9 +252,10 @@
276
252
  else {
277
253
  spec.sort.push({ index: ind, dir: dir ? dir : null });
278
254
  }
279
- page(spec.page.current);
255
+ loadPage(spec.page.current);
280
256
  }
281
- function page(currentPage) {
257
+ // Internal load function (alias for adapter call)
258
+ function loadPage(currentPage) {
282
259
  let dat = null;
283
260
  if (props.data) {
284
261
  if (Array.isArray(props.data))
@@ -288,8 +265,9 @@
288
265
  return;
289
266
  spec.status = TablevuStatus.Loading;
290
267
  if (adapter) {
268
+ const pageSize = spec.page.size || 20;
291
269
  adapter({
292
- pageSize: spec.page.size,
270
+ pageSize,
293
271
  currPage: currentPage,
294
272
  sort: spec.sort,
295
273
  cols: spec.columns,
@@ -303,7 +281,7 @@
303
281
  const groupValue = spec.group.value;
304
282
  if (groupValue && (typeof groupValue == 'string' || typeof groupValue == 'number' || typeof groupValue == 'bigint' || (typeof groupValue == 'object' && groupValue.value)))
305
283
  prepareGroup(spec.group, rows);
306
- spec.page.count = (ada.count > 0 && spec.page.size > 0) ? Math.ceil(ada.count / spec.page.size) : 0;
284
+ spec.page.count = (ada.count > 0 && pageSize > 0) ? Math.ceil(ada.count / pageSize) : 0;
307
285
  spec.page.current = currentPage;
308
286
  spec.status = TablevuStatus.Ready;
309
287
  spec.time = Date.now();
@@ -365,8 +343,8 @@
365
343
  o.style['text-align'] = col.align;
366
344
  if (col.width)
367
345
  o.style['max-width'] = col.width;
368
- const f = col.render(row);
369
- return vue.h('td', o, f);
346
+ const f = col.render?.(row) ?? '';
347
+ return vue.h('td', { ...o, innerHTML: f });
370
348
  }
371
349
  function renderGroup(grp) {
372
350
  const b = vue.h('button', {
@@ -425,6 +403,10 @@
425
403
  }
426
404
  };
427
405
  }
406
+ // Selection
407
+ if (spec.selectedRows.some(s => s[props.rowid || 'id'] === row[props.rowid || 'id'])) {
408
+ o.class = (o.class || '') + ' selected';
409
+ }
428
410
  return vue.h('tr', o, r);
429
411
  }
430
412
  function renderHeader() {
@@ -475,7 +457,10 @@
475
457
  else
476
458
  a = vue.h('a', { href: '#', onClick: (event) => { orderby(i); event.preventDefault(); }, style: cy }, cl);
477
459
  if (spec.columns[i].filter) ;
478
- ar.push(vue.h('th', { colspan: null, style: ch }, [a, f]));
460
+ ar.push(vue.h('th', {
461
+ colspan: null,
462
+ style: ch
463
+ }, [a, f]));
479
464
  }
480
465
  const tr = vue.h('tr', {}, ar);
481
466
  return [tr];
@@ -503,14 +488,34 @@
503
488
  }
504
489
  }
505
490
  }
491
+ else if (spec.settings?.emptyMessage) {
492
+ dr.push(vue.h('tr', {}, vue.h('td', { colspan: spec.columns.length, style: { textAlign: 'center', padding: '2rem', color: '#666' } }, spec.settings.emptyMessage)));
493
+ }
506
494
  return dr;
507
495
  }
496
+ // Prompt user for page number and navigate
497
+ function goToPage() {
498
+ const input = prompt('Page number:', String(spec.page.current));
499
+ if (input) {
500
+ const pageNum = parseInt(input, 10);
501
+ if (!isNaN(pageNum) && pageNum > 0 && pageNum !== spec.page.current) {
502
+ page(pageNum);
503
+ }
504
+ }
505
+ }
506
+ function makeHandler(fn) {
507
+ return (e) => {
508
+ e.preventDefault();
509
+ e.stopPropagation();
510
+ fn();
511
+ };
512
+ }
508
513
  function renderFooter() {
509
- const fr = vue.h('button', { class: spec.footer.button.class, style: 'font: initial; margin-right: .5rem', onClick: first, disabled: spec.page.current == 1 }, '◀◀');
510
- const ls = vue.h('button', { class: spec.footer.button.class, style: 'font: initial; margin-right: .5rem', onClick: last, disabled: spec.page.count == 0 || spec.page.current == spec.page.count }, '▶▶');
511
- const pg = vue.h('button', { class: spec.footer.button.class, style: 'font: initial; margin-right: .5rem', onClick: go }, spec.page.current + (spec.page.count > 0 ? (' / ' + spec.page.count) : ''));
512
- const pr = vue.h('button', { class: spec.footer.button.class, style: 'font: initial; margin-right: .5rem', onClick: prior, disabled: spec.page.current == 1 }, '◀');
513
- const nx = vue.h('button', { class: spec.footer.button.class, style: 'font: initial; margin-right: .5rem', onClick: next, disabled: spec.page.count > 0 && spec.page.current == spec.page.count }, '▶');
514
+ const fr = vue.h('button', { class: spec.footer.button.class, style: 'font: initial; margin-right: .5rem', onClick: makeHandler(first), disabled: spec.page.current == 1 }, '◀◀');
515
+ const ls = vue.h('button', { class: spec.footer.button.class, style: 'font: initial; margin-right: .5rem', onClick: makeHandler(last), disabled: spec.page.count == 0 || spec.page.current == spec.page.count }, '▶▶');
516
+ const pg = vue.h('button', { class: spec.footer.button.class, style: 'font: initial; margin-right: .5rem', onClick: makeHandler(goToPage) }, spec.page.current + (spec.page.count > 0 ? (' / ' + spec.page.count) : ''));
517
+ const pr = vue.h('button', { class: spec.footer.button.class, style: 'font: initial; margin-right: .5rem', onClick: makeHandler(prior), disabled: spec.page.current == 1 }, '◀');
518
+ const nx = vue.h('button', { class: spec.footer.button.class, style: 'font: initial; margin-right: .5rem', onClick: makeHandler(next), disabled: spec.page.count > 0 && spec.page.current == spec.page.count }, '▶');
514
519
  const td = vue.h('td', { colspan: spec.columns.length, align: 'center' }, [fr, pr, pg, nx, ls]);
515
520
  const tr = vue.h('tr', {}, [td]);
516
521
  return [tr];
@@ -518,19 +523,41 @@
518
523
  function renderCaption() {
519
524
  return null;
520
525
  }
526
+ // Initialize column metadata
521
527
  if (spec.columns.length == 0) {
522
528
  console.error('Columns not defined !');
523
529
  }
524
- for (let i = 0; i < spec.columns.length; i++)
530
+ for (let i = 0; i < spec.columns.length; i++) {
525
531
  if (spec.columns[i].name && spec.columns[i].name.indexOf('.') > -1) {
526
532
  spec.columns[i].depth = spec.columns[i].name.split('.');
527
533
  }
528
- page(1);
534
+ // Initialize visibility
535
+ if (spec.columns[i].visible === undefined) {
536
+ spec.columns[i].visible = true;
537
+ spec.columnVisibility[spec.columns[i].name] = true;
538
+ }
539
+ }
540
+ loadPage(1);
541
+ // Expose methods for external access via ref
542
+ expose({
543
+ first,
544
+ prior,
545
+ next,
546
+ last,
547
+ page,
548
+ refresh,
549
+ orderby,
550
+ getSelectedRows: () => spec.selectedRows,
551
+ setSelectedRows: (rows) => { spec.selectedRows = rows; }
552
+ });
529
553
  vue.onMounted(() => {
530
554
  // mounted hook
531
555
  });
532
556
  return {
533
- spec, renderHeader, renderBody, renderFooter, renderCaption
557
+ spec, renderHeader, renderBody, renderFooter, renderCaption,
558
+ first, prior, next, last, page, refresh, orderby,
559
+ getSelectedRows: () => spec.selectedRows,
560
+ setSelectedRows: (rows) => { spec.selectedRows = rows; }
534
561
  };
535
562
  },
536
563
  render(props) {
@@ -1077,7 +1104,6 @@
1077
1104
  };
1078
1105
 
1079
1106
  exports.TableVu = tablevu;
1080
- exports.TablevuStatus = TablevuStatus;
1081
1107
  exports.adaptArray = adaptArray;
1082
1108
  exports.buildFilter = toODataFilter;
1083
1109
  exports.odata = odata;
@@ -81,6 +81,7 @@ const TablevuStatus = {
81
81
  Ready: 0,
82
82
  Loading: 1
83
83
  };
84
+
84
85
  const tablevu = {
85
86
  props: {
86
87
  settings: { type: Object, default: null },
@@ -88,14 +89,13 @@ const tablevu = {
88
89
  group: { type: [String, Object] },
89
90
  search: { type: String },
90
91
  filter: { type: [Array, Object] },
91
- command: { type: Array, default: () => [] },
92
92
  rowid: { type: String },
93
93
  onRowClick: { type: Function },
94
94
  onRowDblClick: { type: Function },
95
95
  class: { type: String, default: 'table' },
96
96
  style: { type: String, default: null }
97
97
  },
98
- emits: ['onRowClick', 'onRowDblClick'],
98
+ emits: ['onRowClick', 'onRowDblClick', 'selectionChange', 'columnVisibilityChange'],
99
99
  setup(props, { attrs, slots, emit, expose }) {
100
100
  let rows = [];
101
101
  let rowg = [];
@@ -105,16 +105,16 @@ const tablevu = {
105
105
  const spec = reactive({
106
106
  caption: null,
107
107
  group: {
108
- value: (props.settings && props.settings.group) ? props.settings.group.value : props.group ? props.group : null,
109
- content: (props.settings && props.settings.group) ? props.settings.group.content : null,
108
+ value: (props.settings && props.settings.group) ? props.settings.group.value : props.group ? props.group : undefined,
109
+ content: (props.settings && props.settings.group) ? props.settings.group.content : undefined,
110
110
  expandAll: true,
111
111
  class: 'table-light'
112
112
  },
113
113
  page: {
114
114
  count: 0,
115
- size: (props.settings && props.settings.page) ? props.settings.page.size : 0,
115
+ size: (props.settings && props.settings.page) ? (props.settings.page.size || 0) : 0,
116
116
  current: 0,
117
- type: null
117
+ type: undefined
118
118
  },
119
119
  sort: (props.settings && props.settings.sort) ? props.settings.sort : [],
120
120
  columns: (props.settings && props.settings.columns) ? props.settings.columns : [],
@@ -127,7 +127,11 @@ const tablevu = {
127
127
  time: null,
128
128
  search: null,
129
129
  filter: null,
130
- onData: (props.settings && props.settings.onData) ? props.settings.onData : undefined
130
+ onData: (props.settings && props.settings.onData) ? props.settings.onData : undefined,
131
+ selectedRows: [],
132
+ columnWidths: {},
133
+ columnOrder: [],
134
+ columnVisibility: {}
131
135
  });
132
136
  if (props.data) {
133
137
  if (Array.isArray(props.data)) {
@@ -163,32 +167,6 @@ const tablevu = {
163
167
  spec.filter = null;
164
168
  refresh();
165
169
  }, { deep: true });
166
- watch(() => props.command, (n, o) => {
167
- if (n && n.length > 0) {
168
- const c = props.command[n.length - 1];
169
- if (c && c.name) {
170
- switch (c.name.toLowerCase()) {
171
- case 'refresh':
172
- refresh();
173
- break;
174
- case 'first':
175
- first();
176
- break;
177
- case 'prior':
178
- prior();
179
- break;
180
- case 'next':
181
- next();
182
- break;
183
- case 'last':
184
- last();
185
- break;
186
- default: console.log('Unknown command');
187
- }
188
- }
189
- props.command.length = 0;
190
- }
191
- }, { deep: true });
192
170
  function prepareGroup(g, r) {
193
171
  grps = [];
194
172
  rowg = [];
@@ -227,28 +205,26 @@ const tablevu = {
227
205
  rowg.push(n);
228
206
  }
229
207
  }
230
- function first() { page(1); }
208
+ function first() { loadPage(1); }
231
209
  function prior() {
232
210
  if (spec.page.current > 1) {
233
- page(spec.page.current - 1);
211
+ loadPage(spec.page.current - 1);
234
212
  }
235
213
  else {
236
- page(spec.page.current);
214
+ loadPage(spec.page.current);
237
215
  }
238
216
  }
239
- function next() { page(spec.page.current + 1); }
240
- function last() { page(spec.page.count); }
241
- function go() {
242
- let p;
243
- let g = spec.page.current;
244
- do {
245
- p = prompt(undefined, String(spec.page.current));
246
- g = parseInt(p || '0');
247
- } while (p && isNaN(g));
248
- if (g && g > 0 && g != spec.page.current)
249
- page(g);
217
+ function next() { loadPage(spec.page.current + 1); }
218
+ function last() { loadPage(spec.page.count); }
219
+ // Navigate to specific page number
220
+ function page(currentPage) {
221
+ if (currentPage < 1)
222
+ currentPage = 1;
223
+ if (currentPage > spec.page.count && spec.page.count > 0)
224
+ currentPage = spec.page.count;
225
+ loadPage(currentPage);
250
226
  }
251
- function refresh() { page(spec.page.current); }
227
+ function refresh() { loadPage(spec.page.current); }
252
228
  function orderby(ind, dir) {
253
229
  if (spec.sort && spec.sort.length > 0) {
254
230
  let l = spec.sort.findIndex(f => f.index == ind);
@@ -272,9 +248,10 @@ const tablevu = {
272
248
  else {
273
249
  spec.sort.push({ index: ind, dir: dir ? dir : null });
274
250
  }
275
- page(spec.page.current);
251
+ loadPage(spec.page.current);
276
252
  }
277
- function page(currentPage) {
253
+ // Internal load function (alias for adapter call)
254
+ function loadPage(currentPage) {
278
255
  let dat = null;
279
256
  if (props.data) {
280
257
  if (Array.isArray(props.data))
@@ -284,8 +261,9 @@ const tablevu = {
284
261
  return;
285
262
  spec.status = TablevuStatus.Loading;
286
263
  if (adapter) {
264
+ const pageSize = spec.page.size || 20;
287
265
  adapter({
288
- pageSize: spec.page.size,
266
+ pageSize,
289
267
  currPage: currentPage,
290
268
  sort: spec.sort,
291
269
  cols: spec.columns,
@@ -299,7 +277,7 @@ const tablevu = {
299
277
  const groupValue = spec.group.value;
300
278
  if (groupValue && (typeof groupValue == 'string' || typeof groupValue == 'number' || typeof groupValue == 'bigint' || (typeof groupValue == 'object' && groupValue.value)))
301
279
  prepareGroup(spec.group, rows);
302
- spec.page.count = (ada.count > 0 && spec.page.size > 0) ? Math.ceil(ada.count / spec.page.size) : 0;
280
+ spec.page.count = (ada.count > 0 && pageSize > 0) ? Math.ceil(ada.count / pageSize) : 0;
303
281
  spec.page.current = currentPage;
304
282
  spec.status = TablevuStatus.Ready;
305
283
  spec.time = Date.now();
@@ -361,8 +339,8 @@ const tablevu = {
361
339
  o.style['text-align'] = col.align;
362
340
  if (col.width)
363
341
  o.style['max-width'] = col.width;
364
- const f = col.render(row);
365
- return h('td', o, f);
342
+ const f = col.render?.(row) ?? '';
343
+ return h('td', { ...o, innerHTML: f });
366
344
  }
367
345
  function renderGroup(grp) {
368
346
  const b = h('button', {
@@ -421,6 +399,10 @@ const tablevu = {
421
399
  }
422
400
  };
423
401
  }
402
+ // Selection
403
+ if (spec.selectedRows.some(s => s[props.rowid || 'id'] === row[props.rowid || 'id'])) {
404
+ o.class = (o.class || '') + ' selected';
405
+ }
424
406
  return h('tr', o, r);
425
407
  }
426
408
  function renderHeader() {
@@ -471,7 +453,10 @@ const tablevu = {
471
453
  else
472
454
  a = h('a', { href: '#', onClick: (event) => { orderby(i); event.preventDefault(); }, style: cy }, cl);
473
455
  if (spec.columns[i].filter) ;
474
- ar.push(h('th', { colspan: null, style: ch }, [a, f]));
456
+ ar.push(h('th', {
457
+ colspan: null,
458
+ style: ch
459
+ }, [a, f]));
475
460
  }
476
461
  const tr = h('tr', {}, ar);
477
462
  return [tr];
@@ -499,14 +484,34 @@ const tablevu = {
499
484
  }
500
485
  }
501
486
  }
487
+ else if (spec.settings?.emptyMessage) {
488
+ dr.push(h('tr', {}, h('td', { colspan: spec.columns.length, style: { textAlign: 'center', padding: '2rem', color: '#666' } }, spec.settings.emptyMessage)));
489
+ }
502
490
  return dr;
503
491
  }
492
+ // Prompt user for page number and navigate
493
+ function goToPage() {
494
+ const input = prompt('Page number:', String(spec.page.current));
495
+ if (input) {
496
+ const pageNum = parseInt(input, 10);
497
+ if (!isNaN(pageNum) && pageNum > 0 && pageNum !== spec.page.current) {
498
+ page(pageNum);
499
+ }
500
+ }
501
+ }
502
+ function makeHandler(fn) {
503
+ return (e) => {
504
+ e.preventDefault();
505
+ e.stopPropagation();
506
+ fn();
507
+ };
508
+ }
504
509
  function renderFooter() {
505
- const fr = h('button', { class: spec.footer.button.class, style: 'font: initial; margin-right: .5rem', onClick: first, disabled: spec.page.current == 1 }, '◀◀');
506
- const ls = h('button', { class: spec.footer.button.class, style: 'font: initial; margin-right: .5rem', onClick: last, disabled: spec.page.count == 0 || spec.page.current == spec.page.count }, '▶▶');
507
- const pg = h('button', { class: spec.footer.button.class, style: 'font: initial; margin-right: .5rem', onClick: go }, spec.page.current + (spec.page.count > 0 ? (' / ' + spec.page.count) : ''));
508
- const pr = h('button', { class: spec.footer.button.class, style: 'font: initial; margin-right: .5rem', onClick: prior, disabled: spec.page.current == 1 }, '◀');
509
- const nx = h('button', { class: spec.footer.button.class, style: 'font: initial; margin-right: .5rem', onClick: next, disabled: spec.page.count > 0 && spec.page.current == spec.page.count }, '▶');
510
+ const fr = h('button', { class: spec.footer.button.class, style: 'font: initial; margin-right: .5rem', onClick: makeHandler(first), disabled: spec.page.current == 1 }, '◀◀');
511
+ const ls = h('button', { class: spec.footer.button.class, style: 'font: initial; margin-right: .5rem', onClick: makeHandler(last), disabled: spec.page.count == 0 || spec.page.current == spec.page.count }, '▶▶');
512
+ const pg = h('button', { class: spec.footer.button.class, style: 'font: initial; margin-right: .5rem', onClick: makeHandler(goToPage) }, spec.page.current + (spec.page.count > 0 ? (' / ' + spec.page.count) : ''));
513
+ const pr = h('button', { class: spec.footer.button.class, style: 'font: initial; margin-right: .5rem', onClick: makeHandler(prior), disabled: spec.page.current == 1 }, '◀');
514
+ const nx = h('button', { class: spec.footer.button.class, style: 'font: initial; margin-right: .5rem', onClick: makeHandler(next), disabled: spec.page.count > 0 && spec.page.current == spec.page.count }, '▶');
510
515
  const td = h('td', { colspan: spec.columns.length, align: 'center' }, [fr, pr, pg, nx, ls]);
511
516
  const tr = h('tr', {}, [td]);
512
517
  return [tr];
@@ -514,19 +519,41 @@ const tablevu = {
514
519
  function renderCaption() {
515
520
  return null;
516
521
  }
522
+ // Initialize column metadata
517
523
  if (spec.columns.length == 0) {
518
524
  console.error('Columns not defined !');
519
525
  }
520
- for (let i = 0; i < spec.columns.length; i++)
526
+ for (let i = 0; i < spec.columns.length; i++) {
521
527
  if (spec.columns[i].name && spec.columns[i].name.indexOf('.') > -1) {
522
528
  spec.columns[i].depth = spec.columns[i].name.split('.');
523
529
  }
524
- page(1);
530
+ // Initialize visibility
531
+ if (spec.columns[i].visible === undefined) {
532
+ spec.columns[i].visible = true;
533
+ spec.columnVisibility[spec.columns[i].name] = true;
534
+ }
535
+ }
536
+ loadPage(1);
537
+ // Expose methods for external access via ref
538
+ expose({
539
+ first,
540
+ prior,
541
+ next,
542
+ last,
543
+ page,
544
+ refresh,
545
+ orderby,
546
+ getSelectedRows: () => spec.selectedRows,
547
+ setSelectedRows: (rows) => { spec.selectedRows = rows; }
548
+ });
525
549
  onMounted(() => {
526
550
  // mounted hook
527
551
  });
528
552
  return {
529
- spec, renderHeader, renderBody, renderFooter, renderCaption
553
+ spec, renderHeader, renderBody, renderFooter, renderCaption,
554
+ first, prior, next, last, page, refresh, orderby,
555
+ getSelectedRows: () => spec.selectedRows,
556
+ setSelectedRows: (rows) => { spec.selectedRows = rows; }
530
557
  };
531
558
  },
532
559
  render(props) {
@@ -548,4 +575,4 @@ const tablevu = {
548
575
  }
549
576
  };
550
577
 
551
- export { TablevuStatus, tablevu as default };
578
+ export { tablevu as default };