@ulu/frontend-vue 0.1.0-beta.10 → 0.1.0-beta.12
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/{breakpoints-DS8rH5b6.js → breakpoints-G33Jau3F.js} +1 -1
- package/dist/frontend-vue.css +1 -1
- package/dist/frontend-vue.js +71 -67
- package/dist/{index-C5pNSAJH.js → index-6gyCmsu_.js} +1819 -1884
- package/lib/components/systems/facets/UluFacetsFilters.vue +73 -0
- package/lib/components/systems/facets/UluFacetsList.vue +13 -14
- package/lib/components/systems/facets/UluFacetsResults.vue +57 -0
- package/lib/components/systems/facets/UluFacetsSearch.vue +26 -49
- package/lib/components/systems/facets/UluFacetsSidebarLayout.vue +31 -0
- package/lib/components/systems/facets/UluFacetsSort.vue +45 -0
- package/lib/components/systems/facets/_mock-data.js +40 -0
- package/lib/components/systems/facets/useFacets.js +217 -0
- package/lib/components/systems/index.js +5 -1
- package/package.json +1 -1
- package/types/components/systems/facets/_mock-data.d.ts +18 -0
- package/types/components/systems/facets/_mock-data.d.ts.map +1 -0
- package/types/components/systems/facets/useFacets.d.ts +39 -0
- package/types/components/systems/facets/useFacets.d.ts.map +1 -0
- package/types/components/systems/index.d.ts +1 -1
- package/lib/components/systems/facets/UluFacets.vue +0 -380
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export {};
|
|
1
|
+
export { useFacets } from "./facets/useFacets.js";
|
|
2
2
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,380 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div class="UluFacets">
|
|
3
|
-
<div class="UluFacets__header" :class="classes.header">
|
|
4
|
-
<slot name="header" :count="filteredItems.length"></slot>
|
|
5
|
-
<div class="UluFacets__header-actions" :class="classes.headerActions">
|
|
6
|
-
<button
|
|
7
|
-
@click="toggleFilterVisibility"
|
|
8
|
-
:class="classes.buttonFilterToggle"
|
|
9
|
-
:aria-controls="filterId"
|
|
10
|
-
:aria-expanded="filtersHidden ? 'false' : 'true'"
|
|
11
|
-
type="button"
|
|
12
|
-
>
|
|
13
|
-
<slot name="buttonFilterToggle" :hidden="filtersHidden">
|
|
14
|
-
{{ filtersHidden ? 'Show' : 'Hide' }} Filters
|
|
15
|
-
</slot>
|
|
16
|
-
</button>
|
|
17
|
-
<button
|
|
18
|
-
v-if="selectedFacets.length"
|
|
19
|
-
@click="clearFilters"
|
|
20
|
-
:class="classes.buttonClearFilters"
|
|
21
|
-
type="button"
|
|
22
|
-
>
|
|
23
|
-
<slot name="buttonClearFilters">
|
|
24
|
-
Clear Filters
|
|
25
|
-
</slot>
|
|
26
|
-
</button>
|
|
27
|
-
<div :class="classes.sortForm">
|
|
28
|
-
<label
|
|
29
|
-
:for="sortId"
|
|
30
|
-
:class="classes.sortFormLabel"
|
|
31
|
-
>Sort:</label>
|
|
32
|
-
<select
|
|
33
|
-
v-model="selectedSort"
|
|
34
|
-
:id="sortId"
|
|
35
|
-
:class="classes.sortFormSelect"
|
|
36
|
-
>
|
|
37
|
-
<option v-for="(item, key) in sortTypes" :value="key" :key="key">
|
|
38
|
-
{{ item.text }}
|
|
39
|
-
</option>
|
|
40
|
-
</select>
|
|
41
|
-
</div>
|
|
42
|
-
</div>
|
|
43
|
-
</div>
|
|
44
|
-
<div class="UluFacets__body">
|
|
45
|
-
<transition name="UluFacetsFade" mode="out-in">
|
|
46
|
-
<div
|
|
47
|
-
v-show="!filtersHidden"
|
|
48
|
-
class="UluFacets__filters"
|
|
49
|
-
:id="filterId"
|
|
50
|
-
:class="{ 'UluFacets__filters--hidden' : filtersHidden }"
|
|
51
|
-
>
|
|
52
|
-
<UluFacetsSearch
|
|
53
|
-
:classes="classes"
|
|
54
|
-
:initialValue="initialSearchValue"
|
|
55
|
-
:placeholder="searchPlaceholder"
|
|
56
|
-
v-model="searchValue"
|
|
57
|
-
/>
|
|
58
|
-
<UluCollapsibleRegion
|
|
59
|
-
class="UluFacets__group"
|
|
60
|
-
:class="classes.group"
|
|
61
|
-
:classToggle="['UluFacets__group-toggle', classes.groupToggle]"
|
|
62
|
-
:classContent="['UluFacets__group-content', classes.groupContent]"
|
|
63
|
-
v-for="group in facets"
|
|
64
|
-
:key="group.uid"
|
|
65
|
-
:group="group"
|
|
66
|
-
:startOpen="group.open"
|
|
67
|
-
:clickOutsideCloses="false"
|
|
68
|
-
:closeOnEscape="false"
|
|
69
|
-
:transitionHeight="true"
|
|
70
|
-
>
|
|
71
|
-
<template #toggle="{ isOpen }">
|
|
72
|
-
<slot name="groupToggle" :group="group" :isOpen="isOpen">
|
|
73
|
-
{{ group.name }}
|
|
74
|
-
</slot>
|
|
75
|
-
</template>
|
|
76
|
-
<template #default>
|
|
77
|
-
<UluFacetsList
|
|
78
|
-
:children="group.children.slice(0, maxVisible)"
|
|
79
|
-
:groupUid="group.uid"
|
|
80
|
-
:classFacet="classes.facet"
|
|
81
|
-
/>
|
|
82
|
-
<UluCollapsibleRegion
|
|
83
|
-
v-if="group.children.length > maxVisible"
|
|
84
|
-
class="UluFacets__more-facets"
|
|
85
|
-
:class="classes.moreFacets"
|
|
86
|
-
:clickOutsideCloses="false"
|
|
87
|
-
:closeOnEscape="false"
|
|
88
|
-
:transitionHeight="true"
|
|
89
|
-
>
|
|
90
|
-
<template #toggle="{ isOpen }">
|
|
91
|
-
{{ isOpen ? "- Less" : "+ More" }}
|
|
92
|
-
</template>
|
|
93
|
-
<template #default>
|
|
94
|
-
<UluFacetsList
|
|
95
|
-
:children="group.children.slice(maxVisible)"
|
|
96
|
-
:groupUid="group.uid"
|
|
97
|
-
:classFacet="classes.facet"
|
|
98
|
-
/>
|
|
99
|
-
</template>
|
|
100
|
-
</UluCollapsibleRegion>
|
|
101
|
-
</template>
|
|
102
|
-
</UluCollapsibleRegion>
|
|
103
|
-
</div>
|
|
104
|
-
</transition>
|
|
105
|
-
<transition name="UluFacetsFade" mode="out-in">
|
|
106
|
-
<ul
|
|
107
|
-
class="UluFacets__results"
|
|
108
|
-
:class="classes.results"
|
|
109
|
-
:key="filterIteration"
|
|
110
|
-
v-if="resultsVisible && filteredItems.length"
|
|
111
|
-
>
|
|
112
|
-
|
|
113
|
-
<li
|
|
114
|
-
class="UluFacets__results-item"
|
|
115
|
-
:class="classes.resultsItem"
|
|
116
|
-
v-for="(item, index) in filteredItems"
|
|
117
|
-
:key="index"
|
|
118
|
-
>
|
|
119
|
-
<slot name="item" :item="item" :index="index"></slot>
|
|
120
|
-
</li>
|
|
121
|
-
</ul>
|
|
122
|
-
<div v-else class="UluFacets__empty">
|
|
123
|
-
<slot name="empty">
|
|
124
|
-
No Results Found
|
|
125
|
-
</slot>
|
|
126
|
-
</div>
|
|
127
|
-
</transition>
|
|
128
|
-
<!-- <div class="UluFacets__pagination"></div> -->
|
|
129
|
-
</div>
|
|
130
|
-
</div>
|
|
131
|
-
</template>
|
|
132
|
-
|
|
133
|
-
<script>
|
|
134
|
-
import Fuse from 'fuse.js';
|
|
135
|
-
import UluFacetsList from "./UluFacetsList.vue";
|
|
136
|
-
import UluFacetsSearch from "./UluFacetsSearch.vue";
|
|
137
|
-
import UluCollapsibleRegion from "../../collapsible/UluCollapsibleRegion.vue";
|
|
138
|
-
|
|
139
|
-
let idCounter = 0;
|
|
140
|
-
const sortAlpha = items => {
|
|
141
|
-
const getTitle = i => (i.title || i.label || "");
|
|
142
|
-
return items.sort((a, b) => getTitle(a).localeCompare(getTitle(b)));
|
|
143
|
-
}
|
|
144
|
-
const defaultSorts = {
|
|
145
|
-
az: { text: "A-Z", sort: sortAlpha },
|
|
146
|
-
za: { text: "Z-A", sort: items => sortAlpha(items).reverse() },
|
|
147
|
-
};
|
|
148
|
-
export default {
|
|
149
|
-
name: 'UluFacets',
|
|
150
|
-
components: {
|
|
151
|
-
UluCollapsibleRegion,
|
|
152
|
-
UluFacetsList,
|
|
153
|
-
UluFacetsSearch
|
|
154
|
-
},
|
|
155
|
-
props: {
|
|
156
|
-
/**
|
|
157
|
-
* Options passed to fuse js for search feature
|
|
158
|
-
*/
|
|
159
|
-
searchOptions: {
|
|
160
|
-
type: Object,
|
|
161
|
-
default: () => ({
|
|
162
|
-
// isCaseSensitive: false,
|
|
163
|
-
// includeScore: false,
|
|
164
|
-
shouldSort: true,
|
|
165
|
-
// includeMatches: false,
|
|
166
|
-
// findAllMatches: false,
|
|
167
|
-
// minMatchCharLength: 1,
|
|
168
|
-
// location: 0,
|
|
169
|
-
// threshold: 0.6,
|
|
170
|
-
// distance: 100,
|
|
171
|
-
// useExtendedSearch: false,
|
|
172
|
-
// ignoreLocation: false,
|
|
173
|
-
// ignoreFieldNorm: false,
|
|
174
|
-
// fieldNormWeight: 1,
|
|
175
|
-
keys: [
|
|
176
|
-
"title",
|
|
177
|
-
"label",
|
|
178
|
-
"description",
|
|
179
|
-
"author"
|
|
180
|
-
]
|
|
181
|
-
})
|
|
182
|
-
},
|
|
183
|
-
initialFiltersHidden: Boolean,
|
|
184
|
-
searchPlaceholder: String,
|
|
185
|
-
/**
|
|
186
|
-
* Array of facet configurations
|
|
187
|
-
*/
|
|
188
|
-
initialFacets: {
|
|
189
|
-
required: true,
|
|
190
|
-
type: Array
|
|
191
|
-
},
|
|
192
|
-
initialSearchValue: String,
|
|
193
|
-
classes: {
|
|
194
|
-
type: Object,
|
|
195
|
-
required: false,
|
|
196
|
-
default: () => ({})
|
|
197
|
-
},
|
|
198
|
-
/**
|
|
199
|
-
* Maximum facets shown per group before truncating
|
|
200
|
-
*/
|
|
201
|
-
maxVisible: {
|
|
202
|
-
type: Number,
|
|
203
|
-
default: 5
|
|
204
|
-
},
|
|
205
|
-
/**
|
|
206
|
-
* Array of objects of the items to display
|
|
207
|
-
*/
|
|
208
|
-
items: {
|
|
209
|
-
required: true,
|
|
210
|
-
type: Array
|
|
211
|
-
},
|
|
212
|
-
/**
|
|
213
|
-
* Provides a way to find categories for each facet
|
|
214
|
-
* @param {Object} item An item to lookup the facet/category info for
|
|
215
|
-
* @param {String} uid The facet's uid (the categories uid) to return a value, value should be an array of facet (child) keys
|
|
216
|
-
*/
|
|
217
|
-
getItemFacet: {
|
|
218
|
-
type: Function,
|
|
219
|
-
default: (item, uid) => item[uid]
|
|
220
|
-
},
|
|
221
|
-
/**
|
|
222
|
-
* Return the value for an item to use for sorting alphabetically
|
|
223
|
-
*/
|
|
224
|
-
getItemSortAlpha: {
|
|
225
|
-
type: Function,
|
|
226
|
-
default: item => (item.title || item.label || "")
|
|
227
|
-
},
|
|
228
|
-
initialSortType: {
|
|
229
|
-
type: String,
|
|
230
|
-
default: "az"
|
|
231
|
-
},
|
|
232
|
-
noDefaultSorts: Boolean,
|
|
233
|
-
extraSortTypes: {
|
|
234
|
-
type: Object,
|
|
235
|
-
default: () => ({})
|
|
236
|
-
}
|
|
237
|
-
},
|
|
238
|
-
data() {
|
|
239
|
-
const {
|
|
240
|
-
initialFiltersHidden,
|
|
241
|
-
initialSearchValue,
|
|
242
|
-
noDefaultSorts,
|
|
243
|
-
initialSortType,
|
|
244
|
-
extraSortTypes
|
|
245
|
-
} = this;
|
|
246
|
-
return {
|
|
247
|
-
filterId: `ulu-facet-filters-${ ++idCounter }`,
|
|
248
|
-
sortId: `ulu-facet-sort-${ ++idCounter }`,
|
|
249
|
-
selectedSort: initialSortType,
|
|
250
|
-
sortTypes: {
|
|
251
|
-
...(noDefaultSorts ? {} : defaultSorts),
|
|
252
|
-
...extraSortTypes
|
|
253
|
-
},
|
|
254
|
-
facets: this.createFacets(), // Copy of users facet configs
|
|
255
|
-
filtersHidden: initialFiltersHidden || false,
|
|
256
|
-
searchValue: initialSearchValue || null,
|
|
257
|
-
resultsVisible: true,
|
|
258
|
-
filterIteration: 0,
|
|
259
|
-
}
|
|
260
|
-
},
|
|
261
|
-
computed: {
|
|
262
|
-
/**
|
|
263
|
-
* Returns an array of groups with children that are active
|
|
264
|
-
*/
|
|
265
|
-
selectedFacets() {
|
|
266
|
-
const selected = [];
|
|
267
|
-
this.facets.forEach((group) => {
|
|
268
|
-
const { name, uid, children } = group;
|
|
269
|
-
let count = 0;
|
|
270
|
-
let added = false;
|
|
271
|
-
if (children) {
|
|
272
|
-
children.forEach(child => {
|
|
273
|
-
if (child.selected) {
|
|
274
|
-
++count;
|
|
275
|
-
if (!added) {
|
|
276
|
-
selected.push({ uid, name, children: [] });
|
|
277
|
-
added = true;
|
|
278
|
-
}
|
|
279
|
-
selected[selected.length - 1].children.push(child);
|
|
280
|
-
}
|
|
281
|
-
});
|
|
282
|
-
}
|
|
283
|
-
group.selectedCount = count;
|
|
284
|
-
});
|
|
285
|
-
return selected;
|
|
286
|
-
},
|
|
287
|
-
filteredItems() {
|
|
288
|
-
this.resultsVisible = false;
|
|
289
|
-
const { getItemFacet, selectedFacets, sortTypes, selectedSort } = this;
|
|
290
|
-
const sort = sortTypes[selectedSort].sort;
|
|
291
|
-
|
|
292
|
-
const filteredItems = this.items.filter(item => {
|
|
293
|
-
if (selectedFacets.length) {
|
|
294
|
-
return selectedFacets.some(group => {
|
|
295
|
-
let matched;
|
|
296
|
-
const cats = getItemFacet(item, group.uid);
|
|
297
|
-
if (cats && cats.length) {
|
|
298
|
-
matched = group.children.some(facet => cats.includes(facet.uid));
|
|
299
|
-
}
|
|
300
|
-
return matched;
|
|
301
|
-
});
|
|
302
|
-
// No filters are applied
|
|
303
|
-
} else {
|
|
304
|
-
return true;
|
|
305
|
-
}
|
|
306
|
-
});
|
|
307
|
-
// Increment counter (used for transitions)
|
|
308
|
-
// this.filterIteration = filterIteration + 1;
|
|
309
|
-
const newItems = sort(this.search(filteredItems));
|
|
310
|
-
// this.resultsVisible = false;
|
|
311
|
-
this.$nextTick(() => {
|
|
312
|
-
this.resultsVisible = true;
|
|
313
|
-
this.filterIteration = this.filterIteration + 1;
|
|
314
|
-
// this.$nextTick(() => this.resultsVisible = true);
|
|
315
|
-
});
|
|
316
|
-
return newItems;
|
|
317
|
-
}
|
|
318
|
-
},
|
|
319
|
-
methods: {
|
|
320
|
-
/**
|
|
321
|
-
* Resets all active filters to user's initial
|
|
322
|
-
*/
|
|
323
|
-
clearFilters() {
|
|
324
|
-
this.facets = this.createFacets();
|
|
325
|
-
},
|
|
326
|
-
/**
|
|
327
|
-
* Maps users initial facets to the local facet array used in this component
|
|
328
|
-
*/
|
|
329
|
-
createFacets() {
|
|
330
|
-
return this.initialFacets.map(group => {
|
|
331
|
-
const children = group.children.map(facet => ({
|
|
332
|
-
...facet,
|
|
333
|
-
selected: facet.selected || false
|
|
334
|
-
}));
|
|
335
|
-
return {
|
|
336
|
-
...group,
|
|
337
|
-
open: group.open || false,
|
|
338
|
-
children,
|
|
339
|
-
selectedCount: 0
|
|
340
|
-
};
|
|
341
|
-
})
|
|
342
|
-
},
|
|
343
|
-
/**
|
|
344
|
-
* Search applied to an already filtered batch of items
|
|
345
|
-
*/
|
|
346
|
-
search(items) {
|
|
347
|
-
const { searchValue, searchOptions } = this;
|
|
348
|
-
if (!searchValue?.length) return items;
|
|
349
|
-
const fuse = new Fuse(items, searchOptions);
|
|
350
|
-
const results = fuse.search(searchValue);
|
|
351
|
-
return results.map(result => result.item);
|
|
352
|
-
},
|
|
353
|
-
toggleFilterVisibility() {
|
|
354
|
-
this.filtersHidden = !this.filtersHidden;
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
</script>
|
|
359
|
-
|
|
360
|
-
<style lang="scss">
|
|
361
|
-
.UluFacets__more-facets {
|
|
362
|
-
display: flex;
|
|
363
|
-
flex-direction: column;
|
|
364
|
-
&.UluCollapsibleRegion--open,
|
|
365
|
-
&.UluCollapsibleRegion--transitioning {
|
|
366
|
-
.UluCollapsibleRegion__content {
|
|
367
|
-
order: -1;
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
.UluFacetsFade-enter-active,
|
|
372
|
-
.UluFacetsFade-leave-active {
|
|
373
|
-
transition: opacity 0.25s ease;
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
.UluFacetsFade-enter-from,
|
|
377
|
-
.UluFacetsFade-leave-to {
|
|
378
|
-
opacity: 0;
|
|
379
|
-
}
|
|
380
|
-
</style>
|