@itfin/components 1.2.91 → 1.2.93
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 +4 -2
- package/src/components/modal/ItemEditor.vue +3 -0
- package/src/components/modal/Modal.vue +1 -1
- package/src/components/table/Table2.vue +39 -0
- package/src/components/table/TableBody.vue +165 -0
- package/src/components/table/TableGroup.vue +220 -0
- package/src/components/table/TableHeader.vue +236 -0
- package/src/components/table/TableRow.vue +221 -0
- package/src/components/table/index.stories.js +23 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@itfin/components",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.93",
|
|
4
4
|
"author": "Vitalii Savchuk <esvit666@gmail.com>",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"serve": "vue-cli-service serve",
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
"@egjs/vue-flicking": "^4.10.4",
|
|
23
23
|
"@mdi/js": "^7.2.96",
|
|
24
24
|
"@popperjs/core": "^2.11.8",
|
|
25
|
+
"@shopify/draggable": "^1.0.0-beta.8",
|
|
25
26
|
"@vue/cli-service": "^5.0.1",
|
|
26
27
|
"@vue/composition-api": "^1.7.1",
|
|
27
28
|
"air-datepicker": "^3.3.5",
|
|
@@ -36,7 +37,8 @@
|
|
|
36
37
|
"vue": "^2.6.12",
|
|
37
38
|
"vue-imask": "^6.6.3",
|
|
38
39
|
"vue-property-decorator": "^9.1.2",
|
|
39
|
-
"vue-swatches": "^2.1.1"
|
|
40
|
+
"vue-swatches": "^2.1.1",
|
|
41
|
+
"vue-virtual-scroller": "^1.1.2"
|
|
40
42
|
},
|
|
41
43
|
"devDependencies": {
|
|
42
44
|
"@babel/eslint-parser": "^7.19.1",
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
>
|
|
8
8
|
<slot name="content">
|
|
9
9
|
<div class="modal-content itf-append-context" ref="content" @click.stop>
|
|
10
|
-
<div v-if="title" class="modal-header">
|
|
10
|
+
<div v-if="title || $slots.title" class="modal-header">
|
|
11
11
|
<slot name="title">
|
|
12
12
|
<h5 class="modal-title" :id="modalId">{{title}}</h5>
|
|
13
13
|
</slot>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
|
|
3
|
+
<div class="scrollable scrollable-x big-scrollbar">
|
|
4
|
+
<itf-table-group
|
|
5
|
+
:columns="columns"
|
|
6
|
+
:rows="rows"
|
|
7
|
+
/>
|
|
8
|
+
</div>
|
|
9
|
+
|
|
10
|
+
</template>
|
|
11
|
+
<style lang="scss">
|
|
12
|
+
//.scrollable {
|
|
13
|
+
// -webkit-overflow-scrolling: touch;
|
|
14
|
+
// overflow: hidden auto;
|
|
15
|
+
//
|
|
16
|
+
// &.scrollable-x {
|
|
17
|
+
// overflow-x: auto;
|
|
18
|
+
// }
|
|
19
|
+
//}
|
|
20
|
+
</style>
|
|
21
|
+
<script>
|
|
22
|
+
import { Vue, Component, Prop, PropSync } from 'vue-property-decorator';
|
|
23
|
+
import itfButton from '../button/Button.vue';
|
|
24
|
+
import itfIcon from '../icon/Icon.vue';
|
|
25
|
+
import itfTableGroup from './TableGroup.vue';
|
|
26
|
+
|
|
27
|
+
export default @Component({
|
|
28
|
+
name: 'itfTable2',
|
|
29
|
+
components: {
|
|
30
|
+
itfButton,
|
|
31
|
+
itfIcon,
|
|
32
|
+
itfTableGroup
|
|
33
|
+
}
|
|
34
|
+
})
|
|
35
|
+
class itfTable2 extends Vue {
|
|
36
|
+
@Prop({ required: true, type: Array }) columns;
|
|
37
|
+
@Prop({ required: true, type: Array }) rows;
|
|
38
|
+
}
|
|
39
|
+
</script>
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
|
|
3
|
+
<recycle-scroller
|
|
4
|
+
class="scroller"
|
|
5
|
+
page-mode
|
|
6
|
+
:items="rows"
|
|
7
|
+
:item-size="36"
|
|
8
|
+
key-field="Id"
|
|
9
|
+
v-slot="{ item }"
|
|
10
|
+
direction="vertical"
|
|
11
|
+
>
|
|
12
|
+
<div group="items" data-test="table-item" class="table-view-item grouped draggable-item">
|
|
13
|
+
<div class="table-row-template">
|
|
14
|
+
<div accept-group="items" class="table-view-body-space"></div>
|
|
15
|
+
<div class="shadow-area">
|
|
16
|
+
<div class="toggler-wrapper"></div>
|
|
17
|
+
<div class="handle-wrapper hover-only">
|
|
18
|
+
<a href="" class="context-menu-toggle table-item-options-menu">
|
|
19
|
+
<div class="v-popper--has-tooltip drag-handle">
|
|
20
|
+
<i data-test="table-item-options" class="ic-drag"></i>
|
|
21
|
+
</div>
|
|
22
|
+
</a>
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
<div class="indicator sticky tw-border-gray dark:tw-border-gray-invert tw-border-r tw-bg-white dark:tw-bg-white-invert tw-border-b ">
|
|
26
|
+
<div class="fill on-rest table-view-row-count">
|
|
27
|
+
<span>{{ item.Id }}</span>
|
|
28
|
+
</div>
|
|
29
|
+
<div class="fill on-hover">
|
|
30
|
+
<a href="" data-test="table-item-expand">
|
|
31
|
+
<i class="ic-expand"></i>
|
|
32
|
+
</a>
|
|
33
|
+
<div class="">
|
|
34
|
+
<a data-test="table-row-generator" href="">
|
|
35
|
+
<i class="ic-plus"></i>
|
|
36
|
+
</a>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
<div accept-group="items" class="hbox table-item-inner">
|
|
41
|
+
<div v-for="(column, n) in columns" :data-column="n" :style="`width: ${column.width}px`">
|
|
42
|
+
<div
|
|
43
|
+
class="table-view-item-value tw-flex tw-relative tw-h-full tw-border-b tw-border-r tw-border-gray tw-bg-white dark:tw-bg-white-invert dark:tw-border-gray-invert hover:tw-bg-light dark:hover:tw-bg-gray-invert tw-items-stretch">
|
|
44
|
+
{{ item.Name }}
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
|
|
48
|
+
<div class="table-view-item-value extra"></div>
|
|
49
|
+
<div class="boundary top"></div>
|
|
50
|
+
<div class="boundary right"></div>
|
|
51
|
+
<div class="boundary bottom"></div>
|
|
52
|
+
<div class="boundary left"></div>
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
</recycle-scroller>
|
|
57
|
+
</template>
|
|
58
|
+
<style lang="scss">
|
|
59
|
+
.table-row-template {
|
|
60
|
+
display: flex;
|
|
61
|
+
height: 100%;
|
|
62
|
+
align-items: stretch;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.table-item-inner {
|
|
66
|
+
height: 100%;
|
|
67
|
+
flex-grow: 1;
|
|
68
|
+
position: relative;
|
|
69
|
+
display: flex;
|
|
70
|
+
flex-direction: row;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.table-view-item-value {
|
|
74
|
+
text-overflow: ellipsis;
|
|
75
|
+
background-color: rgb(255 255 255 / 1);
|
|
76
|
+
border-right: 1px solid rgb(238 238 238 / 1);
|
|
77
|
+
border-bottom: 1px solid rgb(238 238 238 / 1);
|
|
78
|
+
align-items: stretch;
|
|
79
|
+
height: 100%;
|
|
80
|
+
display: flex;
|
|
81
|
+
position: relative;
|
|
82
|
+
|
|
83
|
+
&:hover {
|
|
84
|
+
background-color: rgb(250 251 252 / 1);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.table-item-inner .extra {
|
|
89
|
+
height: 100%;
|
|
90
|
+
flex-grow: 1;
|
|
91
|
+
border-color: rgb(238 238 238 / 1);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.indicator {
|
|
95
|
+
height: 100%;
|
|
96
|
+
left: var(--shadow-area-width);
|
|
97
|
+
width: var(--indicator-area-width);
|
|
98
|
+
z-index: 4;
|
|
99
|
+
position: -webkit-sticky;
|
|
100
|
+
position: sticky;
|
|
101
|
+
background-color: rgb(255 255 255 / 1);
|
|
102
|
+
border-right: 1px solid rgb(238 238 238 / 1);
|
|
103
|
+
border-bottom: 1px solid rgb(238 238 238 / 1);
|
|
104
|
+
display: flex;
|
|
105
|
+
align-items: center;
|
|
106
|
+
justify-content: center;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.table-item-inner .boundary {
|
|
110
|
+
z-index: 3;
|
|
111
|
+
position: absolute;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.table-item-inner .boundary.top, .table-item-inner .boundary.bottom {
|
|
115
|
+
width: 100%;
|
|
116
|
+
border-top: thin solid #0000;
|
|
117
|
+
top: 0;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.table-item-inner .boundary {
|
|
121
|
+
z-index: 3;
|
|
122
|
+
position: absolute;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.table-item-inner .boundary.left, .table-item-inner .boundary.right {
|
|
126
|
+
height: 100%;
|
|
127
|
+
border-left: thin solid #0000;
|
|
128
|
+
left: 0;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.table-item-inner .boundary.right {
|
|
132
|
+
left: auto;
|
|
133
|
+
right: 0;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.table-item-inner .boundary.bottom {
|
|
137
|
+
top: auto;
|
|
138
|
+
bottom: 0;
|
|
139
|
+
}
|
|
140
|
+
.table-small-row .table-view-item {
|
|
141
|
+
height: 36px;
|
|
142
|
+
}
|
|
143
|
+
.vue-recycle-scroller {
|
|
144
|
+
position: relative;
|
|
145
|
+
}
|
|
146
|
+
</style>
|
|
147
|
+
|
|
148
|
+
<script>
|
|
149
|
+
import { Vue, Component, Prop } from 'vue-property-decorator';
|
|
150
|
+
import { RecycleScroller } from 'vue-virtual-scroller'
|
|
151
|
+
|
|
152
|
+
export default @Component({
|
|
153
|
+
name: 'itfTableBody',
|
|
154
|
+
components: {
|
|
155
|
+
RecycleScroller
|
|
156
|
+
}
|
|
157
|
+
})
|
|
158
|
+
class itfTableBody extends Vue {
|
|
159
|
+
@Prop() columns;
|
|
160
|
+
@Prop() rows;
|
|
161
|
+
|
|
162
|
+
mounted() {
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
</script>
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
|
|
3
|
+
<div class="itf-table-group table-small-row">
|
|
4
|
+
<!-- Тут показується лінія при драг н дропі -->
|
|
5
|
+
<div accept-group="tablegroups" class="preline over">
|
|
6
|
+
<div class="line"></div>
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
<div data-test="table-group-wrapper" class="table-group-wrapper" :style="`--row-count: ${isShowTable ? rows.length : 0}`">
|
|
11
|
+
<div class="">
|
|
12
|
+
<div data-test="table-group" class="position-relative me-4">
|
|
13
|
+
<div group="tablegroups" class="draggable-item" data-draggable-mirror="{"xAxis":false}">
|
|
14
|
+
<div class="table-row-template d-flex align-items-stretch" style="height: var(--group-title-height)">
|
|
15
|
+
<div class="shadow-area"></div>
|
|
16
|
+
<div class="header-wrapper drag-handle">
|
|
17
|
+
<div class="header-content tw-sticky tw-flex tw-items-center tw-gap-5 tw-px-4">
|
|
18
|
+
<a href="" class="collapse-arrow" @click.prevent="toggleGroup">
|
|
19
|
+
<itf-icon :name="isShowTable ? 'chevron_down' : 'chevron_right'" />
|
|
20
|
+
</a>
|
|
21
|
+
<a href="" class="d-flex align-items-center line-overflow group-header-value" data-test="group-value-group-label-value">
|
|
22
|
+
<span title="To Do" class="badge text-decoration-none" style="background-color: #FFA2A2; color: #4C4E69;">To Do</span>
|
|
23
|
+
</a>
|
|
24
|
+
<div data-test="table-group-item-count" class="table-group-item-count">
|
|
25
|
+
16
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
|
|
32
|
+
<!-- Сама таблиця -->
|
|
33
|
+
<div v-if="isShowTable" class="table-view-body">
|
|
34
|
+
<itf-table-header :columns="columns" />
|
|
35
|
+
<itf-table-body :rows="rows" :columns="columns" />
|
|
36
|
+
</div>
|
|
37
|
+
|
|
38
|
+
<!-- Лінія додати нову -->
|
|
39
|
+
<div v-if="isShowTable" data-v-54c5481c="" data-v-1fb25116=""
|
|
40
|
+
class="table-row-template tw-flex tw-items-stretch tw-h-[var(--table-small-row-size)]">
|
|
41
|
+
<div data-v-54c5481c="" class="tw-bg-light dark:tw-bg-light-invert shadow-area"></div>
|
|
42
|
+
<a data-v-54c5481c="" href="" data-test="table-add-new-item"
|
|
43
|
+
class="tw-flex tw-items-center tw-flex-grow tw-rounded-b tw-border-b-1 tw-border-r-1 tw-border-gray dark:tw-border-gray-invert tw-bg-white dark:tw-bg-white-invert hover:tw-bg-gray dark:hover:tw-bg-gray-invert tw-text-blue"><span
|
|
44
|
+
data-v-54c5481c=""
|
|
45
|
+
class="tw-sticky tw-left-[var(--shadow-area-width)] tw-flex tw-items-center tw-gap-3 tw-px-4"><i
|
|
46
|
+
data-v-54c5481c="" class="ic-plus"></i> <span
|
|
47
|
+
data-v-54c5481c="">Add new row</span></span></a></div>
|
|
48
|
+
<!-- Групування -->
|
|
49
|
+
<div v-if="isShowTable" data-v-54c5481c="" data-v-1fb25116=""
|
|
50
|
+
class="table-row-template tw-flex tw-items-stretch tw-h-[var(--table-small-row-size)] table-summary">
|
|
51
|
+
<div data-v-54c5481c="" class="tw-bg-light dark:tw-bg-light-invert shadow-area"></div>
|
|
52
|
+
<div data-v-54c5481c=""
|
|
53
|
+
class="tw-flex tw-flex-row tw-items-center tw-ml-[var(--indicator-area-width)]"><span
|
|
54
|
+
data-v-54c5481c="" data-column="0" class="tw-relative line-overflow"
|
|
55
|
+
style="width: 400px;"><a href=""
|
|
56
|
+
class="context-menu-toggle tw-w-full tw-text-gray dark:tw-text-gray-invert tw-text-sm tw-flex tw-pr-3 tw-flex tw-items-stretch tw-justify-end"
|
|
57
|
+
data-v-54c5481c=""><span data-v-016abbf7=""
|
|
58
|
+
data-test="summary-column"
|
|
59
|
+
data-attribute-id="621b5429-3de2-4731-979f-ef0e0c974a6e"
|
|
60
|
+
class="invisible-summary tw-flex tw-items-center tw-justify-end tw-flex-auto"><span
|
|
61
|
+
data-v-016abbf7="" class="summary-placeholder hbox tw-items-center tw-justify-center">
|
|
62
|
+
Summary
|
|
63
|
+
<i data-v-016abbf7=""
|
|
64
|
+
class="tw-ml-2 tw-text-gray dark:tw-text-gray-invert ic-arrow-down"></i></span></span>
|
|
65
|
+
<!----></a></span><span data-v-54c5481c="" data-column="1"
|
|
66
|
+
class="tw-relative line-overflow" style="width: 240px;"><a
|
|
67
|
+
href=""
|
|
68
|
+
class="context-menu-toggle tw-w-full tw-text-gray dark:tw-text-gray-invert tw-text-sm tw-flex tw-pr-3 tw-flex tw-items-stretch tw-justify-end"
|
|
69
|
+
data-v-54c5481c=""><span data-v-016abbf7="" data-test="summary-column"
|
|
70
|
+
data-attribute-id="afaaafd3-6f27-470c-9f85-4f0312eaefc0"
|
|
71
|
+
class="invisible-summary tw-flex tw-items-center tw-justify-end tw-flex-auto visible-summary"><span
|
|
72
|
+
data-v-016abbf7=""><span data-v-016abbf7="" class="summary-placeholder tw-mr-2">
|
|
73
|
+
Earliest:
|
|
74
|
+
</span> <span data-v-016abbf7="">
|
|
75
|
+
Jun 28, 2023
|
|
76
|
+
</span></span></span> <!----></a></span><span data-v-54c5481c="" data-column="2"
|
|
77
|
+
class="tw-relative line-overflow"
|
|
78
|
+
style="width: 240px;"><a href=""
|
|
79
|
+
class="context-menu-toggle tw-w-full tw-text-gray dark:tw-text-gray-invert tw-text-sm tw-flex tw-pr-3 tw-flex tw-items-stretch tw-justify-end"
|
|
80
|
+
data-v-54c5481c=""><span
|
|
81
|
+
data-v-016abbf7="" data-test="summary-column"
|
|
82
|
+
data-attribute-id="0c545783-9fb4-4105-9558-9b105415bb07"
|
|
83
|
+
class="invisible-summary tw-flex tw-items-center tw-justify-end tw-flex-auto"><span
|
|
84
|
+
data-v-016abbf7="" class="summary-placeholder hbox tw-items-center tw-justify-center">
|
|
85
|
+
Summary
|
|
86
|
+
<i data-v-016abbf7=""
|
|
87
|
+
class="tw-ml-2 tw-text-gray dark:tw-text-gray-invert ic-arrow-down"></i></span></span>
|
|
88
|
+
<!----></a></span><span data-v-54c5481c="" data-column="3"
|
|
89
|
+
class="tw-relative line-overflow" style="width: 120px;"><a
|
|
90
|
+
href=""
|
|
91
|
+
class="context-menu-toggle tw-w-full tw-text-gray dark:tw-text-gray-invert tw-text-sm tw-flex tw-pr-3 tw-flex tw-items-stretch tw-justify-end"
|
|
92
|
+
data-v-54c5481c=""><span data-v-016abbf7="" data-test="summary-column"
|
|
93
|
+
data-attribute-id="b3935a97-9dc6-49bc-ae6b-767f3d88b86e"
|
|
94
|
+
class="invisible-summary tw-flex tw-items-center tw-justify-end tw-flex-auto"><span
|
|
95
|
+
data-v-016abbf7="" class="summary-placeholder hbox tw-items-center tw-justify-center">
|
|
96
|
+
Summary
|
|
97
|
+
<i data-v-016abbf7=""
|
|
98
|
+
class="tw-ml-2 tw-text-gray dark:tw-text-gray-invert ic-arrow-down"></i></span></span>
|
|
99
|
+
<!----></a></span></div>
|
|
100
|
+
</div>
|
|
101
|
+
</div>
|
|
102
|
+
</div>
|
|
103
|
+
</div>
|
|
104
|
+
</div>
|
|
105
|
+
|
|
106
|
+
</template>
|
|
107
|
+
<style lang="scss">
|
|
108
|
+
.itf-table-group {
|
|
109
|
+
--group-title-height: 40px;
|
|
110
|
+
--table-small-row-size: 36px;
|
|
111
|
+
--table-row-height: 36px;
|
|
112
|
+
--shadow-area-width: 45px;
|
|
113
|
+
--indicator-area-width: 38px;
|
|
114
|
+
|
|
115
|
+
.preline {
|
|
116
|
+
display: flex;
|
|
117
|
+
align-items: center;
|
|
118
|
+
height: 32px;
|
|
119
|
+
|
|
120
|
+
&.over .line {
|
|
121
|
+
width: 100%;
|
|
122
|
+
border-bottom: 4px solid rgb(71 190 255 / 1);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.table-group-wrapper {
|
|
127
|
+
display: flex;
|
|
128
|
+
height: calc(var(--group-title-height) + var(--table-small-row-size)*3 + var(--row-count)*var(--table-row-height));
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.shadow-area {
|
|
132
|
+
z-index: 4;
|
|
133
|
+
height: 100%;
|
|
134
|
+
width: var(--shadow-area-width);
|
|
135
|
+
justify-content: center;
|
|
136
|
+
align-items: center;
|
|
137
|
+
gap: 4px;
|
|
138
|
+
display: flex;
|
|
139
|
+
position: -webkit-sticky;
|
|
140
|
+
position: sticky;
|
|
141
|
+
left: 0;
|
|
142
|
+
background: #fff;
|
|
143
|
+
}
|
|
144
|
+
.header-wrapper:not(.collapsed *) {
|
|
145
|
+
flex-grow: 1;
|
|
146
|
+
border-bottom-right-radius: 0!important;
|
|
147
|
+
border-bottom-left-radius: 0!important;
|
|
148
|
+
}
|
|
149
|
+
.header-wrapper {
|
|
150
|
+
background-color: rgb(218 218 218 / 1);
|
|
151
|
+
left: var(--shadow-area-width);
|
|
152
|
+
align-items: center;
|
|
153
|
+
display: flex;
|
|
154
|
+
position: -webkit-sticky;
|
|
155
|
+
position: sticky;
|
|
156
|
+
border-radius: 0.1875rem;
|
|
157
|
+
border-bottom-width: 1px;
|
|
158
|
+
border-color: rgb(238 238 238 / 1);
|
|
159
|
+
}
|
|
160
|
+
.header-content:not(.draggable-mirror *) {
|
|
161
|
+
left: var(--shadow-area-width);
|
|
162
|
+
padding-left: 0.75rem;
|
|
163
|
+
padding-right: 0.75rem;
|
|
164
|
+
gap: 1rem;
|
|
165
|
+
align-items: center;
|
|
166
|
+
position: sticky;
|
|
167
|
+
display: flex;
|
|
168
|
+
}
|
|
169
|
+
.table-group-item-count {
|
|
170
|
+
padding-top: 0.125rem;
|
|
171
|
+
padding-bottom: 0.125rem;
|
|
172
|
+
padding-left: 0.5rem;
|
|
173
|
+
padding-right: 0.5rem;
|
|
174
|
+
background-color: rgb(250 251 252 / 1);
|
|
175
|
+
border-radius: 0.1875rem;
|
|
176
|
+
}
|
|
177
|
+
.table-view-wrapper .vue-recycle-scroller__item-wrapper {
|
|
178
|
+
overflow: visible;
|
|
179
|
+
}
|
|
180
|
+
.vue-recycle-scroller.direction-vertical .vue-recycle-scroller__item-wrapper {
|
|
181
|
+
width: 100%;
|
|
182
|
+
}
|
|
183
|
+
.table-view-wrapper .vue-recycle-scroller__item-wrapper {
|
|
184
|
+
overflow: visible;
|
|
185
|
+
}
|
|
186
|
+
.vue-recycle-scroller.ready .vue-recycle-scroller__item-view {
|
|
187
|
+
position: absolute;
|
|
188
|
+
top: 0;
|
|
189
|
+
left: 0;
|
|
190
|
+
will-change: transform;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
</style>
|
|
194
|
+
<script>
|
|
195
|
+
import {Vue, Component, Prop, PropSync} from 'vue-property-decorator';
|
|
196
|
+
import itfButton from '../button/Button.vue';
|
|
197
|
+
import itfIcon from '../icon/Icon.vue';
|
|
198
|
+
import itfTableBody from './TableBody.vue';
|
|
199
|
+
import itfTableHeader from './TableHeader.vue';
|
|
200
|
+
|
|
201
|
+
export default @Component({
|
|
202
|
+
name: 'itfTableGroup',
|
|
203
|
+
components: {
|
|
204
|
+
itfButton,
|
|
205
|
+
itfIcon,
|
|
206
|
+
itfTableBody,
|
|
207
|
+
itfTableHeader
|
|
208
|
+
}
|
|
209
|
+
})
|
|
210
|
+
class itfTableGroup extends Vue {
|
|
211
|
+
@Prop() columns;
|
|
212
|
+
@Prop() rows;
|
|
213
|
+
|
|
214
|
+
isShowTable = true;
|
|
215
|
+
|
|
216
|
+
toggleGroup() {
|
|
217
|
+
this.isShowTable = !this.isShowTable;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
</script>
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
|
|
3
|
+
<div class="itf-table-header">
|
|
4
|
+
<div ref="container" class="table-row-template">
|
|
5
|
+
<div accept-group="items" class="table-view-body-space"></div>
|
|
6
|
+
<div class="tw-bg-light dark:tw-bg-light-invert shadow-area"></div>
|
|
7
|
+
<div class="table-view-header-value reserved sticky"></div>
|
|
8
|
+
|
|
9
|
+
<div v-for="(column, n) in sortedColumns" :key="n" data-test="table-header-column" :data-column="n" :data-id="column.Id"
|
|
10
|
+
class="table-view-header-value" :style="`width: ${column.width}px; left: 0px;`">
|
|
11
|
+
<div accept-group="tablecolumns" class="table-view-header-space">
|
|
12
|
+
<div class="table-view-header-dropzone"></div>
|
|
13
|
+
</div>
|
|
14
|
+
<div group="tablecolumns" class="table-header draggable-item drag-handle" data-draggable-mirror="{"yAxis":false}">
|
|
15
|
+
<a href="" class="context-menu-toggle tw-flex-auto line-overflow">
|
|
16
|
+
<span title="Name">
|
|
17
|
+
<itf-icon name="type_select" :size="16" /> {{column.text}}
|
|
18
|
+
</span>
|
|
19
|
+
</a>
|
|
20
|
+
</div>
|
|
21
|
+
<div ref="resizeHandle" class="resize-handle"></div>
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
<div class="table-view-header-value">
|
|
25
|
+
<div data-v-14c77b30="" class="attribute-creator" data-v-54c5481c="">
|
|
26
|
+
<div data-v-fd8e8e6a="" data-test="dropdown"
|
|
27
|
+
class="dropdown-body tw-relative tw-cursor-pointer tw-w-full"><!---->
|
|
28
|
+
<div data-v-fd8e8e6a="" tabindex="0" data-test="dropdown-toggle">
|
|
29
|
+
<div data-v-fd8e8e6a=""
|
|
30
|
+
class="hbox tw-flex-auto tw-items-center tw-justify-center"><a
|
|
31
|
+
data-v-14c77b30="" data-v-fd8e8e6a="" href=""
|
|
32
|
+
data-test="table-header-add-column" class="tw-text-blue tw-mx-4"><span
|
|
33
|
+
data-v-14c77b30="" data-v-fd8e8e6a="" class="ic-plus"></span>
|
|
34
|
+
Add column
|
|
35
|
+
</a></div>
|
|
36
|
+
</div>
|
|
37
|
+
<span data-v-b4d986ec="" data-v-fd8e8e6a="" style="display: none;"> <div
|
|
38
|
+
data-v-b4d986ec="" class="context-modal-backdrop"></div><div
|
|
39
|
+
data-v-b4d986ec="" class="context-modal tw-min-w-[280px]"><!----> <!---->
|
|
40
|
+
<!----></div></span></div> <!----></div>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
</template>
|
|
46
|
+
<style lang="scss">
|
|
47
|
+
.itf-table-header {
|
|
48
|
+
position: sticky;
|
|
49
|
+
top: 0;
|
|
50
|
+
z-index: calc(var(--row-count) + 1);
|
|
51
|
+
|
|
52
|
+
.table-row-template {
|
|
53
|
+
display: flex;
|
|
54
|
+
align-items: stretch;
|
|
55
|
+
height: var(--table-small-row-size);
|
|
56
|
+
}
|
|
57
|
+
.table-view-header-value {
|
|
58
|
+
align-items: center;
|
|
59
|
+
height: 36px;
|
|
60
|
+
white-space: nowrap;
|
|
61
|
+
border-top: 0;
|
|
62
|
+
border-left: 0;
|
|
63
|
+
border-right-width: thin;
|
|
64
|
+
border-bottom-width: thin;
|
|
65
|
+
border-style: solid;
|
|
66
|
+
position: relative;
|
|
67
|
+
display: flex;
|
|
68
|
+
border-right-color: rgb(218 218 218 / 1);
|
|
69
|
+
border-bottom-color: rgb(238 238 238 / 1);
|
|
70
|
+
background-color: rgb(238 238 238 / 1);
|
|
71
|
+
|
|
72
|
+
&.reserved {
|
|
73
|
+
left: var(--shadow-area-width);
|
|
74
|
+
width: var(--indicator-area-width);
|
|
75
|
+
}
|
|
76
|
+
&.sticky {
|
|
77
|
+
position: sticky;
|
|
78
|
+
position: -webkit-sticky;
|
|
79
|
+
z-index: calc(var(--row-count) + 4);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
.table-header {
|
|
83
|
+
flex: 0 0 auto;
|
|
84
|
+
overflow: hidden;
|
|
85
|
+
width: 100%;
|
|
86
|
+
text-overflow: ellipsis;
|
|
87
|
+
margin-right: -5px;
|
|
88
|
+
padding-left: 0.75rem;
|
|
89
|
+
padding-right: 0.75rem;
|
|
90
|
+
gap: 0.25rem;
|
|
91
|
+
align-items: center;
|
|
92
|
+
display: flex;
|
|
93
|
+
}
|
|
94
|
+
.resize-handle {
|
|
95
|
+
width: 4px;
|
|
96
|
+
height: 36px;
|
|
97
|
+
position: absolute;
|
|
98
|
+
right: -2px;
|
|
99
|
+
top: 0;
|
|
100
|
+
background: #29ACE1;
|
|
101
|
+
border-radius: 2px;
|
|
102
|
+
z-index: 100;
|
|
103
|
+
opacity: 0;
|
|
104
|
+
cursor: ew-resize;
|
|
105
|
+
transition: .2s;
|
|
106
|
+
|
|
107
|
+
&:hover {
|
|
108
|
+
opacity: 1;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
.context-menu-toggle {
|
|
112
|
+
display: flex;
|
|
113
|
+
flex: 1 1 auto;
|
|
114
|
+
text-overflow: ellipsis;
|
|
115
|
+
white-space: nowrap;
|
|
116
|
+
overflow: hidden;
|
|
117
|
+
|
|
118
|
+
span {
|
|
119
|
+
font-size: 12px;
|
|
120
|
+
line-height: 36px;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
.itf-sortable-list {
|
|
124
|
+
display: flex;
|
|
125
|
+
}
|
|
126
|
+
.table-view-header-space {
|
|
127
|
+
height: 100%;
|
|
128
|
+
position: absolute;
|
|
129
|
+
left: 0;
|
|
130
|
+
display: none;
|
|
131
|
+
background: transparent;
|
|
132
|
+
z-index: 100;
|
|
133
|
+
width: 2px;
|
|
134
|
+
margin-left: -1px;
|
|
135
|
+
}
|
|
136
|
+
.draggable-mirror {
|
|
137
|
+
opacity: .5;
|
|
138
|
+
}
|
|
139
|
+
.draggable-container--over .table-view-header-space {
|
|
140
|
+
display: block;
|
|
141
|
+
}
|
|
142
|
+
.draggable-container--over .draggable--over .table-view-header-space {
|
|
143
|
+
background: #47BEFF;
|
|
144
|
+
}
|
|
145
|
+
.table-view-header-space > .table-view-header-dropzone {
|
|
146
|
+
position: absolute;
|
|
147
|
+
top: 0;
|
|
148
|
+
right: -50px;
|
|
149
|
+
bottom: 0;
|
|
150
|
+
left: -50px;
|
|
151
|
+
}
|
|
152
|
+
.table-view-header-value:not(.reserved):hover {
|
|
153
|
+
background-color: rgb(218 218 218 / 1);
|
|
154
|
+
}
|
|
155
|
+
.draggable-source--is-dragging {
|
|
156
|
+
z-index: 100;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
</style>
|
|
160
|
+
<script>
|
|
161
|
+
import { Vue, Component, Prop, PropSync } from 'vue-property-decorator';
|
|
162
|
+
import itfButton from '../button/Button.vue';
|
|
163
|
+
import itfIcon from '../icon/Icon.vue';
|
|
164
|
+
import { Draggable, Droppable, Sortable } from '@shopify/draggable';
|
|
165
|
+
|
|
166
|
+
export default @Component({
|
|
167
|
+
name: 'itfTableHeader',
|
|
168
|
+
components: {
|
|
169
|
+
itfButton,
|
|
170
|
+
itfIcon
|
|
171
|
+
}
|
|
172
|
+
})
|
|
173
|
+
class itfTable extends Vue {
|
|
174
|
+
@PropSync('columns', { type: Array, default: () => ([]) }) sortedColumns;
|
|
175
|
+
@Prop(Boolean) columnSorting;
|
|
176
|
+
@Prop(Boolean) columnResizing;
|
|
177
|
+
|
|
178
|
+
initDraggable() {
|
|
179
|
+
const draggable = new Sortable(this.$refs.container, {
|
|
180
|
+
// draggable: '[group="tablecolumns"]',
|
|
181
|
+
draggable: '[data-test="table-header-column"]',
|
|
182
|
+
mirror: {
|
|
183
|
+
yAxis: false,
|
|
184
|
+
appendTo: this.$refs.container
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
// const droppable = new Droppable(this.$refs.container, {
|
|
188
|
+
// draggable: '[group="tablecolumns"]',
|
|
189
|
+
// dropzone: '[accept-group="tablecolumns"]'
|
|
190
|
+
// });
|
|
191
|
+
draggable.on('drag:stop', (event) => {
|
|
192
|
+
console.info('dropped', event);
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
initResizing() {
|
|
197
|
+
const resizeHandle = this.$refs.resizeHandle;
|
|
198
|
+
resizeHandle.forEach((handle) => {
|
|
199
|
+
handle.addEventListener('mousedown', (event) => {
|
|
200
|
+
const column = event.target.closest('.table-view-header-value');
|
|
201
|
+
const body = event.target.closest('.table-view-body');
|
|
202
|
+
const columnWidth = column.offsetWidth;
|
|
203
|
+
const startX = event.pageX;
|
|
204
|
+
const index = column.getAttribute('data-column');
|
|
205
|
+
const columns = body.querySelectorAll(`[data-column="${index}"]`);
|
|
206
|
+
const mouseMoveHandler = (event) => {
|
|
207
|
+
const delta = event.pageX - startX;
|
|
208
|
+
columns.forEach((column) => {
|
|
209
|
+
column.style.width = `${columnWidth + delta}px`;
|
|
210
|
+
});
|
|
211
|
+
this.changeColumn(index, { width: columnWidth + delta });
|
|
212
|
+
};
|
|
213
|
+
const mouseUpHandler = () => {
|
|
214
|
+
document.removeEventListener('mousemove', mouseMoveHandler);
|
|
215
|
+
document.removeEventListener('mouseup', mouseUpHandler);
|
|
216
|
+
};
|
|
217
|
+
document.addEventListener('mousemove', mouseMoveHandler);
|
|
218
|
+
document.addEventListener('mouseup', mouseUpHandler);
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
mounted() {
|
|
224
|
+
if (this.columnSorting) {
|
|
225
|
+
this.initDraggable();
|
|
226
|
+
}
|
|
227
|
+
if (this.columnResizing) {
|
|
228
|
+
this.initResizing();
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
changeColumn(index, params) {
|
|
233
|
+
console.info(index, params);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
</script>
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
|
|
3
|
+
<div
|
|
4
|
+
class="table-row-template flex items-stretch" view-settings="[object Object]">
|
|
5
|
+
<div accept-group="items" class="table-view-body-space"
|
|
6
|
+
></div>
|
|
7
|
+
<div class="bg-light dark:bg-light-invert shadow-area">
|
|
8
|
+
<div class="toggler-wrapper"><!----></div>
|
|
9
|
+
<div class="handle-wrapper hover-only"><a
|
|
10
|
+
href="" class="context-menu-toggle table-item-options-menu"
|
|
11
|
+
>
|
|
12
|
+
<div class="v-popper--has-tooltip drag-handle"><i
|
|
13
|
+
data-test="table-item-options"
|
|
14
|
+
class="ic-drag"></i>
|
|
15
|
+
</div> <!----></a></div>
|
|
16
|
+
</div>
|
|
17
|
+
<div class="indicator">
|
|
18
|
+
<div class="fill on-rest table-view-row-count"><span
|
|
19
|
+
>1</span></div>
|
|
20
|
+
<div class="fill on-hover"><a
|
|
21
|
+
href=""
|
|
22
|
+
data-test="table-item-expand"><i
|
|
23
|
+
class="ic-expand"></i></a>
|
|
24
|
+
<div class="top"><a
|
|
25
|
+
data-test="table-row-generator" href=""><i
|
|
26
|
+
class="ic-plus"></i></a>
|
|
27
|
+
</div>
|
|
28
|
+
<div class=""><a
|
|
29
|
+
data-test="table-row-generator"
|
|
30
|
+
href=""><i
|
|
31
|
+
class="ic-plus"></i></a></div>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
<div accept-group="items" class="hbox table-item-inner">
|
|
35
|
+
<div data-column="0" class="sticky last-sticky-column"
|
|
36
|
+
style="width: 240px; left: 83px;">
|
|
37
|
+
<div
|
|
38
|
+
class="table-view-item-value flex relative h-full border-b border-r border-gray bg-white dark:bg-white-invert dark:border-gray-invert hover:bg-light dark:hover:bg-gray-invert items-stretch"
|
|
39
|
+
>
|
|
40
|
+
<div
|
|
41
|
+
class="flex-auto flex gap-2 items-start p-3 show-hidden-hover overflow-hidden">
|
|
42
|
+
<a href=""
|
|
43
|
+
class="context-menu-toggle h-full line-overflow cursor-pointer flex-auto"><span>
|
|
44
|
+
Jun 30th
|
|
45
|
+
</span> <!----></a> <!---->
|
|
46
|
+
<div class="flex items-center justify-end hover-show"><a href="" tabindex="0"
|
|
47
|
+
class="text-sm p-2 ic-exit"></a>
|
|
48
|
+
</div>
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
<div data-column="1" class="" style="width: 400px;">
|
|
53
|
+
<div
|
|
54
|
+
class="table-view-item-value flex relative h-full border-b border-r border-gray bg-white dark:bg-white-invert dark:border-gray-invert hover:bg-light dark:hover:bg-gray-invert items-stretch"
|
|
55
|
+
><textarea
|
|
56
|
+
data-test="table-text-value" rows="2" type="text"
|
|
57
|
+
wrap="hard"
|
|
58
|
+
class="h-full px-3 input-inline text-value w-full hide-scrollbar !leading-[35px] whitespace-nowrap"></textarea>
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
<div data-column="2" class="" style="width: 240px;">
|
|
62
|
+
<div
|
|
63
|
+
class="table-view-item-value flex relative h-full border-b border-r border-gray bg-white dark:bg-white-invert dark:border-gray-invert hover:bg-light dark:hover:bg-gray-invert items-stretch"
|
|
64
|
+
>
|
|
65
|
+
<div
|
|
66
|
+
class="flex-auto flex gap-2 items-start p-3 show-hidden-hover overflow-hidden">
|
|
67
|
+
<a href=""
|
|
68
|
+
class="context-menu-toggle h-full line-overflow cursor-pointer flex-auto"><span>
|
|
69
|
+
Jul 13th
|
|
70
|
+
</span> <!----></a> <!---->
|
|
71
|
+
<div class="flex items-center justify-end hover-show"><a href="" tabindex="0"
|
|
72
|
+
class="text-sm p-2 ic-exit"></a>
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
<div data-column="3" class="" style="width: 120px;">
|
|
78
|
+
<div
|
|
79
|
+
class="table-view-item-value flex relative h-full border-b border-r border-gray bg-white dark:bg-white-invert dark:border-gray-invert hover:bg-light dark:hover:bg-gray-invert items-stretch"
|
|
80
|
+
><a href=""
|
|
81
|
+
class="context-menu-toggle table-value-label flex flex-auto p-3 w-full"><span
|
|
82
|
+
class="table-value-label-selected w-full h-full vbox"><span
|
|
83
|
+
class="flex gap-2 hide-scrollbar overflow-auto"><span
|
|
84
|
+
title="Upcoming"
|
|
85
|
+
class="label-value"
|
|
86
|
+
style="--label-color: #A7E6FF; --label-text: #4C4E69;">
|
|
87
|
+
Upcoming
|
|
88
|
+
<!----></span></span></span> <!----></a></div>
|
|
89
|
+
</div>
|
|
90
|
+
<div
|
|
91
|
+
class="extra border-b border-r border-gray dark:border-gray-invert"></div>
|
|
92
|
+
<div class="boundary top"></div>
|
|
93
|
+
<div class="boundary right"></div>
|
|
94
|
+
<div class="boundary bottom"></div>
|
|
95
|
+
<div class="boundary left"></div> <!----></div>
|
|
96
|
+
</div>
|
|
97
|
+
|
|
98
|
+
</template>
|
|
99
|
+
<script>
|
|
100
|
+
import { Vue, Component, Prop, PropSync } from 'vue-property-decorator';
|
|
101
|
+
import itfButton from '../button/Button.vue';
|
|
102
|
+
import itfIcon from '../icon/Icon.vue';
|
|
103
|
+
|
|
104
|
+
export default @Component({
|
|
105
|
+
name: 'itfTable',
|
|
106
|
+
components: {
|
|
107
|
+
itfButton,
|
|
108
|
+
itfIcon,
|
|
109
|
+
}
|
|
110
|
+
})
|
|
111
|
+
class itfTable extends Vue {
|
|
112
|
+
@PropSync('sorting', { type: Object, default: () => ({}) }) sortedColumns;
|
|
113
|
+
@Prop({ required: true, type: Array }) columns;
|
|
114
|
+
@Prop({ required: true, type: Array }) rows;
|
|
115
|
+
@Prop({ default: false, type: Boolean }) stickyHeader;
|
|
116
|
+
@Prop({ default: false, type: Boolean }) stickyColumn;
|
|
117
|
+
@Prop({ default: false, type: Boolean }) stickyLastColumn;
|
|
118
|
+
@Prop({ default: false, type: Boolean }) loading;
|
|
119
|
+
@Prop({ default: false, type: Boolean }) striped;
|
|
120
|
+
@Prop({ default: false, type: Boolean }) hoverable;
|
|
121
|
+
@Prop({ default: false, type: Boolean }) small;
|
|
122
|
+
|
|
123
|
+
sortDirection = 'asc';
|
|
124
|
+
scrolledX = false;
|
|
125
|
+
scrolledEnd = false;
|
|
126
|
+
scrolledY = false;
|
|
127
|
+
stickyObserver = null;
|
|
128
|
+
|
|
129
|
+
scrollFunc = null;
|
|
130
|
+
|
|
131
|
+
mounted() {
|
|
132
|
+
if (this.$refs.scrollContainer && this.$refs.scrollContainer2) {
|
|
133
|
+
this.scrollFunc = initSyncScroll(this.$refs.scrollContainer, this.$refs.scrollContainer2, (isEnd) => {
|
|
134
|
+
this.scrolledX = true;
|
|
135
|
+
this.scrolledEnd = isEnd;
|
|
136
|
+
}, () => {
|
|
137
|
+
this.scrolledX = false;
|
|
138
|
+
});
|
|
139
|
+
} else {
|
|
140
|
+
setTimeout(() => {
|
|
141
|
+
this.scrollFunc = initSyncScroll(this.$refs.scrollContainer, this.$refs.scrollContainer2, (isEnd) => {
|
|
142
|
+
this.scrolledX = true;
|
|
143
|
+
this.scrolledEnd = isEnd;
|
|
144
|
+
}, () => {
|
|
145
|
+
this.scrolledX = false;
|
|
146
|
+
});
|
|
147
|
+
}, 1000);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (this.$refs.stickyHeader) {
|
|
151
|
+
this.stickyObserver = new IntersectionObserver(([e]) => {
|
|
152
|
+
return this.scrolledY = e.intersectionRatio < 1;
|
|
153
|
+
}, {
|
|
154
|
+
rootMargin: `-${this.$refs.stickyHeader.offsetHeight + 5}px 0px 0px 0px`,
|
|
155
|
+
threshold: [1]
|
|
156
|
+
});
|
|
157
|
+
this.stickyObserver.observe(this.$refs.stickyHeader);
|
|
158
|
+
}
|
|
159
|
+
function initSyncScroll(el1, el2, stuck, unstuck) {
|
|
160
|
+
function isScrolledEnd(el) {
|
|
161
|
+
return el.scrollWidth === el.getBoundingClientRect().width // якщо контейнер менший ширини екрану
|
|
162
|
+
|| el.scrollLeft === el.scrollWidth - el.getBoundingClientRect().width; // якщо контейнер більший ширини екрану
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function func1() {
|
|
166
|
+
el2.scrollLeft = el1.scrollLeft;
|
|
167
|
+
if (el1.scrollLeft > 0) {
|
|
168
|
+
stuck(isScrolledEnd(el1));
|
|
169
|
+
} else {
|
|
170
|
+
unstuck();
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function func2() {
|
|
175
|
+
el1.scrollLeft = el2.scrollLeft;
|
|
176
|
+
if (el2.scrollLeft > 0) {
|
|
177
|
+
stuck(isScrolledEnd(el2));
|
|
178
|
+
} else {
|
|
179
|
+
unstuck();
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (isScrolledEnd(el1)) {
|
|
184
|
+
stuck(true);
|
|
185
|
+
unstuck();
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
el1.addEventListener('scroll', func1);
|
|
189
|
+
el2.addEventListener('scroll', func2);
|
|
190
|
+
|
|
191
|
+
return [func1, func2];
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
beforeDestroy() {
|
|
196
|
+
if (this.scrollFunc) {
|
|
197
|
+
const [func1, func2] = this.scrollFunc;
|
|
198
|
+
this.$refs.scrollContainer.removeEventListener('scroll', func1);
|
|
199
|
+
this.$refs.scrollContainer2.removeEventListener('scroll', func2);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
get columnsGridStyle() {
|
|
204
|
+
return this.columns.map((column) => {
|
|
205
|
+
if (column.min) {
|
|
206
|
+
return `minmax(${column.min}px, ${column.max ? `${column.max}px` : 'auto'})`;
|
|
207
|
+
}
|
|
208
|
+
return `${column.fraction || 1}fr`;
|
|
209
|
+
}).join(' ');
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
sortBy(column, index) {
|
|
213
|
+
if (!column.sortable) {
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
const { name } = this.columns[index];
|
|
217
|
+
const direction = this.sortedColumns[name] === 'asc' ? 'desc' : 'asc';
|
|
218
|
+
this.sortedColumns = { [name]: direction };
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
</script>
|
|
@@ -2,6 +2,7 @@ import { storiesOf } from '@storybook/vue';
|
|
|
2
2
|
import itfApp from '../app/App.vue';
|
|
3
3
|
import itfButton from '../button/Button.vue';
|
|
4
4
|
import itfTable from './Table.vue';
|
|
5
|
+
import itfTable2 from './Table2.vue';
|
|
5
6
|
|
|
6
7
|
const exampleData = [{
|
|
7
8
|
Employee: 'Cool',
|
|
@@ -75,69 +76,84 @@ storiesOf('Common', module)
|
|
|
75
76
|
.add('Simple Table', () => ({
|
|
76
77
|
components: {
|
|
77
78
|
itfTable,
|
|
78
|
-
itfButton
|
|
79
|
+
itfButton,
|
|
80
|
+
itfTable2
|
|
79
81
|
},
|
|
80
82
|
data() {
|
|
81
83
|
return {
|
|
84
|
+
list: Array.from({length: 30}).map((_, i) => ({
|
|
85
|
+
Id: i,
|
|
86
|
+
Name: `Item #${i}`
|
|
87
|
+
})),
|
|
82
88
|
columns: [{
|
|
83
89
|
text: 'Employee',
|
|
84
90
|
name: 'Employee',
|
|
91
|
+
width: 200,
|
|
85
92
|
min: 250,
|
|
86
93
|
max: 250
|
|
87
94
|
}, {
|
|
88
95
|
text: 'Total',
|
|
89
96
|
name: 'Total',
|
|
97
|
+
width: 200,
|
|
90
98
|
min: 150,
|
|
91
99
|
max: 150
|
|
92
100
|
}, {
|
|
93
101
|
text: 'FTE',
|
|
94
102
|
name: 'FTE',
|
|
103
|
+
width: 200,
|
|
95
104
|
min: 100,
|
|
96
105
|
max: 100
|
|
97
106
|
}, {
|
|
98
107
|
text: 'Position',
|
|
99
108
|
name: 'Position',
|
|
109
|
+
width: 200,
|
|
100
110
|
min: 200,
|
|
101
111
|
max: 200
|
|
102
112
|
}, {
|
|
103
113
|
text: 'Office',
|
|
104
114
|
name: 'Office',
|
|
115
|
+
width: 200,
|
|
105
116
|
min: 150,
|
|
106
117
|
max: 150
|
|
107
118
|
}, {
|
|
108
119
|
text: 'Internal',
|
|
109
120
|
name: 'MinutesInternal',
|
|
121
|
+
width: 200,
|
|
110
122
|
min: 150,
|
|
111
123
|
max: 150,
|
|
112
124
|
sortable: true
|
|
113
125
|
}, {
|
|
114
126
|
text: 'External',
|
|
115
127
|
name: 'MinutesExternal',
|
|
128
|
+
width: 200,
|
|
116
129
|
min: 150,
|
|
117
130
|
max: 150,
|
|
118
131
|
sortable: true
|
|
119
132
|
}, {
|
|
120
133
|
text: 'Compensation (Internal)',
|
|
121
134
|
name: 'AmountInternal',
|
|
135
|
+
width: 200,
|
|
122
136
|
min: 200,
|
|
123
137
|
max: 200
|
|
124
138
|
}, {
|
|
125
139
|
text: 'Compensation (External)',
|
|
126
140
|
name: 'AmountExternal',
|
|
141
|
+
width: 200,
|
|
127
142
|
min: 150,
|
|
128
143
|
max: 150
|
|
129
144
|
}, {
|
|
130
145
|
text: 'Bonus/Commission',
|
|
131
146
|
name: 'AmountShare',
|
|
147
|
+
width: 200,
|
|
132
148
|
min: 150,
|
|
133
149
|
max: 150
|
|
134
150
|
}, {
|
|
135
151
|
text: 'Actions',
|
|
136
152
|
name: 'Notes',
|
|
153
|
+
width: 200,
|
|
137
154
|
min: 80,
|
|
138
155
|
max: 80
|
|
139
|
-
}]
|
|
140
|
-
list: exampleData
|
|
156
|
+
}]
|
|
141
157
|
}
|
|
142
158
|
},
|
|
143
159
|
template: `<div>
|
|
@@ -156,14 +172,16 @@ storiesOf('Common', module)
|
|
|
156
172
|
|
|
157
173
|
<h3>Example</h3>
|
|
158
174
|
|
|
159
|
-
<itf-
|
|
175
|
+
<itf-table2 :columns="columns" :rows="list" />
|
|
176
|
+
|
|
177
|
+
<!--itf-table
|
|
160
178
|
:columns="columns"
|
|
161
179
|
:rows="list"
|
|
162
180
|
>
|
|
163
181
|
<template #column.Employee="{ item }">
|
|
164
182
|
{{item.Employee}}
|
|
165
183
|
</template>
|
|
166
|
-
</itf-table
|
|
184
|
+
</itf-table-->
|
|
167
185
|
|
|
168
186
|
</div>`,
|
|
169
187
|
}))
|