@itfin/components 1.3.84 → 1.3.87
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 +1 -1
- package/src/assets/scss/_variables.scss +3 -3
- package/src/assets/scss/components/_button.scss +0 -1
- package/src/assets/scss/components/_range.scss +276 -0
- package/src/assets/scss/components/_toaster.scss +4 -4
- package/src/assets/scss/main.scss +1 -0
- package/src/components/app/message.js +4 -6
- package/src/components/filter/FilterAmountRange.vue +93 -0
- package/src/components/filter/FilterBadge.vue +182 -0
- package/src/components/filter/FilterFacetsList.vue +206 -0
- package/src/components/filter/FilterPanel.vue +184 -0
- package/src/components/filter/index.stories.js +3 -18
- package/src/components/panels/PanelList.vue +36 -11
- package/src/components/range/Range.vue +1261 -0
- package/src/components/range/utils.js +74 -0
- package/src/components/text-field/TextField.vue +2 -1
- package/src/locales/en.js +10 -0
- package/src/locales/uk.js +10 -0
- package/src/components/filter/ConditionGroup.vue +0 -196
- package/src/components/filter/FilterInput.vue +0 -64
- package/src/components/filter/constants.js +0 -20
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// Unsharp text [#166](https://github.com/NightCatSama/vue-slider-component/issues/166)
|
|
2
|
+
export const roundToDPR = (function () {
|
|
3
|
+
const r = typeof window !== 'undefined' ? window.devicePixelRatio || 1 : 1
|
|
4
|
+
return value => Math.round(value * r) / r
|
|
5
|
+
})()
|
|
6
|
+
|
|
7
|
+
export const isMobile = (() => {
|
|
8
|
+
const userAgentInfo = navigator.userAgent.toLowerCase()
|
|
9
|
+
const agents = ["Android", "iPhone",
|
|
10
|
+
"SymbianOS", "Windows Phone",
|
|
11
|
+
"iPad", "iPod"]
|
|
12
|
+
let flag = false
|
|
13
|
+
for (let v = 0; v < agents.length; v++) {
|
|
14
|
+
if (userAgentInfo.indexOf(agents[v].toLowerCase()) > 0) {
|
|
15
|
+
flag = true
|
|
16
|
+
break
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return flag
|
|
20
|
+
})()
|
|
21
|
+
|
|
22
|
+
export function isArray(input) {
|
|
23
|
+
if (Array.prototype.isArray) {
|
|
24
|
+
return Array.isArray(input)
|
|
25
|
+
}
|
|
26
|
+
return input instanceof Array || Object.prototype.toString.call(input) === '[object Array]'
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function isDiff(a, b) {
|
|
30
|
+
if (Object.prototype.toString.call(a) !== Object.prototype.toString.call(b)) {
|
|
31
|
+
return true
|
|
32
|
+
} else if (isArray(a) && a.length === b.length) {
|
|
33
|
+
return a.some((v, i) => v !== b[i])
|
|
34
|
+
}
|
|
35
|
+
return a !== b
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
let elementStyle = document.createElement('div').style
|
|
39
|
+
let vendor = (() => {
|
|
40
|
+
let transformNames = {
|
|
41
|
+
webkit: 'webkitTransform',
|
|
42
|
+
Moz: 'MozTransform',
|
|
43
|
+
O: 'OTransform',
|
|
44
|
+
ms: 'msTransform',
|
|
45
|
+
standard: 'transform'
|
|
46
|
+
}
|
|
47
|
+
for (let key in transformNames) {
|
|
48
|
+
if (elementStyle[transformNames[key]] !== undefined) {
|
|
49
|
+
return key
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return false
|
|
53
|
+
})()
|
|
54
|
+
|
|
55
|
+
export function prefixStyle(style) {
|
|
56
|
+
if (vendor === false) {
|
|
57
|
+
return false
|
|
58
|
+
}
|
|
59
|
+
if (vendor === 'standard') {
|
|
60
|
+
if (style === 'transitionEnd') {
|
|
61
|
+
return 'transitionend'
|
|
62
|
+
}
|
|
63
|
+
return style
|
|
64
|
+
}
|
|
65
|
+
return vendor + style.charAt(0).toUpperCase() + style.substr(1)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function addEvent(el, type, fn, capture) {
|
|
69
|
+
el.addEventListener(type, fn, {passive: false, capture: !!capture})
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function removeEvent(el, type, fn, capture) {
|
|
73
|
+
el.removeEventListener(type, fn, {passive: false, capture: !!capture})
|
|
74
|
+
}
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
ref="input"
|
|
12
12
|
autocomplete="off"
|
|
13
13
|
:placeholder="placeholder"
|
|
14
|
-
:class="{ 'is-invalid': isInvalid(), 'is-valid': isSuccess() }"
|
|
14
|
+
:class="{ 'is-invalid': isInvalid(), 'is-valid': isSuccess(), 'form-control-sm': small }"
|
|
15
15
|
class="itf-text-field__input form-control"
|
|
16
16
|
:type="type"
|
|
17
17
|
:value="value"
|
|
@@ -67,6 +67,7 @@ class itfTextField extends Vue {
|
|
|
67
67
|
@Prop(Boolean) clearable;
|
|
68
68
|
@Prop(Boolean) disabled;
|
|
69
69
|
@Prop(Boolean) readonly;
|
|
70
|
+
@Prop(Boolean) small;
|
|
70
71
|
@Prop({ type: String, default: 'text' }) type;
|
|
71
72
|
@Prop({ type: [Number, String], default: 0 }) delayInput;
|
|
72
73
|
|
package/src/locales/en.js
CHANGED
|
@@ -125,5 +125,15 @@ module.exports = {
|
|
|
125
125
|
itemsPerPage: 'Items per page',
|
|
126
126
|
previous: 'Previous',
|
|
127
127
|
next: 'Next'
|
|
128
|
+
},
|
|
129
|
+
filter: {
|
|
130
|
+
search: 'Search',
|
|
131
|
+
deselectAll: 'Deselect all',
|
|
132
|
+
selectAll: 'Select all',
|
|
133
|
+
showSelected: 'Show selected',
|
|
134
|
+
showAll: 'Show all',
|
|
135
|
+
noResults: 'No results',
|
|
136
|
+
showMore: 'show all ({count})',
|
|
137
|
+
hideMore: 'hide',
|
|
128
138
|
}
|
|
129
139
|
};
|
package/src/locales/uk.js
CHANGED
|
@@ -125,5 +125,15 @@ module.exports = {
|
|
|
125
125
|
calculateCountNotEmpty: 'Кількість не порожніх',
|
|
126
126
|
calculatePercentEmpty: 'Відсоток порожніх',
|
|
127
127
|
calculatePercentNotEmpty: 'Відсоток не порожніх',
|
|
128
|
+
},
|
|
129
|
+
filter: {
|
|
130
|
+
search: 'Пошук',
|
|
131
|
+
deselectAll: 'Скасувати вибір',
|
|
132
|
+
selectAll: 'Вибрати все',
|
|
133
|
+
showSelected: 'Показати вибрані',
|
|
134
|
+
showAll: 'Показати все',
|
|
135
|
+
noResults: 'Немає результатів',
|
|
136
|
+
showMore: 'показати всі ({count})',
|
|
137
|
+
hideMore: 'сховати',
|
|
128
138
|
}
|
|
129
139
|
};
|
|
@@ -1,196 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
|
|
3
|
-
<div class="b-condition-group-input w-100 pt-1 pb-2 px-2">
|
|
4
|
-
<div class="d-flex align-items-start">
|
|
5
|
-
<div v-if="value.conditions.length > 1" class="condition-group-type">
|
|
6
|
-
<itf-select
|
|
7
|
-
:value="value.link"
|
|
8
|
-
:reduce="(item) => item.value"
|
|
9
|
-
:options="[{ label: 'AND', value: 'and' }, { label: 'OR', value: 'or' }]"
|
|
10
|
-
@input="onLinkUpdate"
|
|
11
|
-
/>
|
|
12
|
-
</div>
|
|
13
|
-
<div class="flex-1 pt-1">
|
|
14
|
-
<div v-for="(filter, n) in value.conditions" :key="n" :class="{'tree-node': value.conditions.length > 1}">
|
|
15
|
-
<div class="d-flex align-items-start">
|
|
16
|
-
<div class="flex-grow-1 py-2 me-2">
|
|
17
|
-
<itf-condition-group
|
|
18
|
-
v-if="filter.link"
|
|
19
|
-
:level="level + 1"
|
|
20
|
-
class="rounded"
|
|
21
|
-
:value="filter"
|
|
22
|
-
@input="onFilterUpdate(n, $event)"
|
|
23
|
-
:class="{'bg-group1': level === 0, 'bg-group2': level === 1}"
|
|
24
|
-
/>
|
|
25
|
-
<filter-input
|
|
26
|
-
v-else
|
|
27
|
-
:value="filter"
|
|
28
|
-
@input="onFilterUpdate(n, $event)"
|
|
29
|
-
/>
|
|
30
|
-
</div>
|
|
31
|
-
<div class="pt-2 mt-1">
|
|
32
|
-
<itf-button small icon @click="removeField(n)">
|
|
33
|
-
<itf-icon name="trash" />
|
|
34
|
-
</itf-button>
|
|
35
|
-
</div>
|
|
36
|
-
</div>
|
|
37
|
-
</div>
|
|
38
|
-
</div>
|
|
39
|
-
</div>
|
|
40
|
-
|
|
41
|
-
<itf-button small secondary @click="addCondition">
|
|
42
|
-
<itf-icon name="plus" />
|
|
43
|
-
Add condition
|
|
44
|
-
</itf-button>
|
|
45
|
-
<itf-button v-if="level < maxDepth" small secondary @click="addConditionGroup">
|
|
46
|
-
<itf-icon name="plus" />
|
|
47
|
-
Add group
|
|
48
|
-
</itf-button>
|
|
49
|
-
</div>
|
|
50
|
-
|
|
51
|
-
</template>
|
|
52
|
-
<style>
|
|
53
|
-
.b-condition-group-input {
|
|
54
|
-
--b-filterGroupBorder: rgba(0,0,0,.05);
|
|
55
|
-
--b-filterGroup1Bg: #f9fafb;
|
|
56
|
-
--b-filterGroup2Bg: #f1f2f4;
|
|
57
|
-
|
|
58
|
-
[data-theme="dark"] & {
|
|
59
|
-
--b-filterGroup1Bg: #303436;
|
|
60
|
-
--b-filterGroup2Bg: #3a3e41;
|
|
61
|
-
--b-filterGroupBorder: hsla(0,0%,100%,.03);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
.bg-group1 {
|
|
65
|
-
background: var(--b-filterGroup1Bg);
|
|
66
|
-
border: 1px solid var(--b-filterGroupBorder);
|
|
67
|
-
}
|
|
68
|
-
.bg-group2 {
|
|
69
|
-
background: var(--b-filterGroup2Bg);
|
|
70
|
-
border: 1px solid var(--b-filterGroupBorder);
|
|
71
|
-
}
|
|
72
|
-
.condition-group-type {
|
|
73
|
-
width: 85px;
|
|
74
|
-
z-index: 10;
|
|
75
|
-
margin-right: 1rem;
|
|
76
|
-
margin-top: .5rem;
|
|
77
|
-
margin-bottom: .5rem;
|
|
78
|
-
position: relative;
|
|
79
|
-
}
|
|
80
|
-
.flex-1 {
|
|
81
|
-
flex: 1 1 0%;
|
|
82
|
-
}
|
|
83
|
-
.tree-node {
|
|
84
|
-
--h-line-position: 1.5rem;
|
|
85
|
-
--line-color: #D2D5DF;
|
|
86
|
-
--line-width: 1px;
|
|
87
|
-
--line-radius: 10px;
|
|
88
|
-
--line-connection-position: -3.5rem;
|
|
89
|
-
--node-space: .5rem;
|
|
90
|
-
margin-bottom: var(--node-space);
|
|
91
|
-
position: relative;
|
|
92
|
-
|
|
93
|
-
&:first-child:before {
|
|
94
|
-
border-left: solid var(--line-width) var(--line-color);
|
|
95
|
-
top: var(--h-line-position);
|
|
96
|
-
height: calc(100% - var(--h-line-position) + var(--node-space));
|
|
97
|
-
width: var(--line-radius);
|
|
98
|
-
}
|
|
99
|
-
&:before {
|
|
100
|
-
display: inline-block;
|
|
101
|
-
border-left: solid var(--line-width) var(--line-color);
|
|
102
|
-
content: "";
|
|
103
|
-
height: calc(100% + var(--node-space));
|
|
104
|
-
position: absolute;
|
|
105
|
-
left: var(--line-connection-position);
|
|
106
|
-
}
|
|
107
|
-
&:first-child:after {
|
|
108
|
-
height: var(--line-radius);
|
|
109
|
-
}
|
|
110
|
-
&:after {
|
|
111
|
-
display: inline-block;
|
|
112
|
-
border-top: solid var(--line-width) var(--line-color);
|
|
113
|
-
content: "";
|
|
114
|
-
width: calc(var(--line-connection-position)* -1);
|
|
115
|
-
position: absolute;
|
|
116
|
-
top: var(--h-line-position);
|
|
117
|
-
left: var(--line-connection-position);
|
|
118
|
-
}
|
|
119
|
-
&:last-child:before {
|
|
120
|
-
border-color: var(--line-color);
|
|
121
|
-
top: 0%;
|
|
122
|
-
height: var(--h-line-position);
|
|
123
|
-
width: var(--line-radius);
|
|
124
|
-
border-bottom-left-radius: var(--line-radius);
|
|
125
|
-
}
|
|
126
|
-
&:last-child:after {
|
|
127
|
-
border-top: none;
|
|
128
|
-
border-bottom: solid var(--line-width) var(--line-color);
|
|
129
|
-
border-left: solid var(--line-width) var(--line-color);
|
|
130
|
-
height: var(--line-radius);
|
|
131
|
-
border-bottom-left-radius: var(--line-radius);
|
|
132
|
-
top: calc(var(--h-line-position) - var(--line-radius));
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
</style>
|
|
136
|
-
<script>
|
|
137
|
-
import { Component, Prop, Model, Vue, Watch } from 'vue-property-decorator';
|
|
138
|
-
import itfButton from '@itfin/components/src/components/button/Button.vue';
|
|
139
|
-
import itfTextField from '@itfin/components/src/components/text-field/TextField.vue';
|
|
140
|
-
import itfDropdown from '@itfin/components/src/components/dropdown/Dropdown.vue';
|
|
141
|
-
import itfSelect from '@itfin/components/src/components/select/Select.vue';
|
|
142
|
-
import itfIcon from '@itfin/components/src/components/icon/Icon.vue';
|
|
143
|
-
import FilterInput from '~/components/Panels/FilterInput.vue';
|
|
144
|
-
|
|
145
|
-
export default @Component({
|
|
146
|
-
name: 'itfConditionGroup',
|
|
147
|
-
components: {
|
|
148
|
-
itfTextField,
|
|
149
|
-
itfSelect,
|
|
150
|
-
itfDropdown,
|
|
151
|
-
itfButton,
|
|
152
|
-
itfIcon,
|
|
153
|
-
FilterInput
|
|
154
|
-
}
|
|
155
|
-
})
|
|
156
|
-
class ConditionGroup extends Vue {
|
|
157
|
-
@Model('input', { default: () => ({ link: 'and', conditions: [] }) }) value;
|
|
158
|
-
@Prop({ default: 0 }) level;
|
|
159
|
-
@Prop({ default: 1 }) maxDepth;
|
|
160
|
-
|
|
161
|
-
onLinkUpdate(link) {
|
|
162
|
-
this.$emit('input', { ...this.value, link });
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
onFilterUpdate(index, filter) {
|
|
166
|
-
this.applyValue((conditions) => {
|
|
167
|
-
conditions[index] = filter;
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
applyValue(func) {
|
|
172
|
-
const newValue = { ...this.value, conditions: [...this.value.conditions] };
|
|
173
|
-
func(newValue.conditions);
|
|
174
|
-
this.$emit('input', newValue);
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
addCondition() {
|
|
178
|
-
this.applyValue((conditions) => {
|
|
179
|
-
conditions.push({ operator: 'is', values: [] });
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
addConditionGroup() {
|
|
184
|
-
this.applyValue((conditions) => {
|
|
185
|
-
conditions.push({ link: 'and', conditions: [] });
|
|
186
|
-
});
|
|
187
|
-
// this.filters.push({ type: 'group' });
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
removeField(index) {
|
|
191
|
-
this.applyValue((conditions) => {
|
|
192
|
-
conditions.splice(index, 1);
|
|
193
|
-
});
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
</script>
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
|
|
3
|
-
<div class="d-flex">
|
|
4
|
-
<div class="w-25">
|
|
5
|
-
<itf-select :options="fields" />
|
|
6
|
-
</div>
|
|
7
|
-
<div class="w-25 px-1">
|
|
8
|
-
<itf-select
|
|
9
|
-
:reduce="(item) => item.id"
|
|
10
|
-
:get-option-label="(item) => item.title"
|
|
11
|
-
:options="conditions"
|
|
12
|
-
>
|
|
13
|
-
<template #selected-option="{ option }">
|
|
14
|
-
<span class="sign-box"> {{option.title}}</span>
|
|
15
|
-
</template>
|
|
16
|
-
<template #option="{ option }">
|
|
17
|
-
{{option.title}}
|
|
18
|
-
</template>
|
|
19
|
-
</itf-select>
|
|
20
|
-
</div>
|
|
21
|
-
<div class="w-50">
|
|
22
|
-
<itf-text-field />
|
|
23
|
-
</div>
|
|
24
|
-
</div>
|
|
25
|
-
|
|
26
|
-
</template>
|
|
27
|
-
<style>
|
|
28
|
-
</style>
|
|
29
|
-
<script>
|
|
30
|
-
import { Component, Prop, Model, Vue, Watch } from 'vue-property-decorator';
|
|
31
|
-
import itfButton from '@itfin/components/src/components/button/Button.vue';
|
|
32
|
-
import itfTextField from '@itfin/components/src/components/text-field/TextField.vue';
|
|
33
|
-
import itfSelect from '@itfin/components/src/components/select/Select.vue';
|
|
34
|
-
import itfDropdown from '@itfin/components/src/components/dropdown/Dropdown.vue';
|
|
35
|
-
import itfIcon from '@itfin/components/src/components/icon/Icon.vue';
|
|
36
|
-
|
|
37
|
-
const conditions = [
|
|
38
|
-
{ id: 'eq', title: 'equal', sign: '=' },
|
|
39
|
-
{ id: 'notEq', title: 'not equal', sign: '≠' },
|
|
40
|
-
{ id: 'contains', title: 'contains', sign: '∋' },
|
|
41
|
-
{ id: 'noContains', title: 'not contains', sign: '∌' },
|
|
42
|
-
{ id: 'startsWith', title: 'starts with', sign: 'A…' },
|
|
43
|
-
{ id: 'endsWith', title: 'ends with', sign: '…Z' },
|
|
44
|
-
// { id: 'exists', title: 'exists', sign: '∃' }
|
|
45
|
-
];
|
|
46
|
-
|
|
47
|
-
export default @Component({
|
|
48
|
-
name: 'itfFilterInput',
|
|
49
|
-
components: {
|
|
50
|
-
itfTextField,
|
|
51
|
-
itfSelect,
|
|
52
|
-
itfDropdown,
|
|
53
|
-
itfButton,
|
|
54
|
-
itfIcon
|
|
55
|
-
}
|
|
56
|
-
})
|
|
57
|
-
class FilterInput extends Vue {
|
|
58
|
-
@Prop() fields;
|
|
59
|
-
|
|
60
|
-
get conditions() {
|
|
61
|
-
return conditions;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
</script>
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export function getOperatorsByType(type) {
|
|
4
|
-
const operations = [
|
|
5
|
-
{
|
|
6
|
-
type: 'string',
|
|
7
|
-
operators: [
|
|
8
|
-
{ id: 'eq', title: 'equal', sign: '=' },
|
|
9
|
-
{ id: 'notEq', title: 'not equal', sign: '≠' },
|
|
10
|
-
{ id: 'contains', title: 'contains', sign: '∋' },
|
|
11
|
-
{ id: 'noContains', title: 'not contains', sign: '∌' },
|
|
12
|
-
{ id: 'startsWith', title: 'starts with', sign: 'A…' },
|
|
13
|
-
{ id: 'endsWith', title: 'ends with', sign: '…Z' },
|
|
14
|
-
// { id: 'exists', title: 'exists', sign: '∃' }
|
|
15
|
-
]
|
|
16
|
-
}
|
|
17
|
-
];
|
|
18
|
-
|
|
19
|
-
return operations.find((operation) => operation.type === type).operators;
|
|
20
|
-
}
|