@itfin/components 1.3.32 → 1.3.34
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/components/select/_selected.scss +1 -1
- package/src/components/datepicker/DatePickerInline.vue +10 -3
- package/src/components/datepicker/DateRangePickerInline.vue +10 -3
- package/src/components/editable/EditableList.vue +1 -0
- package/src/components/filter/FilterBadge.vue +36 -19
- package/src/components/filter/FilterControl.vue +105 -0
- package/src/components/filter/constants.js +7 -6
- package/src/components/filter/index.stories.js +31 -3
- package/src/components/select/Select.vue +9 -2
- package/src/components/text-field/TextField.vue +1 -0
package/package.json
CHANGED
|
@@ -68,15 +68,22 @@ class itfDatePickerInline extends Vue {
|
|
|
68
68
|
const [
|
|
69
69
|
{ default: AirDatepicker },
|
|
70
70
|
{ default: localeEn },
|
|
71
|
-
{ default: localeUk }
|
|
71
|
+
{ default: localeUk },
|
|
72
|
+
{ default: localeDe }
|
|
72
73
|
] = await Promise.all([
|
|
73
74
|
import('babel-loader!air-datepicker/air-datepicker.js'),
|
|
74
75
|
import('babel-loader!air-datepicker/locale/en'),
|
|
75
|
-
import('babel-loader!air-datepicker/locale/uk')
|
|
76
|
+
import('babel-loader!air-datepicker/locale/uk'),
|
|
77
|
+
import('babel-loader!air-datepicker/locale/de')
|
|
76
78
|
]);
|
|
77
79
|
|
|
80
|
+
const locales = {
|
|
81
|
+
en: localeEn,
|
|
82
|
+
uk: localeUk,
|
|
83
|
+
de: localeDe,
|
|
84
|
+
};
|
|
78
85
|
this.calendar = new AirDatepicker(this.$refs.calendar, {
|
|
79
|
-
locale: this.$i18n.locale
|
|
86
|
+
locale: locales[this.$i18n.locale] || locales.en,
|
|
80
87
|
firstDay: 1,
|
|
81
88
|
altFieldDateFormat: this.valueFormat,
|
|
82
89
|
range: this.range,
|
|
@@ -68,19 +68,26 @@ class itfDatePickerInline extends Vue {
|
|
|
68
68
|
const [
|
|
69
69
|
{ default: AirDatepicker },
|
|
70
70
|
{ default: localeEn },
|
|
71
|
-
{ default: localeUk }
|
|
71
|
+
{ default: localeUk },
|
|
72
|
+
{ default: localeDe }
|
|
72
73
|
] = await Promise.all([
|
|
73
74
|
import('babel-loader!air-datepicker/air-datepicker.js'),
|
|
74
75
|
import('babel-loader!air-datepicker/locale/en'),
|
|
75
|
-
import('babel-loader!air-datepicker/locale/uk')
|
|
76
|
+
import('babel-loader!air-datepicker/locale/uk'),
|
|
77
|
+
import('babel-loader!air-datepicker/locale/de')
|
|
76
78
|
]);
|
|
77
79
|
|
|
80
|
+
const locales = {
|
|
81
|
+
en: localeEn,
|
|
82
|
+
uk: localeUk,
|
|
83
|
+
de: localeDe,
|
|
84
|
+
};
|
|
78
85
|
this.calendar = new AirDatepicker(this.$refs.calendar, {
|
|
86
|
+
locale: locales[this.$i18n.locale] || locales.en,
|
|
79
87
|
firstDay: 1,
|
|
80
88
|
altFieldDateFormat: this.valueFormat,
|
|
81
89
|
minDate: this.minDate,
|
|
82
90
|
maxDate: this.maxDate,
|
|
83
|
-
locale: this.$i18n.locale === 'en' ? localeEn : localeUk,
|
|
84
91
|
range: true,
|
|
85
92
|
dynamicRange: true,
|
|
86
93
|
toggleSelected: false,
|
|
@@ -1,18 +1,35 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
<span class="border rounded d-inline-flex ps-3 pe-1 gap-1 align-items-center">
|
|
4
|
+
<span class="b-filter-badge border rounded d-inline-flex ps-3 pe-1 gap-1 align-items-center">
|
|
5
5
|
Status
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
<itf-select
|
|
8
|
+
class="mx-2"
|
|
9
|
+
v-model="operator"
|
|
10
|
+
simple
|
|
11
|
+
:reduce="(item) => item.id"
|
|
12
|
+
:get-option-label="(item) => item.title"
|
|
13
|
+
:options="operators"
|
|
14
|
+
>
|
|
15
|
+
<template #selected-option="{ option }">
|
|
16
|
+
<span class="sign-box"> {{option.sign || option.title}}</span>
|
|
17
|
+
</template>
|
|
18
|
+
<template #option="{ option }">
|
|
19
|
+
<span class="sign-box" v-if="option.sign"> {{option.sign}}</span>
|
|
20
|
+
{{option.title}}
|
|
21
|
+
</template>
|
|
22
|
+
<template #open-indicator><div></div></template>
|
|
23
|
+
</itf-select>
|
|
13
24
|
|
|
14
25
|
<div>
|
|
15
|
-
|
|
26
|
+
<itf-select
|
|
27
|
+
simple
|
|
28
|
+
multiple
|
|
29
|
+
:get-option-label="(item) => item.title"
|
|
30
|
+
:options="[{ title:'text' }, { title:'text2' }]"
|
|
31
|
+
>
|
|
32
|
+
</itf-select>
|
|
16
33
|
</div>
|
|
17
34
|
|
|
18
35
|
<itf-button icon>
|
|
@@ -22,17 +39,15 @@
|
|
|
22
39
|
|
|
23
40
|
</template>
|
|
24
41
|
<style>
|
|
25
|
-
.
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
box
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
&:hover {
|
|
42
|
+
.b-filter-badge {
|
|
43
|
+
padding: 1px;
|
|
44
|
+
|
|
45
|
+
.sign-box {
|
|
46
|
+
height: 24px;
|
|
47
|
+
text-align: center;
|
|
48
|
+
line-height: 22px;
|
|
49
|
+
width: 24px;
|
|
50
|
+
border-radius: 0.25rem;
|
|
36
51
|
background-color: var(--bs-tertiary-bg);
|
|
37
52
|
}
|
|
38
53
|
}
|
|
@@ -41,6 +56,7 @@
|
|
|
41
56
|
import { Component, Prop, Watch, Vue } from 'vue-property-decorator';
|
|
42
57
|
import {getOperatorsByType} from "./constants";
|
|
43
58
|
import itfButton from '../button/Button.vue';
|
|
59
|
+
import itfSelect from '../select/Select.vue';
|
|
44
60
|
import itfIcon from '../icon/Icon.vue';
|
|
45
61
|
|
|
46
62
|
|
|
@@ -48,6 +64,7 @@ export default @Component({
|
|
|
48
64
|
name: 'itfFilterBadge',
|
|
49
65
|
components: {
|
|
50
66
|
itfButton,
|
|
67
|
+
itfSelect,
|
|
51
68
|
itfIcon
|
|
52
69
|
}
|
|
53
70
|
})
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
<div class="d-flex align-items-center">
|
|
5
|
+
<itf-text-field
|
|
6
|
+
style="width: 250px;"
|
|
7
|
+
prepend-icon="search"
|
|
8
|
+
placeholder="Search"
|
|
9
|
+
@change="onQueryChanged"
|
|
10
|
+
/>
|
|
11
|
+
|
|
12
|
+
<itf-dropdown class="ms-3" :button-options="{ secondary: true }">
|
|
13
|
+
<template #button>
|
|
14
|
+
<itf-icon name="flip_view" class="me-1" />
|
|
15
|
+
Group
|
|
16
|
+
</template>
|
|
17
|
+
|
|
18
|
+
<div v-for="(filter, n) of filters" :key="n" class="dropdown-item">
|
|
19
|
+
<slot name="dropdown-item" :item="filter">{{filter.text}}</slot>
|
|
20
|
+
</div>
|
|
21
|
+
</itf-dropdown>
|
|
22
|
+
|
|
23
|
+
<template v-if="filters && filters.length">
|
|
24
|
+
<itf-dropdown class="mx-3" :button-options="{ secondary: true }">
|
|
25
|
+
<template #button>
|
|
26
|
+
<itf-icon name="filter" class="me-1" />
|
|
27
|
+
Filter
|
|
28
|
+
</template>
|
|
29
|
+
|
|
30
|
+
<div v-for="(filter, n) of filters" :key="n" class="dropdown-item">
|
|
31
|
+
<slot name="dropdown-item" :item="filter">{{filter.text}}</slot>
|
|
32
|
+
</div>
|
|
33
|
+
</itf-dropdown>
|
|
34
|
+
|
|
35
|
+
<div class="flex-grow-1">
|
|
36
|
+
<itf-filter-badge type="string" />
|
|
37
|
+
</div>
|
|
38
|
+
</template>
|
|
39
|
+
</div>
|
|
40
|
+
|
|
41
|
+
</template>
|
|
42
|
+
<style>
|
|
43
|
+
</style>
|
|
44
|
+
<script>
|
|
45
|
+
import { Component, Prop, Model, Vue, Watch } from 'vue-property-decorator';
|
|
46
|
+
import itfButton from '../button/Button.vue';
|
|
47
|
+
import itfTextField from '../text-field/TextField.vue';
|
|
48
|
+
import itfDropdown from '../dropdown/Dropdown.vue';
|
|
49
|
+
import itfIcon from '../icon/Icon.vue';
|
|
50
|
+
import itfFilterBadge from './FilterBadge.vue';
|
|
51
|
+
|
|
52
|
+
export default @Component({
|
|
53
|
+
name: 'itfFilterControl',
|
|
54
|
+
components: {
|
|
55
|
+
itfFilterBadge,
|
|
56
|
+
itfTextField,
|
|
57
|
+
itfDropdown,
|
|
58
|
+
itfButton,
|
|
59
|
+
itfIcon
|
|
60
|
+
}
|
|
61
|
+
})
|
|
62
|
+
class itfFilterControl extends Vue {
|
|
63
|
+
@Model('input') value;
|
|
64
|
+
@Prop({ type: String, default: 'query' }) queryField;
|
|
65
|
+
@Prop({ type: Array, default: () => ([]) }) filters;
|
|
66
|
+
@Prop(Boolean) urlSync;
|
|
67
|
+
|
|
68
|
+
mounted() {
|
|
69
|
+
if (this.urlSync) {
|
|
70
|
+
if (window.itfinUrlWatcher) {
|
|
71
|
+
throw new Error('urlSync component already exists');
|
|
72
|
+
}
|
|
73
|
+
window.itfinUrlWatcher = this;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
@Watch('$route')
|
|
78
|
+
onRouteChange() {
|
|
79
|
+
const newValue = { ...(this.value || {}) };
|
|
80
|
+
const query = this.$route.query;
|
|
81
|
+
if (query) {
|
|
82
|
+
Object.keys(query).forEach((key) => {
|
|
83
|
+
newValue[key] = query[key];
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
this.$emit('input', newValue);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
beforeDestroy() {
|
|
90
|
+
if (this.urlSync) {
|
|
91
|
+
window.itfinUrlWatcher = null;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
onQueryChanged(value) {
|
|
96
|
+
const newValue = { ...(this.value || {}) };
|
|
97
|
+
newValue[this.queryField] = value;
|
|
98
|
+
if (this.urlSync) {
|
|
99
|
+
this.$router.push({ ...this.$route, query: newValue });
|
|
100
|
+
} else {
|
|
101
|
+
this.$emit('input', newValue);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
</script>
|
|
@@ -5,12 +5,13 @@ export function getOperatorsByType(type) {
|
|
|
5
5
|
{
|
|
6
6
|
type: 'string',
|
|
7
7
|
operators: [
|
|
8
|
-
{ id: 'eq', title: 'equal' },
|
|
9
|
-
{ id: 'notEq', title: 'not equal' },
|
|
10
|
-
{ id: 'contains', title: 'contains' },
|
|
11
|
-
{ id: 'noContains', title: 'not contains' },
|
|
12
|
-
{ id: 'startsWith', title: 'starts with' },
|
|
13
|
-
{ id: 'endsWith', title: 'ends with' }
|
|
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: '∃' }
|
|
14
15
|
]
|
|
15
16
|
}
|
|
16
17
|
];
|
|
@@ -2,13 +2,15 @@ import { storiesOf } from '@storybook/vue';
|
|
|
2
2
|
import itfRule from './Rule.vue';
|
|
3
3
|
import itfRuleGroup from './RuleGroup.vue';
|
|
4
4
|
import itfFilterBadge from './FilterBadge.vue';
|
|
5
|
+
import itfFilterControl from './FilterControl.vue';
|
|
5
6
|
|
|
6
7
|
storiesOf('Common', module)
|
|
7
8
|
.add('Filter', () => ({
|
|
8
9
|
components: {
|
|
9
10
|
itfRule,
|
|
10
11
|
itfRuleGroup,
|
|
11
|
-
itfFilterBadge
|
|
12
|
+
itfFilterBadge,
|
|
13
|
+
itfFilterControl
|
|
12
14
|
},
|
|
13
15
|
data() {
|
|
14
16
|
return {
|
|
@@ -44,7 +46,22 @@ storiesOf('Common', module)
|
|
|
44
46
|
dates: [],
|
|
45
47
|
customDays: {
|
|
46
48
|
'2021-10-21': { text: '🎉', class: 'test' }
|
|
47
|
-
}
|
|
49
|
+
},
|
|
50
|
+
filter: {},
|
|
51
|
+
filterFields: [
|
|
52
|
+
{
|
|
53
|
+
type: 'list',
|
|
54
|
+
text: 'Status',
|
|
55
|
+
options: [
|
|
56
|
+
{ title: 'Active', value: 'active' },
|
|
57
|
+
{ title: 'Inactive', value: 'inactive' },
|
|
58
|
+
]
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
type: 'employee',
|
|
62
|
+
text: 'Employee'
|
|
63
|
+
},
|
|
64
|
+
]
|
|
48
65
|
}
|
|
49
66
|
},
|
|
50
67
|
methods: {
|
|
@@ -65,8 +82,19 @@ storiesOf('Common', module)
|
|
|
65
82
|
</pre>
|
|
66
83
|
|
|
67
84
|
|
|
68
|
-
<itf-filter-
|
|
85
|
+
<itf-filter-control url-sync v-model="filter" :filters="filterFields">
|
|
86
|
+
<template #dropdown-item="{ item }">
|
|
87
|
+
{{item.text}}
|
|
88
|
+
</template>
|
|
89
|
+
<template #item="{ item }">
|
|
90
|
+
{{item}}
|
|
91
|
+
</template>
|
|
92
|
+
<template #item="{ item }">
|
|
93
|
+
{{item}}
|
|
94
|
+
</template>
|
|
95
|
+
</itf-filter-control>
|
|
69
96
|
|
|
97
|
+
{{filter}}
|
|
70
98
|
|
|
71
99
|
<h2>Example</h2>
|
|
72
100
|
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
<div
|
|
5
5
|
:id="`vs${uid}__combobox`"
|
|
6
6
|
ref="toggle"
|
|
7
|
-
:class="{ 'is-invalid': isInvalid(), 'is-valid': isSuccess() }"
|
|
8
|
-
class="vs__dropdown-toggle
|
|
7
|
+
:class="{ 'is-invalid': isInvalid(), 'is-valid': isSuccess(), 'form-control': !simple }"
|
|
8
|
+
class="vs__dropdown-toggle"
|
|
9
9
|
role="combobox"
|
|
10
10
|
:aria-expanded="dropdownOpen.toString()"
|
|
11
11
|
:aria-owns="`vs${uid}__listbox`"
|
|
@@ -212,6 +212,13 @@ export default {
|
|
|
212
212
|
type: Boolean,
|
|
213
213
|
default: false,
|
|
214
214
|
},
|
|
215
|
+
/**
|
|
216
|
+
* Remove form-control class
|
|
217
|
+
*/
|
|
218
|
+
simple: {
|
|
219
|
+
type: Boolean,
|
|
220
|
+
default: false,
|
|
221
|
+
},
|
|
215
222
|
/**
|
|
216
223
|
* Can the user deselect an option by clicking it from
|
|
217
224
|
* within the dropdown.
|