lkt-table 1.0.19 → 1.0.20

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lkt-table",
3
- "version": "1.0.19",
3
+ "version": "1.0.20",
4
4
  "description": "",
5
5
  "keywords": [
6
6
  "lkt",
@@ -19,7 +19,7 @@
19
19
  "./styles": "./dist/style.css"
20
20
  },
21
21
  "types": "./dist/lkt-table.d.ts",
22
- "files": ["dist/*"],
22
+ "files": ["dist/*", "src/**/*.vue"],
23
23
  "license": "MIT",
24
24
  "sideEffects": false,
25
25
  "scripts": {
@@ -0,0 +1,66 @@
1
+ <script lang="ts">
2
+ export default {name: "LktHiddenRow", inheritAttrs: false}
3
+ </script>
4
+
5
+ <script lang="ts" setup>
6
+ import {createLktEvent} from "lkt-events";
7
+ import {getColumnDisplayContent} from "../functions/table-functions";
8
+ import {LktTableColumn} from "../instances/LktTableColumn";
9
+ import {PropType} from "vue/dist/vue";
10
+ import LktTableCell from "./LktTableCell.vue";
11
+ import {ref, watch} from "vue";
12
+
13
+ const emit = defineEmits(['update:modelValue', 'click']);
14
+
15
+ const props = defineProps({
16
+ isDraggable: {type: Boolean, default: true},
17
+ sortable: {type: Boolean, default: true},
18
+ i: {type: [Number], default: 0},
19
+ hiddenColumnsColSpan: {type: Number, default: 0},
20
+ visibleColumns: {type: Array as PropType<LktTableColumn[]>, default: (): LktTableColumn[] => []},
21
+ hiddenColumns: {type: Array as PropType<LktTableColumn[]>, default: (): LktTableColumn[] => []},
22
+ emptyColumns: {type: Array as PropType<string[]>, default: (): string[] => []},
23
+ hiddenIsVisible: {type: Boolean, default: false},
24
+ modelValue: {type: Object as PropType<any>, default: () => ({})},
25
+ });
26
+
27
+ const item = ref(props.modelValue);
28
+
29
+ const onClick = ($event: any, item: any, column: LktTableColumn) => {
30
+ emit('click', $event, createLktEvent('', {item, column}))
31
+ };
32
+
33
+ watch(() => props.modelValue, (v) => item.value = v);
34
+ watch(item, () => emit('update:modelValue', item.value));
35
+ </script>
36
+
37
+ <template>
38
+ <tr v-show="hiddenIsVisible" data-role="hidden-row">
39
+ <td :colspan="hiddenColumnsColSpan">
40
+ <table>
41
+ <tr>
42
+ <th v-for="column in hiddenColumns" :data-column="column.key">
43
+ <div>{{ column.label }}</div>
44
+ </th>
45
+ </tr>
46
+ <tr :data-i="i">
47
+ <td v-for="(column, i) in hiddenColumns"
48
+ v-bind:data-column="column.key"
49
+ v-bind:title="getColumnDisplayContent (column, item, i)"
50
+ v-on:click="onClick($event, item, column)">
51
+ <template v-if="!!$slots[column.key]">
52
+ <slot v-bind:name="column.key"
53
+ v-bind:value="item[column.key]"
54
+ v-bind:item="item"
55
+ v-bind:column="column"
56
+ v-bind:i="i"></slot>
57
+ </template>
58
+ <template v-else>
59
+ <lkt-table-cell :column="column" v-model="item" :i="i"></lkt-table-cell>
60
+ </template>
61
+ </td>
62
+ </tr>
63
+ </table>
64
+ </td>
65
+ </tr>
66
+ </template>
@@ -0,0 +1,103 @@
1
+ <script lang="ts">
2
+ export default {name: "LktTableCell", inheritAttrs: false}
3
+ </script>
4
+
5
+ <script lang="ts" setup>
6
+ import {getColumnDisplayContent} from "../functions/table-functions";
7
+ import {LktTableColumn} from "../instances/LktTableColumn";
8
+ import {PropType} from "vue/dist/vue";
9
+ import {nextTick, ref, watch} from "vue";
10
+ import {LktObject} from "lkt-ts-interfaces";
11
+
12
+ const emit = defineEmits(['edited']);
13
+
14
+ const props = defineProps({
15
+ modelValue: {type: Object as PropType<LktObject>, default: () => ({})},
16
+ column: {type: Object as PropType<LktTableColumn>, default: () => ({})},
17
+ i: {type: [Number], default: 0},
18
+ });
19
+
20
+ const item = ref(props.modelValue),
21
+ value = ref(item.value[props.column.key]),
22
+ inputElement = ref(null),
23
+ loadingColumn = ref(props.column.showLoading());
24
+
25
+ watch(value, () => {
26
+ const payload = JSON.parse(JSON.stringify(item.value));
27
+ payload[props.column.key] = value.value;
28
+ emit('edited', payload, props.i);
29
+ })
30
+
31
+ watch(() => props.modelValue, (v) => {
32
+ item.value = v
33
+ value.value = item.value[props.column.key];
34
+ });
35
+
36
+ watch(() => props.column, () => {
37
+ if (props.column.resourceLoaded) {
38
+ nextTick(() => loadingColumn.value = false)
39
+ }
40
+ }, {deep: true});
41
+
42
+ if (props.column.hasToLoadResource()) {
43
+ props.column.loadResource();
44
+ }
45
+ </script>
46
+
47
+ <template>
48
+ <template v-if="column.type === 'link'">
49
+ <router-link :to="column.getHref(item)">{{ getColumnDisplayContent(column, item, i) }}</router-link>
50
+ </template>
51
+ <template v-else-if="column.type === 'action'">
52
+ <a href="#" v-on:click="column.doAction(item)">{{ getColumnDisplayContent(column, item, i) }}</a>
53
+ </template>
54
+ <template v-else-if="column.type === 'text'">
55
+ <lkt-field-text
56
+ v-bind:read-mode="!column.editable"
57
+ :ref="(el:any) => inputElement = el"
58
+ :edit-slot="column.editSlot"
59
+ :value-slot="column.valueSlot"
60
+ v-model="value"></lkt-field-text>
61
+ </template>
62
+ <template v-else-if="column.type === 'email'">
63
+ <lkt-field-text
64
+ v-bind:read-mode="!column.editable"
65
+ :ref="(el:any) => inputElement = el"
66
+ :edit-slot="column.editSlot"
67
+ :value-slot="column.valueSlot"
68
+ is-email
69
+ v-model="value"></lkt-field-text>
70
+ </template>
71
+ <template v-else-if="column.type === 'tel'">
72
+ <lkt-field-text
73
+ v-bind:read-mode="!column.editable"
74
+ :ref="(el:any) => inputElement = el"
75
+ :edit-slot="column.editSlot"
76
+ :value-slot="column.valueSlot"
77
+ is-tel
78
+ v-model="value"></lkt-field-text>
79
+ </template>
80
+ <template v-else-if="column.type === 'check'">
81
+ <lkt-field-check v-bind:read-mode="!column.editable" :ref="(el:any) => inputElement = el" v-model="value"></lkt-field-check>
82
+ </template>
83
+ <template v-else-if="column.type === 'switch'">
84
+ <lkt-field-switch v-bind:read-mode="!column.editable" :ref="(el:any) => inputElement = el" v-model="value"></lkt-field-switch>
85
+ </template>
86
+ <template v-else-if="column.type === 'select'">
87
+ <lkt-loader v-if="loadingColumn"></lkt-loader>
88
+ <lkt-field-select
89
+ v-else
90
+ v-bind:read-mode="!column.editable"
91
+ :ref="(el:any) => inputElement = el"
92
+ v-model="value"
93
+ v-bind:resource="column.resource"
94
+ v-bind:resource-data="column.resourceData"
95
+ v-bind:options="column.options"
96
+ v-bind:multiple="column.isMultiple"
97
+ v-bind:multiple-display="column.multipleDisplay"
98
+ v-bind:multiple-display-edition="column.multipleDisplayEdition"></lkt-field-select>
99
+ </template>
100
+ <template v-else>
101
+ {{ getColumnDisplayContent(column, item, i) }}
102
+ </template>
103
+ </template>
@@ -0,0 +1,72 @@
1
+ <script lang="ts">
2
+ export default {name: "LktTableRow", inheritAttrs: false}
3
+ </script>
4
+
5
+ <script lang="ts" setup>
6
+ import {createLktEvent} from "lkt-events";
7
+ import {getColumnDisplayContent, getHorizontalColSpan, canRenderColumn} from "../functions/table-functions";
8
+ import {LktTableColumn} from "../instances/LktTableColumn";
9
+ import {PropType} from "vue/dist/vue";
10
+ import LktTableCell from "./LktTableCell.vue";
11
+ import {ref, watch} from "vue";
12
+ import {LktObject} from "lkt-ts-interfaces";
13
+
14
+ const emit = defineEmits(['edited', 'click', 'show']);
15
+
16
+ const props = defineProps({
17
+ isDraggable: {type: Boolean, default: true},
18
+ sortable: {type: Boolean, default: true},
19
+ i: {type: [Number], default: 0},
20
+ displayHiddenColumnsIndicator: {type: Boolean, default: false},
21
+ visibleColumns: {type: Array as PropType<LktTableColumn[]>, default: (): LktTableColumn[] => []},
22
+ emptyColumns: {type: Array as PropType<string[]>, default: (): string[] => []},
23
+ hiddenIsVisible: {type: Boolean, default: false},
24
+ item: {type: Object as PropType<any>, default: () => ({})},
25
+ });
26
+
27
+ const Item = ref(props.item);
28
+
29
+ const onClick = ($event: any, item: any, column: LktTableColumn) => {
30
+ emit('click', $event, createLktEvent('', {item, column}))
31
+ };
32
+ const onShow = ($event: any, i: any) => {
33
+ emit('show', $event, createLktEvent('', {i}))
34
+ };
35
+
36
+ const onEdited = (payload: LktObject, i: any) => {
37
+ Item.value = payload;
38
+ }
39
+
40
+ watch(() => props.item, (v) => Item.value = v);
41
+ watch(Item, () => emit('edited', Item.value, props.i));
42
+ </script>
43
+
44
+ <template>
45
+ <tr :data-i="i" :data-handle-drag="isDraggable">
46
+ <td v-if="sortable && isDraggable" data-role="drag-indicator"></td>
47
+ <td v-else-if="sortable" data-role="invalid-drag-indicator"></td>
48
+ <td v-if="displayHiddenColumnsIndicator"
49
+ v-on:click="onShow($event, i)" data-role="show-more"
50
+ v-bind:class="hiddenIsVisible ? 'state-open' : ''"></td>
51
+ <template v-for="column in visibleColumns">
52
+ <td v-if="canRenderColumn(column, emptyColumns, item)"
53
+ v-bind:data-column="column.key"
54
+ v-bind:colspan="getHorizontalColSpan(column,item)"
55
+ v-bind:title="getColumnDisplayContent (column, item, i)"
56
+ v-on:click="onClick($event, item, column)"
57
+ >
58
+ <template v-if="!!$slots[column.key]">
59
+ <slot v-bind:name="column.key"
60
+ v-bind:value="item[column.key]"
61
+ v-bind:item="item"
62
+ v-bind:column="column"
63
+ v-bind:i="i"></slot>
64
+ </template>
65
+ <template v-else-if="item">
66
+ <lkt-table-cell :column="column" v-model="Item" :i="i" v-on:edited="onEdited"></lkt-table-cell>
67
+ </template>
68
+ </td>
69
+ </template>
70
+ </tr>
71
+
72
+ </template>
@@ -0,0 +1,268 @@
1
+ <script lang="ts">
2
+ export default {name: "LktTable", inheritAttrs: false}
3
+ </script>
4
+
5
+ <script lang="ts" setup>
6
+ import draggable from "vuedraggable";
7
+ import {
8
+ defaultTableSorter,
9
+ getVerticalColSpan,
10
+ getDefaultSortColumn,
11
+ getColumnByKey
12
+ } from "../functions/table-functions";
13
+ import LktTableRow from "../components/LktTableRow.vue";
14
+ import {computed, onMounted, PropType, ref, useSlots, watch} from "vue";
15
+ import {LktTableColumn} from "../instances/LktTableColumn";
16
+ import {LktEvent} from "lkt-events/dist/types/classes/LktEvent";
17
+ import LktHiddenRow from "../components/LktHiddenRow.vue";
18
+ import {generateRandomString} from "lkt-string-tools";
19
+ import {LktObject} from "lkt-ts-interfaces";
20
+
21
+ const emit = defineEmits(['update:modelValue', 'sort', 'click']);
22
+
23
+ const slots = useSlots();
24
+
25
+ const props = defineProps({
26
+ modelValue: {type: Array as PropType<LktObject[]>, default: (): any[] => []},
27
+ columns: {type: Array as PropType<LktTableColumn[]>, default: (): LktTableColumn[] => []},
28
+ sorter: {type: Function, default: defaultTableSorter},
29
+ sortable: {type: Boolean, default: false},
30
+ hideEmptyColumns: {type: Boolean, default: false},
31
+ draggableChecker: {type: Function, default: (item: any) => true},
32
+ checkValidDrag: {type: Function, default: (evt: any) => true},
33
+ draggableItemKey: {type: String, default: 'name'}
34
+ });
35
+
36
+ const hiddenColumnsStack: LktObject = {};
37
+
38
+ const Sorter = ref(typeof props.sorter === 'function' ? props.sorter : defaultTableSorter),
39
+ SortBy = ref(getDefaultSortColumn(props.columns)),
40
+ SortDirection = ref('asc'),
41
+ Items = ref(props.modelValue),
42
+ Hidden = ref(hiddenColumnsStack),
43
+ drag = ref(false);
44
+
45
+
46
+ const uniqueId = generateRandomString(12);
47
+
48
+ const hasData = computed(() => {
49
+ return Items.value.length > 0;
50
+ }),
51
+ emptyColumns = computed(() => {
52
+ if (!props.hideEmptyColumns) return [];
53
+ let r: string[] = [];
54
+ props.columns.forEach((column: LktTableColumn) => {
55
+ let key = column.key;
56
+
57
+ let ok = false;
58
+ Items.value.forEach((item: any) => {
59
+ if (typeof item.checkEmpty === 'function') {
60
+ return item.checkEmpty(item);
61
+ }
62
+ if (item[key]) ok = true;
63
+ });
64
+
65
+ if (!ok) r.push(key);
66
+ });
67
+ return r;
68
+ }),
69
+ visibleColumns = computed(() => {
70
+ return props.columns.filter((c: LktTableColumn) => !c.hidden);
71
+ }),
72
+ hiddenColumns = computed(() => {
73
+ return props.columns.filter((c: LktTableColumn) => c.hidden);
74
+ }),
75
+ hiddenColumnsColSpan = computed(() => {
76
+ let r = visibleColumns.value.length + 1;
77
+ if (props.sortable) ++r;
78
+ return r;
79
+ }),
80
+ displayHiddenColumnsIndicator = computed(() => {
81
+ return hiddenColumns.value.length > 0 && !props.sortable;
82
+ }),
83
+ columnKeys = computed((): string[] => {
84
+ return props.columns.map(c => c.key);
85
+
86
+ }),
87
+ colSlots = computed((): LktObject => {
88
+ let r = [];
89
+ for (let k in slots) if (columnKeys.value.indexOf(k) !== -1) r.push(k);
90
+ return r;
91
+ });
92
+
93
+
94
+ const getItemByEvent = (e: any) => {
95
+ let t = e.target;
96
+ if (typeof t.dataset.column === 'undefined') {
97
+ do {
98
+ t = t.parentNode;
99
+ } while (typeof t.dataset.column === 'undefined' && t.tagName !== 'TABLE' && t.tagName !== 'body');
100
+ }
101
+
102
+ if (t.tagName === 'TD') {
103
+ t = t.parentNode;
104
+ t = t.dataset.i;
105
+ if (typeof t !== 'undefined') return Items.value[t];
106
+ }
107
+
108
+ return undefined;
109
+ },
110
+ isVisible = (index: number) => {
111
+ return Hidden.value['tr_' + index] === true;
112
+ },
113
+ sort = (column: LktTableColumn | null) => {
114
+ if (!column) return;
115
+ if (column.sortable) {
116
+ Items.value = Items.value.sort((a: any, b: any) => {
117
+ return Sorter.value(a, b, column, SortDirection.value);
118
+ });
119
+ SortDirection.value = SortDirection.value === 'asc' ? 'desc' : 'asc';
120
+ SortBy.value = column.key;
121
+ emit('sort', [SortBy.value, SortDirection.value]);
122
+ }
123
+ },
124
+ onClick = ($event: any, $lkt: LktEvent) => {
125
+ emit('click', $event, $lkt);
126
+ },
127
+ show = ($event: any, $lkt: LktEvent) => {
128
+ let k = 'tr_' + $lkt.value.i;
129
+ Hidden.value[k] = typeof Hidden.value[k] === 'undefined' ? true : !Hidden.value[k];
130
+ };
131
+
132
+
133
+ const onEdited = (payload: LktObject, i: any) => {
134
+ Items.value[i] = payload;
135
+ }
136
+
137
+ onMounted(() => {
138
+ sort(getColumnByKey(props.columns, SortBy.value));
139
+ })
140
+
141
+ watch(() => props.modelValue, (v) => Items.value = v);
142
+ watch(Items, (v: any) => {
143
+ emit('update:modelValue', v)
144
+ });
145
+
146
+ defineExpose({getItemByEvent});
147
+
148
+ </script>
149
+
150
+ <template>
151
+ <div v-if="hasData" class="lkt-table" :data-sortable="sortable">
152
+ <table>
153
+ <thead>
154
+ <tr>
155
+ <th v-if="sortable" data-role="drag-indicator"></th>
156
+ <th v-if="displayHiddenColumnsIndicator"></th>
157
+ <template v-for="column in visibleColumns">
158
+ <th :data-column="column.key"
159
+ v-if="emptyColumns.indexOf(column.key) === -1"
160
+ v-bind:data-sortable="column.sortable === true"
161
+ v-bind:data-sort="column.sortable === true && SortBy === column.key ? SortDirection : ''"
162
+ v-bind:colspan="getVerticalColSpan(column, columns.length, Items)"
163
+ v-bind:title="column.label"
164
+ v-on:click="sort(column)"
165
+ >
166
+ <div>{{ column.label }}</div>
167
+ </th>
168
+ </template>
169
+ </tr>
170
+ </thead>
171
+ <draggable v-if="sortable"
172
+ v-model="Items"
173
+ v-bind:move="checkValidDrag"
174
+ v-bind:itemKey="draggableItemKey"
175
+ v-on:start="drag=true"
176
+ v-on:end="drag=false"
177
+ tag="tbody"
178
+ class="lkt-sortable-table"
179
+ handle="[data-handle-drag]">
180
+ <template #item="{element, index}">
181
+ <lkt-table-row
182
+ v-bind:key="uniqueId + '-' + index"
183
+ v-bind:i="index"
184
+ v-bind:item="element"
185
+ v-bind:display-hidden-columns-indicator="displayHiddenColumnsIndicator"
186
+ v-bind:is-draggable="draggableChecker ? draggableChecker(element) : true"
187
+ v-bind:sortable="sortable"
188
+ v-bind:visible-columns="visibleColumns"
189
+ v-bind:empty-columns="emptyColumns"
190
+ v-bind:hidden-is-visible="isVisible(index)"
191
+ v-on:click="onClick"
192
+ v-on:show="show"
193
+ >
194
+ <template
195
+ v-for="column in colSlots"
196
+ v-slot:[column]="row">
197
+ <slot
198
+ v-bind:name="column"
199
+ v-bind:item="row.item"
200
+ v-bind:value="row.value"
201
+ v-bind:column="row.column"
202
+ ></slot>
203
+ </template>
204
+ </lkt-table-row>
205
+ </template>
206
+ </draggable>
207
+
208
+ <tbody v-else>
209
+ <lkt-table-row
210
+ v-for="(item, i) in Items"
211
+ v-bind:key="uniqueId + '-' + i"
212
+ v-bind:i="i"
213
+ v-bind:item="item"
214
+ v-bind:display-hidden-columns-indicator="displayHiddenColumnsIndicator"
215
+ v-bind:is-draggable="draggableChecker ? draggableChecker(item) : true"
216
+ v-bind:sortable="sortable"
217
+ v-bind:visible-columns="visibleColumns"
218
+ v-bind:empty-columns="emptyColumns"
219
+ v-bind:hidden-is-visible="isVisible(i)"
220
+ v-on:click="onClick"
221
+ v-on:show="show"
222
+ v-on:edited="onEdited"
223
+ >
224
+ <template
225
+ v-for="column in colSlots"
226
+ v-slot:[column]="row">
227
+ <slot
228
+ v-bind:name="column"
229
+ v-bind:item="row.item"
230
+ v-bind:value="row.value"
231
+ v-bind:column="row.column"
232
+ ></slot>
233
+ </template>
234
+ </lkt-table-row>
235
+ <lkt-hidden-row
236
+ v-if="hiddenColumns.length > 0"
237
+ v-for="(item, i) in Items"
238
+ v-bind:key="uniqueId + '-' + i"
239
+ v-bind:i="i"
240
+ v-bind:item="item"
241
+ v-bind:hidden-columns="hiddenColumns"
242
+ v-bind:hidden-columns-col-span="hiddenColumnsColSpan"
243
+ v-bind:is-draggable="draggableChecker ? draggableChecker(item) : true"
244
+ v-bind:sortable="sortable"
245
+ v-bind:visible-columns="visibleColumns"
246
+ v-bind:empty-columns="emptyColumns"
247
+ v-bind:hidden-is-visible="isVisible(i)"
248
+ v-on:click="onClick"
249
+ v-on:show="show"
250
+ >
251
+ <template
252
+ v-for="column in colSlots"
253
+ v-slot:[column]="row">
254
+ <slot
255
+ v-bind:name="column"
256
+ v-bind:item="row.item"
257
+ v-bind:value="row.value"
258
+ v-bind:column="row.column"
259
+ ></slot>
260
+ </template>
261
+ </lkt-hidden-row>
262
+ </tbody>
263
+ </table>
264
+ </div>
265
+ <div v-else-if="!!$slots['no-items']" class="lkt-empty-table">
266
+ <slot name="no-items"></slot>
267
+ </div>
268
+ </template>