@everchron/ec-shards 3.1.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ec-shards.common.js +840 -184
- package/dist/ec-shards.common.js.map +1 -1
- package/dist/ec-shards.css +1 -1
- package/dist/ec-shards.umd.js +840 -184
- package/dist/ec-shards.umd.js.map +1 -1
- package/dist/ec-shards.umd.min.js +2 -2
- package/dist/ec-shards.umd.min.js.map +1 -1
- package/package.json +1 -1
- package/src/components/animations/animations.vue +34 -1
- package/src/components/data-grid/data-grid-cell.vue +158 -0
- package/src/components/data-grid/data-grid-group.vue +31 -0
- package/src/components/data-grid/data-grid-head-cell.vue +225 -0
- package/src/components/data-grid/data-grid-row.vue +100 -0
- package/src/components/data-grid/data-grid.vue +83 -0
- package/src/components/index.js +10 -2
- package/src/components/layout-index/layout-index.vue +11 -6
- package/src/stories/Changelog.stories.mdx +7 -0
- package/src/stories/data-grid/data-grid-cell.stories.js +28 -0
- package/src/stories/data-grid/data-grid-group.stories.js +60 -0
- package/src/stories/data-grid/data-grid-head-cell.stories.js +77 -0
- package/src/stories/data-grid/data-grid-row.stories.js +91 -0
- package/src/stories/data-grid/data-grid.stories.js +48 -0
- package/src/stories/data-list/data-list-item.stories.js +8 -0
package/package.json
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
<style lang="scss">
|
|
2
|
+
@import "../../tokens/build/scss/tokens.scss";
|
|
3
|
+
|
|
2
4
|
@keyframes spin{
|
|
3
5
|
0%{
|
|
4
6
|
transform: rotate(0deg);
|
|
@@ -8,4 +10,35 @@
|
|
|
8
10
|
transform: rotate(-360deg);
|
|
9
11
|
}
|
|
10
12
|
}
|
|
11
|
-
|
|
13
|
+
|
|
14
|
+
// Table entry added animations
|
|
15
|
+
@keyframes highlight-to-white{
|
|
16
|
+
0% {
|
|
17
|
+
background: $color-yellow-3;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
100% {
|
|
21
|
+
background: $color-white;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@keyframes highlight-to-gray{
|
|
26
|
+
0% {
|
|
27
|
+
background: $color-yellow-3;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
100% {
|
|
31
|
+
background: #FBFBFC;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
@keyframes border-added{
|
|
36
|
+
0% {
|
|
37
|
+
border-bottom-color: $color-yellow-4;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
100% {
|
|
41
|
+
border-bottom-color: $color-gray-3;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
</style>
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="ecs-data-grid-cell" :style="[fixedStyles]" :class="[fixedLeft ? 'fixed-left' : '', fixedLeftLast ? 'fixed-left-last' : '', fixedRight ? 'fixed-right' : '']">
|
|
3
|
+
<div v-if="fixedRight" class="shadow" :class="fixedRight ? 'left' : ''" />
|
|
4
|
+
<div class="ecs-data-grid-cell-inner" :style="[widthStyles, paddingStyles]" :data-test="computedId">
|
|
5
|
+
<!-- @slot Tabe cell content slot. -->
|
|
6
|
+
<slot></slot>
|
|
7
|
+
</div>
|
|
8
|
+
<div v-if="fixedLeftLast" class="shadow" :class="fixedLeftLast ? 'right' : ''" />
|
|
9
|
+
</div>
|
|
10
|
+
</template>
|
|
11
|
+
|
|
12
|
+
<script>
|
|
13
|
+
import EcsAnimations from '../animations/animations'
|
|
14
|
+
|
|
15
|
+
export default {
|
|
16
|
+
components: {
|
|
17
|
+
EcsAnimations
|
|
18
|
+
},
|
|
19
|
+
|
|
20
|
+
props: {
|
|
21
|
+
/** Column identifier for the cell. The `column` is used to perform resize actions (needs to match `id` or `name` of corresponding EcsDataGridHeadCell), automatically set data-test attributes, etc. */
|
|
22
|
+
column: {
|
|
23
|
+
type: String,
|
|
24
|
+
required: true
|
|
25
|
+
},
|
|
26
|
+
/** Sets the width of the column. */
|
|
27
|
+
width: {
|
|
28
|
+
type: Number,
|
|
29
|
+
required: true
|
|
30
|
+
},
|
|
31
|
+
/** Sets the minimum width of the column. It's not possible to set a resize width that's less than the minimum width. */
|
|
32
|
+
minWidth: {
|
|
33
|
+
type: Number,
|
|
34
|
+
default: 60
|
|
35
|
+
},
|
|
36
|
+
/** Keeps the cell's column fixed at the left side. This requires the `fixedLeftOffset` prop to be set. */
|
|
37
|
+
fixedLeft: {
|
|
38
|
+
type: Boolean,
|
|
39
|
+
default: false
|
|
40
|
+
},
|
|
41
|
+
/** Sets the offset (position left) of the cell's column in pixels. If there is only one fixed column at the left, the value needs to be `0`. If there are multiple columns fixed at the left, the value needs to be the sum of the `width` of all cells the preceed this cell. */
|
|
42
|
+
fixedLeftOffset: {
|
|
43
|
+
type: Number
|
|
44
|
+
},
|
|
45
|
+
/** Determines if this is the last fixed column in the fixed group. When set, this adds a subtle shadow to the right to indicate fixed content on scroll. */
|
|
46
|
+
fixedLeftLast: {
|
|
47
|
+
type: Boolean,
|
|
48
|
+
default: false
|
|
49
|
+
},
|
|
50
|
+
/** Keeps the cell's column fixed at the right side. There should never be more than one fixedRight column and a cell can not be fixedRight and fixedLeft at the same time. */
|
|
51
|
+
fixedRight: {
|
|
52
|
+
type: Boolean,
|
|
53
|
+
default: false
|
|
54
|
+
},
|
|
55
|
+
/** Overwrites the default padding. Should only be used when the cell contains e.g. a button which has it's own padding and thus needs to be aligned with the padding of other cells. Only pass padding shorthand values, for example: `4px 0 4px 8px`.*/
|
|
56
|
+
padding: {
|
|
57
|
+
type: String
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
data () {
|
|
62
|
+
return {
|
|
63
|
+
widthStyles: {
|
|
64
|
+
width: this.width + 'px',
|
|
65
|
+
minWidth: this.minWidth + 'px',
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
computed: {
|
|
71
|
+
fixedStyles(){
|
|
72
|
+
if(this.fixedLeft)
|
|
73
|
+
if (this.fixedLeftOffset && this.fixedLeftOffset !== '')
|
|
74
|
+
return { position: 'sticky', left: this.fixedLeftOffset + 'px', zIndex: '1' }
|
|
75
|
+
else
|
|
76
|
+
return { position: 'sticky', left: '0', zIndex: '1' }
|
|
77
|
+
else if(this.fixedRight)
|
|
78
|
+
return { position: 'sticky', right: '0', zIndex: '1' }
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
paddingStyles(){
|
|
82
|
+
if (this.padding && this.padding !== '')
|
|
83
|
+
return { padding: this.padding }
|
|
84
|
+
else
|
|
85
|
+
return { padding: '8px' }
|
|
86
|
+
},
|
|
87
|
+
|
|
88
|
+
computedId(){
|
|
89
|
+
let string = this.column
|
|
90
|
+
return string.replace(/\W+/g, '-').toLowerCase() + '-column-cell'
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
}
|
|
94
|
+
</script>
|
|
95
|
+
|
|
96
|
+
<style lang="scss" scoped>
|
|
97
|
+
@import "../../tokens/build/scss/tokens.scss";
|
|
98
|
+
@import "../mixins/svg-uri";
|
|
99
|
+
|
|
100
|
+
.ecs-data-grid-cell{
|
|
101
|
+
flex-shrink: 0;
|
|
102
|
+
position: relative;
|
|
103
|
+
background: $color-white;
|
|
104
|
+
|
|
105
|
+
&-inner{
|
|
106
|
+
display: flex;
|
|
107
|
+
align-items: center;
|
|
108
|
+
position: relative;
|
|
109
|
+
font-size: $type-scale-3-font-size;
|
|
110
|
+
line-height: $type-scale-3-line-height;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.shadow{
|
|
115
|
+
position: absolute;
|
|
116
|
+
width: 10px;
|
|
117
|
+
top: 0;
|
|
118
|
+
bottom: -1px;
|
|
119
|
+
pointer-events: none;
|
|
120
|
+
|
|
121
|
+
&.left{
|
|
122
|
+
left: -10px;
|
|
123
|
+
background: linear-gradient(90deg, rgba($color-gray-15, 0) 0%, rgba($color-gray-15, .02) 65%, rgba($color-gray-15, .08) 100%);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
&.right{
|
|
127
|
+
right: -10px;
|
|
128
|
+
background: linear-gradient(90deg, rgba($color-gray-15, .12) 0%, rgba($color-gray-15, .04) 35%, rgba($color-gray-15, 0) 100%);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.ecs-data-grid-rows.striped{
|
|
133
|
+
.ecs-data-grid-row.default:nth-child(even) .ecs-data-grid-cell{
|
|
134
|
+
background-color: #FBFBFC;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.ecs-data-grid-row.added:nth-child(even) .ecs-data-grid-cell{
|
|
138
|
+
animation: highlight-to-gray 8s ease forwards;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.ecs-data-grid-row.selected .ecs-data-grid-cell{
|
|
143
|
+
background-color: #F4F9FF;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.ecs-data-grid-row.opened .ecs-data-grid-cell{
|
|
147
|
+
background-color: $color-blue-2;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.ecs-data-grid-row.droppable .ecs-data-grid-cell{
|
|
151
|
+
background-color: $color-green-2;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.ecs-data-grid-row.added .ecs-data-grid-cell{
|
|
155
|
+
animation: highlight-to-white 8s ease forwards;
|
|
156
|
+
}
|
|
157
|
+
</style>
|
|
158
|
+
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div v-show="show" class="ecs-data-grid-group">
|
|
3
|
+
<template v-if="show">
|
|
4
|
+
<slot></slot>
|
|
5
|
+
</template>
|
|
6
|
+
</div>
|
|
7
|
+
</template>
|
|
8
|
+
|
|
9
|
+
<script>
|
|
10
|
+
export default {
|
|
11
|
+
props: {
|
|
12
|
+
/** Determines if this cell group should be shown. Avoid showing more than 1 group at the same time. */
|
|
13
|
+
show: {
|
|
14
|
+
type: Boolean,
|
|
15
|
+
default: false
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
<style lang="scss" scoped>
|
|
22
|
+
@import "../../tokens/build/scss/tokens.scss";
|
|
23
|
+
@import "../mixins/svg-uri";
|
|
24
|
+
|
|
25
|
+
.ecs-data-grid-group{
|
|
26
|
+
display: flex;
|
|
27
|
+
flex-shrink: 0;
|
|
28
|
+
width: fit-content;
|
|
29
|
+
}
|
|
30
|
+
</style>
|
|
31
|
+
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="ecs-data-grid-head-cell" :style="[fixedStyles]" :class="[fixedLeft ? 'fixed-left' : '', fixedLeftLast ? 'fixed-left-last' : '', fixedRight ? 'fixed-right' : '']">
|
|
3
|
+
<div v-if="fixedRight" class="shadow" :class="fixedRight ? 'left' : ''" />
|
|
4
|
+
<div ref="resizer" class="ecs-data-grid-head-cell-inner" :style="[widthStyles, paddingStyles]" :data-test="computedId">
|
|
5
|
+
<ecs-icon v-if="icon" :type="icon" size="20" color="#202127" :title="name" />
|
|
6
|
+
<ecs-select v-else-if="select" @change="$emit('selection', $event.target.value)" type="invisible">
|
|
7
|
+
<option v-for="(option, index) in select" :key="index" :value="option.value">{{ option.name }}</option>
|
|
8
|
+
</ecs-select>
|
|
9
|
+
<div v-else class="ecs-data-grid-head-cell-text">
|
|
10
|
+
{{ name }}
|
|
11
|
+
</div>
|
|
12
|
+
<!-- @slot Slot for additional content that should appear next to the column title. -->
|
|
13
|
+
<slot></slot>
|
|
14
|
+
<button v-if="sortable" @click="sortBy" :class="[ 'sort-button', sorting ]" :title="sortTitle">
|
|
15
|
+
<svg width="14" height="20" viewBox="0 0 14 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
16
|
+
<path d="M3.99023 11.802L6.76923 14.722L9.54823 11.802" :stroke="sorting == 'descending' ? '#157EFB' : '#B9BCC2'" :stroke-width="sorting == 'descending' ? '1.5' : '1'" :opacity="sorting == 'descending' || sorting == 'none' ? '1' : '0.5'" stroke-linecap="round" stroke-linejoin="round"/>
|
|
17
|
+
<path d="M3.99023 8.722L6.76923 5.802L9.54823 8.722" :stroke="sorting == 'ascending' ? '#157EFB' : '#B9BCC2'" :stroke-width="sorting == 'ascending' ? '1.5' : '1'" :opacity="sorting == 'ascending' || sorting == 'none' ? '1' : '0.5'" stroke-linecap="round" stroke-linejoin="round"/>
|
|
18
|
+
</svg>
|
|
19
|
+
</button>
|
|
20
|
+
</div>
|
|
21
|
+
<div v-if="fixedLeftLast" class="shadow" :class="fixedLeftLast ? 'right' : ''" />
|
|
22
|
+
</div>
|
|
23
|
+
</template>
|
|
24
|
+
|
|
25
|
+
<script>
|
|
26
|
+
import EcsIcon from '../icon/icon'
|
|
27
|
+
import EcsSelect from '../select/select'
|
|
28
|
+
|
|
29
|
+
export default {
|
|
30
|
+
components: {
|
|
31
|
+
EcsIcon, EcsSelect
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
props: {
|
|
35
|
+
/** Sets the width of the column. */
|
|
36
|
+
width: {
|
|
37
|
+
type: Number,
|
|
38
|
+
required: true
|
|
39
|
+
},
|
|
40
|
+
/** The column title. When `select` is used, use the broad term that describes the data type, e.g. "Identifiers". */
|
|
41
|
+
name: {
|
|
42
|
+
type: String,
|
|
43
|
+
required: true
|
|
44
|
+
},
|
|
45
|
+
/** Set a unique id for the column. The `id` is used to target other cells inside this column to perform resize actions, automatically set data-test attributes, etc. If not set, the id will use a kebap-case String of `name`. */
|
|
46
|
+
id: {
|
|
47
|
+
type: String
|
|
48
|
+
},
|
|
49
|
+
/** Sets the minimum width of the column. It's not possible to set a resize width that's less than the minimum width. */
|
|
50
|
+
minWidth: {
|
|
51
|
+
type: Number,
|
|
52
|
+
default: 60
|
|
53
|
+
},
|
|
54
|
+
/** If set, an icon will be added to the header cell. The icon will replace any text. The list of available icon names can be found [here](https://github.com/everchron/ec-shards/tree/main/src/assets/icons). */
|
|
55
|
+
icon: {
|
|
56
|
+
type: String
|
|
57
|
+
},
|
|
58
|
+
/** Keeps the cell's column fixed at the left side. This requires the `fixedLeftOffset` prop to be set. */
|
|
59
|
+
fixedLeft: {
|
|
60
|
+
type: Boolean,
|
|
61
|
+
default: false
|
|
62
|
+
},
|
|
63
|
+
/** Sets the offset (position left) of the cell's column in pixels. If there is only one fixed column at the left, the value needs to be `0`. If there are multiple columns fixed at the left, the value needs to be the sum of the `width` of all cells the preceed this cell. */
|
|
64
|
+
fixedLeftOffset: {
|
|
65
|
+
type: Number
|
|
66
|
+
},
|
|
67
|
+
/** Determines if this is the last fixed column in the fixed group. When set, this adds a subtle shadow to the right to indicate fixed content on scroll. */
|
|
68
|
+
fixedLeftLast: {
|
|
69
|
+
type: Boolean,
|
|
70
|
+
default: false
|
|
71
|
+
},
|
|
72
|
+
/** Keeps the cell's column fixed at the right side. There should never be more than one fixedRight column and a cell can not be fixedRight and fixedLeft at the same time. */
|
|
73
|
+
fixedRight: {
|
|
74
|
+
type: Boolean,
|
|
75
|
+
default: false
|
|
76
|
+
},
|
|
77
|
+
/** If passed, the head cell won't render the slot in the text, but a select menu with the passed options instead. This is useful when one column should be able to switch the data that is shown in it. For example, you could have a column with a selector in the head cell which allows you to switch between ECID, Bates Range, and Trial Exhibit No. The array needs to contain objects with `value` and `name`. */
|
|
78
|
+
select: {
|
|
79
|
+
type: Array
|
|
80
|
+
},
|
|
81
|
+
/** Determines if the column should be sortable. */
|
|
82
|
+
sortable: {
|
|
83
|
+
type: Boolean,
|
|
84
|
+
default: false
|
|
85
|
+
},
|
|
86
|
+
/** Determines the current sort order. */
|
|
87
|
+
sorting: {
|
|
88
|
+
type: String,
|
|
89
|
+
validator: v => ['none', 'ascending', 'descending'].includes(v),
|
|
90
|
+
default: 'none'
|
|
91
|
+
},
|
|
92
|
+
/** Overwrites the default padding. Should only be used when the cell contains e.g. a button which has it's own padding and thus needs to be aligned with the padding of other cells. Only pass padding shorthand values, for example: `4px 0 4px 8px`.*/
|
|
93
|
+
padding: {
|
|
94
|
+
type: String
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
|
|
98
|
+
data () {
|
|
99
|
+
return {
|
|
100
|
+
widthStyles: {
|
|
101
|
+
width: this.width + 'px',
|
|
102
|
+
minWidth: this.minWidth + 'px',
|
|
103
|
+
},
|
|
104
|
+
newSort: this.sorting,
|
|
105
|
+
resizeWidth: null
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
computed: {
|
|
110
|
+
fixedStyles(){
|
|
111
|
+
if(this.fixedLeft)
|
|
112
|
+
if (this.fixedLeftOffset && this.fixedLeftOffset !== '')
|
|
113
|
+
return { position: 'sticky', left: this.fixedLeftOffset + 'px', zIndex: '1' }
|
|
114
|
+
else
|
|
115
|
+
return { position: 'sticky', left: '0', zIndex: '1' }
|
|
116
|
+
else if(this.fixedRight)
|
|
117
|
+
return { position: 'sticky', right: '0', zIndex: '1' }
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
paddingStyles(){
|
|
121
|
+
if (this.padding && this.padding !== '')
|
|
122
|
+
return { padding: this.padding }
|
|
123
|
+
else if (this.icon && this.icon !== '')
|
|
124
|
+
return { padding: '0 8px 0 4px' }
|
|
125
|
+
else if (this.select && this.select !== '')
|
|
126
|
+
return { padding: '0 8px 0 0' }
|
|
127
|
+
else
|
|
128
|
+
return { padding: '0 8px' }
|
|
129
|
+
},
|
|
130
|
+
|
|
131
|
+
sortTitle(){
|
|
132
|
+
switch (this.sorting){
|
|
133
|
+
case 'ascending':
|
|
134
|
+
return 'Sorting ' + this.name + ' ascending'
|
|
135
|
+
case 'descending':
|
|
136
|
+
return 'Sorting ' + this.name + ' descending'
|
|
137
|
+
default:
|
|
138
|
+
return 'Sort by ' + this.name
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
|
|
142
|
+
computedId(){
|
|
143
|
+
let string = this.name
|
|
144
|
+
if(this.id && this.id !== '')
|
|
145
|
+
string = this.id
|
|
146
|
+
return string.replace(/\W+/g, '-').toLowerCase() + '-column-head'
|
|
147
|
+
}
|
|
148
|
+
},
|
|
149
|
+
|
|
150
|
+
methods: {
|
|
151
|
+
sortBy(){
|
|
152
|
+
if(this.sorting == 'none')
|
|
153
|
+
this.newSort = 'descending'
|
|
154
|
+
else if(this.sorting == 'ascending')
|
|
155
|
+
this.newSort = 'descending'
|
|
156
|
+
else
|
|
157
|
+
this.newSort = 'ascending'
|
|
158
|
+
|
|
159
|
+
/** Emitted when the sort button is clicked. Returns the new sort order for the column. */
|
|
160
|
+
this.$emit('sortby', this.newSort)
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
</script>
|
|
165
|
+
|
|
166
|
+
<style lang="scss" scoped>
|
|
167
|
+
@import "../../tokens/build/scss/tokens.scss";
|
|
168
|
+
@import "../mixins/svg-uri";
|
|
169
|
+
|
|
170
|
+
.ecs-data-grid-head-cell{
|
|
171
|
+
flex-shrink: 0;
|
|
172
|
+
background: $color-white;
|
|
173
|
+
position: relative;
|
|
174
|
+
|
|
175
|
+
&-inner{
|
|
176
|
+
display: flex;
|
|
177
|
+
align-items: center;
|
|
178
|
+
column-gap: $spacing-10;
|
|
179
|
+
height: 40px;
|
|
180
|
+
position: relative;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
&-text{
|
|
184
|
+
font-size: $type-scale-3-font-size;
|
|
185
|
+
line-height: $type-scale-3-line-height;
|
|
186
|
+
font-weight: $font-weight-medium;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.ecs-form-select{
|
|
190
|
+
flex: 1;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.sort-button{
|
|
195
|
+
background: none;
|
|
196
|
+
padding: 0 1px;
|
|
197
|
+
height: 24px;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
.shadow{
|
|
201
|
+
position: absolute;
|
|
202
|
+
width: 10px;
|
|
203
|
+
top: 0;
|
|
204
|
+
bottom: 0;
|
|
205
|
+
pointer-events: none;
|
|
206
|
+
|
|
207
|
+
&.left{
|
|
208
|
+
left: -10px;
|
|
209
|
+
background: linear-gradient(90deg, rgba($color-gray-15, 0) 0%, rgba($color-gray-15, .02) 65%, rgba($color-gray-15, .08) 100%);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
&.right{
|
|
213
|
+
right: -10px;
|
|
214
|
+
background: linear-gradient(90deg, rgba($color-gray-15, .12) 0%, rgba($color-gray-15, .04) 35%, rgba($color-gray-15, 0) 100%);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
</style>
|
|
218
|
+
|
|
219
|
+
<style lang="scss">
|
|
220
|
+
@import "../../tokens/build/scss/tokens.scss";
|
|
221
|
+
|
|
222
|
+
.ecs-data-grid-head-cell .ecs-form-select select{
|
|
223
|
+
font-weight: $font-weight-medium;
|
|
224
|
+
}
|
|
225
|
+
</style>
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="ecs-data-grid-row" :class="state">
|
|
3
|
+
<div v-if="state == 'droppable'" @click="handleDropzoneClick" class="ecs-data-grid-row-drop-zone" />
|
|
4
|
+
|
|
5
|
+
<!-- @slot All of the row's cells go here. There should **never** be any other child component other than EcsDataGridCell be used. -->
|
|
6
|
+
<slot></slot>
|
|
7
|
+
</div>
|
|
8
|
+
</template>
|
|
9
|
+
|
|
10
|
+
<script>
|
|
11
|
+
|
|
12
|
+
export default {
|
|
13
|
+
props: {
|
|
14
|
+
/** Determines the state of the table row. */
|
|
15
|
+
state: {
|
|
16
|
+
type: String,
|
|
17
|
+
validator: v => ['default', 'selected', 'opened', 'added', 'droppable'].includes(v),
|
|
18
|
+
default: 'default'
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
methods: {
|
|
23
|
+
handleDropzoneClick(){
|
|
24
|
+
/** Emitted when clicking (eg. dropping a bunch of other rows via lift & drop) the rows dropzone. */
|
|
25
|
+
this.$emit('rowdrop')
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<style lang="scss" scoped>
|
|
32
|
+
@import "../../tokens/build/scss/tokens.scss";
|
|
33
|
+
@import "../mixins/svg-uri";
|
|
34
|
+
|
|
35
|
+
.ecs-data-grid-row{
|
|
36
|
+
display: flex;
|
|
37
|
+
flex-shrink: 0;
|
|
38
|
+
width: fit-content;
|
|
39
|
+
min-width: 100%;
|
|
40
|
+
position: relative;
|
|
41
|
+
border-bottom: 1px solid $color-gray-3;
|
|
42
|
+
|
|
43
|
+
&:before{
|
|
44
|
+
content: "";
|
|
45
|
+
position: absolute;
|
|
46
|
+
inset: 0;
|
|
47
|
+
opacity: .04;
|
|
48
|
+
z-index: 2;
|
|
49
|
+
pointer-events: none;
|
|
50
|
+
background-blend-mode: multiply;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
&:hover:before{
|
|
54
|
+
background-color: $color-gray-10;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
&.selected{
|
|
58
|
+
border-bottom-color: $color-blue-3;
|
|
59
|
+
|
|
60
|
+
&:hover:before{
|
|
61
|
+
background-color: $color-blue-5;
|
|
62
|
+
opacity: .1;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
&.opened{
|
|
67
|
+
border-bottom-color: $color-blue-3;
|
|
68
|
+
|
|
69
|
+
&:hover:before{
|
|
70
|
+
background-color: $color-blue-5;
|
|
71
|
+
opacity: .1;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
> .ecs-data-grid-cell:first-child{
|
|
75
|
+
box-shadow: 2px 0 0 $color-blue-8 inset;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
&.droppable{
|
|
80
|
+
border-bottom-color: $color-green-4;
|
|
81
|
+
cursor: copy;
|
|
82
|
+
|
|
83
|
+
&:hover:before{
|
|
84
|
+
background-color: $color-green-6;
|
|
85
|
+
opacity: .15;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
&.added{
|
|
90
|
+
animation: border-added 8s ease forwards;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
&-drop-zone{
|
|
94
|
+
position: absolute;
|
|
95
|
+
inset: 0;
|
|
96
|
+
z-index: 2;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
</style>
|
|
100
|
+
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="ecs-data-grid scrollbar">
|
|
3
|
+
<div class="ecs-data-grid-head">
|
|
4
|
+
<!-- @slot Slot for the table head row cells. -->
|
|
5
|
+
<slot name="head"></slot>
|
|
6
|
+
</div>
|
|
7
|
+
|
|
8
|
+
<div v-if="$slots.empty" class="ecs-data-grid-empty">
|
|
9
|
+
<!-- @slot Slot for empty state. -->
|
|
10
|
+
<slot name="empty"></slot>
|
|
11
|
+
</div>
|
|
12
|
+
|
|
13
|
+
<div v-else class="ecs-data-grid-rows" :class="striped ? 'striped' : ''">
|
|
14
|
+
<!-- @slot Default slot for the table rows. -->
|
|
15
|
+
<slot></slot>
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
</template>
|
|
19
|
+
|
|
20
|
+
<script>
|
|
21
|
+
export default {
|
|
22
|
+
props: {
|
|
23
|
+
/** Applies striping to the body rows background. */
|
|
24
|
+
striped: {
|
|
25
|
+
type: Boolean,
|
|
26
|
+
default: true
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
data () {
|
|
31
|
+
return {
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
methods : {
|
|
36
|
+
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
</script>
|
|
40
|
+
|
|
41
|
+
<style lang="scss" scoped>
|
|
42
|
+
@import "../../tokens/build/scss/tokens.scss";
|
|
43
|
+
@import "../mixins/svg-uri";
|
|
44
|
+
|
|
45
|
+
.ecs-data-grid{
|
|
46
|
+
width: 100%;
|
|
47
|
+
height: 100%;
|
|
48
|
+
display: flex;
|
|
49
|
+
flex-direction: column;
|
|
50
|
+
position: relative;
|
|
51
|
+
overflow: auto;
|
|
52
|
+
background: $color-white;
|
|
53
|
+
|
|
54
|
+
&.non-sticky{
|
|
55
|
+
height: auto;
|
|
56
|
+
overflow: initial;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
&-head{
|
|
60
|
+
height: 40px;
|
|
61
|
+
display: flex;
|
|
62
|
+
align-items: center;
|
|
63
|
+
flex-shrink: 0;
|
|
64
|
+
width: fit-content;
|
|
65
|
+
min-width: 100%;
|
|
66
|
+
background: $color-white;
|
|
67
|
+
z-index: 3;
|
|
68
|
+
position: sticky;
|
|
69
|
+
top: 0;
|
|
70
|
+
box-shadow: 0 1px 0 rgba($color-gray-6, .4);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
&-rows{
|
|
74
|
+
flex: 1;
|
|
75
|
+
min-width: fit-content;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
&-empty{
|
|
79
|
+
flex: 1;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
</style>
|
|
83
|
+
|
package/src/components/index.js
CHANGED
|
@@ -30,6 +30,11 @@ import EcsComment from "./comment/comment.vue"
|
|
|
30
30
|
import EcsCommentList from "./comment-list/comment-list.vue"
|
|
31
31
|
import EcsDataCard from "./data-card/data-card.vue"
|
|
32
32
|
import EcsDataCardList from "./data-card-list/data-card-list.vue"
|
|
33
|
+
import EcsDataGrid from "./data-grid/data-grid.vue"
|
|
34
|
+
import EcsDataGridRow from "./data-grid/data-grid-row.vue"
|
|
35
|
+
import EcsDataGridHeadCell from "./data-grid/data-grid-head-cell.vue"
|
|
36
|
+
import EcsDataGridGroup from "./data-grid/data-grid-group.vue"
|
|
37
|
+
import EcsDataGridCell from "./data-grid/data-grid-cell.vue"
|
|
33
38
|
import EcsDataList from "./data-list/data-list.vue"
|
|
34
39
|
import EcsDataListItem from "./data-list-item/data-list-item.vue"
|
|
35
40
|
import EcsDialog from "./dialog/dialog.vue"
|
|
@@ -114,7 +119,6 @@ import EcsTabBar from "./tab-bar/tab-bar.vue"
|
|
|
114
119
|
import EcsTabButton from "./tab-button/tab-button.vue"
|
|
115
120
|
import EcsTag from "./tag/tag.vue"
|
|
116
121
|
import EcsTagCloud from "./tag-cloud/tag-cloud.vue"
|
|
117
|
-
//import EcsTiptap from "./tiptap/tiptap.vue"
|
|
118
122
|
import EcsText from "./text/text.vue"
|
|
119
123
|
import EcsToast from "./toast/toast.vue"
|
|
120
124
|
import EcsToasts from "./toasts/toasts.vue"
|
|
@@ -154,6 +158,11 @@ const Components = {
|
|
|
154
158
|
EcsCommentList,
|
|
155
159
|
EcsDataCard,
|
|
156
160
|
EcsDataCardList,
|
|
161
|
+
EcsDataGrid,
|
|
162
|
+
EcsDataGridGroup,
|
|
163
|
+
EcsDataGridRow,
|
|
164
|
+
EcsDataGridHeadCell,
|
|
165
|
+
EcsDataGridCell,
|
|
157
166
|
EcsDataList,
|
|
158
167
|
EcsDataListItem,
|
|
159
168
|
EcsDialog,
|
|
@@ -238,7 +247,6 @@ const Components = {
|
|
|
238
247
|
EcsTabButton,
|
|
239
248
|
EcsTag,
|
|
240
249
|
EcsTagCloud,
|
|
241
|
-
//EcsTiptap,
|
|
242
250
|
EcsText,
|
|
243
251
|
EcsToast,
|
|
244
252
|
EcsToasts,
|