lkt-table 1.0.13

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/lkt-table.css ADDED
@@ -0,0 +1,114 @@
1
+ .lkt-table {
2
+ width: var(--table-width);
3
+ overflow-x: auto;
4
+ font-family: var(--table-font-family);
5
+ }
6
+
7
+ .lkt-table > table {
8
+ width: 100%;
9
+ max-width: 100%;
10
+ border-collapse: separate;
11
+ border-radius: var(--table-border-radius);
12
+ border-spacing: 0;
13
+ }
14
+
15
+ .lkt-table th,
16
+ .lkt-table td {
17
+ vertical-align: middle;
18
+ text-align: var(--table-text-align);
19
+ padding: var(--table-row-padding);
20
+ font-size: var(--table-row-font-size);
21
+ color: var(--table-row-color);
22
+ }
23
+
24
+ .lkt-table th {
25
+ font-family: var(--table-header-font-family);
26
+ padding: var(--table-header-padding);
27
+ }
28
+
29
+ .lkt-table thead tr {
30
+ background-color: var(--table-header-background)
31
+ }
32
+
33
+ .lkt-table tbody tr {
34
+ background-color: var(--table-row-background);
35
+ }
36
+
37
+ .lkt-table tbody tr:nth-child(odd) {
38
+ background-color: var(--table-row-background-odd);
39
+ }
40
+
41
+ .lkt-table [data-sort="asc"] > div,
42
+ .lkt-table [data-sort="desc"] > div {
43
+ display: inline-block;
44
+ }
45
+
46
+ .lkt-table [data-sort="asc"] > div:after,
47
+ .lkt-table [data-sort="desc"] > div:after {
48
+ font-family: var(--table-sort-icon-font-family);
49
+ display: inline-block;
50
+ font-size: var(--table-sort-icon-font-size);
51
+ }
52
+
53
+ .lkt-table [data-sort="asc"] > div:after {
54
+ content: var(--table-sort-asc-icon-content);
55
+ }
56
+
57
+ .lkt-table [data-sort="desc"] > div:after {
58
+ content: var(--table-sort-desc-icon-content);
59
+ }
60
+
61
+ .lkt-table td[data-role="drag-indicator"],
62
+ .lkt-table td[data-role="invalid-drag-indicator"] {
63
+ width: var(--table-drag-indicator-width);
64
+ height: 40px;
65
+ padding: 0 !important;
66
+ position: relative;
67
+ background: #eeeeee;
68
+ cursor: pointer;
69
+ }
70
+
71
+ .lkt-table td[data-role="drag-indicator"]:before,
72
+ .lkt-table td[data-role="invalid-drag-indicator"]:before {
73
+ content: '';
74
+ display: block;
75
+ background: #eeeeee;
76
+ width: 18px;
77
+ height: 36px;
78
+ margin: auto;
79
+ }
80
+
81
+ .lkt-table td[data-role="drag-indicator"]:after,
82
+ .lkt-table td[data-role="invalid-drag-indicator"]:after {
83
+ content: "\2026";
84
+ color: #000000;
85
+ display: block;
86
+ position: absolute;
87
+ top: 50%;
88
+ left: 50%;
89
+ font-weight: 700;
90
+ width: 15px;
91
+ height: 7px;
92
+ transform: rotate(90deg);
93
+ transform-origin: center center;
94
+ }
95
+
96
+ [data-lkt="empty-table"] {
97
+ border: 1px solid #ddd;
98
+ border-radius: var(--table-border-radius);
99
+ width: 100%;
100
+ padding: 10px;
101
+ background-color: #f8f7e5;
102
+ font-family: var(--table-font-family);
103
+ font-size: 13px;
104
+ color: #444;
105
+ text-align: var(--table-text-align);
106
+ }
107
+
108
+ .sortable-chosen {
109
+ border: var(--table-sortable-chosen-border);
110
+ }
111
+
112
+ .sortable-chosen.ghost {
113
+ background: var(--table-sortable-chosen-ghost-background);
114
+ }
package/package.json ADDED
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "lkt-table",
3
+ "version": "1.0.13",
4
+ "description": "",
5
+ "main": "src/index.ts",
6
+ "module": "src/index.ts",
7
+ "files": [
8
+ "lkt-table.css",
9
+ "dist/*",
10
+ "src/**/*.vue"
11
+ ],
12
+ "sideEffects": false,
13
+ "exports": {
14
+ ".": {
15
+ "import": "./dist/lkt-table.es.js",
16
+ "require": "./dist/lkt-table.umd.js"
17
+ },
18
+ "./dist/style.css": "./dist/style.css"
19
+ },
20
+ "types": "./dist/types/index.d.ts",
21
+ "scripts": {
22
+ "serve": "vite",
23
+ "build": "vite build && vue-tsc --emitDeclarationOnly --project tsconfig.json && mv dist/src dist/types && rm dist/README.md.d.ts && rm dist/vite.config.d.ts",
24
+ "build2": "vite build",
25
+ "preview": "vite preview",
26
+ "test": "vitest",
27
+ "test-coverage": "vitest run --coverage"
28
+ },
29
+ "author": "Antonio Ibáñez",
30
+ "devDependencies": {
31
+ "@babel/core": "^7.13.13",
32
+ "@babel/preset-env": "^7.13.12",
33
+ "@babel/types": "^7.18.9",
34
+ "@testing-library/cypress": "^7.0.4",
35
+ "@testing-library/dom": "^7.30.1",
36
+ "@testing-library/jest-dom": "^5.11.10",
37
+ "@types/jest": "^29.0.1",
38
+ "@types/node": "^18.6.2",
39
+ "@typescript-eslint/eslint-plugin": "^5.36.2",
40
+ "@typescript-eslint/parser": "^5.36.2",
41
+ "@vitejs/plugin-vue": "^3.0.1",
42
+ "babel-eslint": "^10.1.0",
43
+ "babel-jest": "^29.0.3",
44
+ "babel-loader": "^8.2.2",
45
+ "cypress": "^6.8.0",
46
+ "eslint": "8.22.0",
47
+ "eslint-config-prettier": "^8.1.0",
48
+ "eslint-plugin-cypress": "^2.11.2",
49
+ "eslint-plugin-html": "^7.1.0",
50
+ "eslint-plugin-import": "^2.22.1",
51
+ "eslint-plugin-jest": "^24.3.2",
52
+ "eslint-plugin-prettier": "^3.3.1",
53
+ "eslint-plugin-simple-import-sort": "^7.0.0",
54
+ "jest": "^29.0.3",
55
+ "prettier": "^2.7.1",
56
+ "ts-jest": "^29.0.0",
57
+ "typescript": "^4.8.3",
58
+ "vite": "^3.1.2",
59
+ "vue-tsc": "^0.38.9"
60
+ },
61
+ "dependencies": {
62
+ "lkt-events": "^1.0.2",
63
+ "lkt-string-tools": "^1.0.3",
64
+ "lkt-ts-interfaces": "^1.0.2",
65
+ "vue": "^3.3",
66
+ "vuedraggable": "^4.1.0"
67
+ },
68
+ "engines": {
69
+ "node": ">=18"
70
+ }
71
+ }
@@ -0,0 +1,59 @@
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
+
11
+ const emit = defineEmits(['click']);
12
+
13
+ const props = defineProps({
14
+ isDraggable: {type: Boolean, default: true},
15
+ sortable: {type: Boolean, default: true},
16
+ i: {type: [Number], default: 0},
17
+ hiddenColumnsColSpan: {type: Number, default: 0},
18
+ visibleColumns: {type: Array as PropType<LktTableColumn[]>, default: (): LktTableColumn[] => []},
19
+ hiddenColumns: {type: Array as PropType<LktTableColumn[]>, default: (): LktTableColumn[] => []},
20
+ emptyColumns: {type: Array as PropType<string[]>, default: (): string[] => []},
21
+ hiddenIsVisible: {type: Boolean, default: false},
22
+ item: {type: Object as PropType<any>, default: () => ({})},
23
+ });
24
+
25
+ const onClick = ($event: any, item: any, column: LktTableColumn) => {
26
+ emit('click', $event, createLktEvent('', {item, column}))
27
+ };
28
+ </script>
29
+
30
+ <template>
31
+ <tr v-show="hiddenIsVisible" data-role="hidden-row">
32
+ <td :colspan="hiddenColumnsColSpan">
33
+ <table>
34
+ <tr>
35
+ <th v-for="column in hiddenColumns" :data-column="column.key">
36
+ <div>{{ column.label }}</div>
37
+ </th>
38
+ </tr>
39
+ <tr :data-i="i">
40
+ <td v-for="(column, i) in hiddenColumns"
41
+ v-bind:data-column="column.key"
42
+ v-bind:title="getColumnDisplayContent (column, item, i)"
43
+ v-on:click="onClick($event, item, column)">
44
+ <template v-if="!!$slots[column.key]">
45
+ <slot v-bind:name="column.key"
46
+ v-bind:value="item[column.key]"
47
+ v-bind:item="item"
48
+ v-bind:column="column"
49
+ v-bind:i="i"></slot>
50
+ </template>
51
+ <template v-else>
52
+ {{ getColumnDisplayContent(column, item, i) }}
53
+ </template>
54
+ </td>
55
+ </tr>
56
+ </table>
57
+ </td>
58
+ </tr>
59
+ </template>
@@ -0,0 +1,60 @@
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
+
11
+ const emit = defineEmits(['click', 'show']);
12
+
13
+ const props = defineProps({
14
+ isDraggable: {type: Boolean, default: true},
15
+ sortable: {type: Boolean, default: true},
16
+ i: {type: [Number], default: 0},
17
+ displayHiddenColumnsIndicator: {type: Boolean, default: false},
18
+ visibleColumns: {type: Array as PropType<LktTableColumn[]>, default: (): LktTableColumn[] => []},
19
+ emptyColumns: {type: Array as PropType<string[]>, default: (): string[] => []},
20
+ hiddenIsVisible: {type: Boolean, default: false},
21
+ item: {type: Object as PropType<any>, default: () => ({})},
22
+ });
23
+
24
+ const onClick = ($event: any, item: any, column: LktTableColumn) => {
25
+ emit('click', $event, createLktEvent('', {item, column}))
26
+ };
27
+ const onShow = ($event: any, i: any) => {
28
+ emit('show', $event, createLktEvent('', {i}))
29
+ };
30
+ </script>
31
+
32
+ <template>
33
+ <tr :data-i="i" :data-handle-drag="isDraggable">
34
+ <td v-if="sortable && isDraggable" data-role="drag-indicator"></td>
35
+ <td v-else-if="sortable" data-role="invalid-drag-indicator"></td>
36
+ <td v-if="displayHiddenColumnsIndicator"
37
+ v-on:click="onShow($event, i)" data-role="show-more"
38
+ v-bind:class="hiddenIsVisible ? 'state-open' : ''"></td>
39
+ <template v-for="column in visibleColumns">
40
+ <td v-if="canRenderColumn(column, emptyColumns, item)"
41
+ v-bind:data-column="column.key"
42
+ v-bind:colspan="getHorizontalColSpan(column,item)"
43
+ v-bind:title="getColumnDisplayContent (column, item, i)"
44
+ v-on:click="onClick($event, item, column)"
45
+ >
46
+ <template v-if="!!$slots[column.key]">
47
+ <slot v-bind:name="column.key"
48
+ v-bind:value="item[column.key]"
49
+ v-bind:item="item"
50
+ v-bind:column="column"
51
+ v-bind:i="i"></slot>
52
+ </template>
53
+ <template v-else-if="item">
54
+ {{ getColumnDisplayContent(column, item, i) }}
55
+ </template>
56
+ </td>
57
+ </template>
58
+ </tr>
59
+
60
+ </template>
package/src/index.ts ADDED
@@ -0,0 +1,13 @@
1
+ /* eslint-disable import/prefer-default-export */
2
+ import {default as table} from "./lib-components/LktTable.vue";
3
+ import {App} from "vue";
4
+
5
+ export {createColumn, createHiddenColumn} from "./functions/table-functions";
6
+
7
+ const LktTable = {
8
+ install: (app: App) => {
9
+ app.component('lkt-table', table);
10
+ },
11
+ };
12
+
13
+ export default LktTable;
@@ -0,0 +1,260 @@
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
+ onMounted(() => {
133
+ sort(getColumnByKey(props.columns, SortBy.value));
134
+ })
135
+
136
+ watch(() => props.modelValue, (v) => Items.value = v);
137
+ watch(Items, (v: any) => emit('update:modelValue', v));
138
+
139
+ defineExpose({getItemByEvent});
140
+
141
+ </script>
142
+
143
+ <template>
144
+ <div v-if="hasData" class="lkt-table" :data-sortable="sortable">
145
+ <table>
146
+ <thead>
147
+ <tr>
148
+ <th v-if="sortable" data-role="drag-indicator"></th>
149
+ <th v-if="displayHiddenColumnsIndicator"></th>
150
+ <template v-for="column in visibleColumns">
151
+ <th :data-column="column.key"
152
+ v-if="emptyColumns.indexOf(column.key) === -1"
153
+ v-bind:data-sortable="column.sortable === true"
154
+ v-bind:data-sort="column.sortable === true && SortBy === column.key ? SortDirection : ''"
155
+ v-bind:colspan="getVerticalColSpan(column, columns.length, Items)"
156
+ v-bind:title="column.label"
157
+ v-on:click="sort(column)"
158
+ >
159
+ <div>{{ column.label }}</div>
160
+ </th>
161
+ </template>
162
+ </tr>
163
+ </thead>
164
+ <draggable v-if="sortable"
165
+ v-model="Items"
166
+ v-bind:move="checkValidDrag"
167
+ v-bind:itemKey="draggableItemKey"
168
+ v-on:start="drag=true"
169
+ v-on:end="drag=false"
170
+ tag="tbody"
171
+ class="lkt-sortable-table"
172
+ handle="[data-handle-drag]">
173
+ <template #item="{element, index}">
174
+ <lkt-table-row
175
+ v-bind:key="uniqueId + '-' + index"
176
+ v-bind:i="index"
177
+ v-bind:item="element"
178
+ v-bind:display-hidden-columns-indicator="displayHiddenColumnsIndicator"
179
+ v-bind:is-draggable="draggableChecker ? draggableChecker(element) : true"
180
+ v-bind:sortable="sortable"
181
+ v-bind:visible-columns="visibleColumns"
182
+ v-bind:empty-columns="emptyColumns"
183
+ v-bind:hidden-is-visible="isVisible(index)"
184
+ v-on:click="onClick"
185
+ v-on:show="show"
186
+ >
187
+ <template
188
+ v-for="column in colSlots"
189
+ v-slot:[column]="row">
190
+ <slot
191
+ v-bind:name="column"
192
+ v-bind:item="row.item"
193
+ v-bind:value="row.value"
194
+ v-bind:column="row.column"
195
+ ></slot>
196
+ </template>
197
+ </lkt-table-row>
198
+ </template>
199
+ </draggable>
200
+
201
+ <tbody v-else>
202
+ <lkt-table-row
203
+ v-for="(item, i) in Items"
204
+ v-bind:key="uniqueId + '-' + i"
205
+ v-bind:i="i"
206
+ v-bind:item="item"
207
+ v-bind:display-hidden-columns-indicator="displayHiddenColumnsIndicator"
208
+ v-bind:is-draggable="draggableChecker ? draggableChecker(item) : true"
209
+ v-bind:sortable="sortable"
210
+ v-bind:visible-columns="visibleColumns"
211
+ v-bind:empty-columns="emptyColumns"
212
+ v-bind:hidden-is-visible="isVisible(i)"
213
+ v-on:click="onClick"
214
+ v-on:show="show"
215
+ >
216
+ <template
217
+ v-for="column in colSlots"
218
+ v-slot:[column]="row">
219
+ <slot
220
+ v-bind:name="column"
221
+ v-bind:item="row.item"
222
+ v-bind:value="row.value"
223
+ v-bind:column="row.column"
224
+ ></slot>
225
+ </template>
226
+ </lkt-table-row>
227
+ <lkt-hidden-row
228
+ v-if="hiddenColumns.length > 0"
229
+ v-for="(item, i) in Items"
230
+ v-bind:key="uniqueId + '-' + i"
231
+ v-bind:i="i"
232
+ v-bind:item="item"
233
+ v-bind:hidden-columns="hiddenColumns"
234
+ v-bind:hidden-columns-col-span="hiddenColumnsColSpan"
235
+ v-bind:is-draggable="draggableChecker ? draggableChecker(item) : true"
236
+ v-bind:sortable="sortable"
237
+ v-bind:visible-columns="visibleColumns"
238
+ v-bind:empty-columns="emptyColumns"
239
+ v-bind:hidden-is-visible="isVisible(i)"
240
+ v-on:click="onClick"
241
+ v-on:show="show"
242
+ >
243
+ <template
244
+ v-for="column in colSlots"
245
+ v-slot:[column]="row">
246
+ <slot
247
+ v-bind:name="column"
248
+ v-bind:item="row.item"
249
+ v-bind:value="row.value"
250
+ v-bind:column="row.column"
251
+ ></slot>
252
+ </template>
253
+ </lkt-hidden-row>
254
+ </tbody>
255
+ </table>
256
+ </div>
257
+ <div v-else-if="!!$slots['no-items']" class="lkt-empty-table">
258
+ <slot name="no-items"></slot>
259
+ </div>
260
+ </template>