@ulu/frontend-vue 0.1.0-beta.1
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/LICENSE +21 -0
- package/README.md +9 -0
- package/dist/breakpoints-ClT9bfZm.js +211 -0
- package/dist/frontend-vue.css +1 -0
- package/dist/frontend-vue.js +82 -0
- package/dist/frontend-vue.umd.cjs +561 -0
- package/dist/index-P5Rwl_Dl.js +7263 -0
- package/dist/index.es-HlG3u0J5.js +3134 -0
- package/lib/_index.scss +14 -0
- package/lib/components/_index.scss +6 -0
- package/lib/components/collapsible/UluAccordion.vue +82 -0
- package/lib/components/collapsible/UluCollapsibleRegion.vue +278 -0
- package/lib/components/collapsible/UluDropdown.vue +42 -0
- package/lib/components/collapsible/UluModal.vue +384 -0
- package/lib/components/collapsible/UluOverflowPopover.vue +52 -0
- package/lib/components/collapsible/UluTab.vue +9 -0
- package/lib/components/collapsible/UluTabGroup.vue +31 -0
- package/lib/components/collapsible/UluTabList.vue +9 -0
- package/lib/components/collapsible/UluTabPanel.vue +9 -0
- package/lib/components/collapsible/UluTabPanels.vue +9 -0
- package/lib/components/elements/UluAlert.vue +81 -0
- package/lib/components/elements/UluBadge.vue +58 -0
- package/lib/components/elements/UluBadgeStack.vue +27 -0
- package/lib/components/elements/UluButton.vue +161 -0
- package/lib/components/elements/UluCallout.vue +30 -0
- package/lib/components/elements/UluCard.vue +241 -0
- package/lib/components/elements/UluDefinitionList.vue +40 -0
- package/lib/components/elements/UluExternalLink.vue +47 -0
- package/lib/components/elements/UluIcon.vue +108 -0
- package/lib/components/elements/UluList.vue +87 -0
- package/lib/components/elements/UluMain.vue +5 -0
- package/lib/components/elements/UluSpokeSpinner.vue +25 -0
- package/lib/components/elements/UluTag.vue +53 -0
- package/lib/components/forms/UluCheckboxMenu.vue +36 -0
- package/lib/components/forms/UluFileDisplay.vue +39 -0
- package/lib/components/forms/UluFormDropzone.vue +62 -0
- package/lib/components/forms/UluFormFile.vue +47 -0
- package/lib/components/forms/UluFormMessage.vue +20 -0
- package/lib/components/forms/UluFormSelect.vue +37 -0
- package/lib/components/forms/UluFormText.vue +32 -0
- package/lib/components/forms/UluSearchForm.vue +31 -0
- package/lib/components/index.js +54 -0
- package/lib/components/layout/UluAdaptiveLayout.vue +11 -0
- package/lib/components/layout/UluDataGrid.vue +41 -0
- package/lib/components/layout/UluTitleRail.vue +56 -0
- package/lib/components/layout/UluWhenBreakpoint.vue +86 -0
- package/lib/components/navigation/UluBreadcrumb.vue +72 -0
- package/lib/components/navigation/UluMenu.vue +105 -0
- package/lib/components/navigation/UluMenuStack.vue +49 -0
- package/lib/components/navigation/UluNavStrip.vue +48 -0
- package/lib/components/navigation/UluSkipLink.vue +5 -0
- package/lib/components/systems/facets/UluFacets.vue +380 -0
- package/lib/components/systems/facets/UluFacetsList.vue +39 -0
- package/lib/components/systems/facets/UluFacetsSearch.vue +67 -0
- package/lib/components/systems/facets/_facets.scss +64 -0
- package/lib/components/systems/index.js +17 -0
- package/lib/components/systems/scroll-anchors/UluScrollAnchors.vue +152 -0
- package/lib/components/systems/scroll-anchors/UluScrollAnchorsNav.vue +37 -0
- package/lib/components/systems/scroll-anchors/UluScrollAnchorsNavAnimated.vue +124 -0
- package/lib/components/systems/scroll-anchors/UluScrollAnchorsSection.vue +63 -0
- package/lib/components/systems/scroll-anchors/symbols.js +6 -0
- package/lib/components/systems/skeleton/UluShowSkeleton.vue +13 -0
- package/lib/components/systems/skeleton/UluSkeletonContent.vue +60 -0
- package/lib/components/systems/skeleton/UluSkeletonMedia.vue +11 -0
- package/lib/components/systems/skeleton/UluSkeletonTextInline.vue +9 -0
- package/lib/components/systems/slider/UluImageSlideShow.vue +75 -0
- package/lib/components/systems/slider/UluSlideShow.vue +331 -0
- package/lib/components/systems/slider/UluSlideShowSlide.vue +25 -0
- package/lib/components/systems/table-sticky/UluTableSticky.vue +793 -0
- package/lib/components/systems/table-sticky/UluTableStickyRows.vue +73 -0
- package/lib/components/systems/table-sticky/UluTableStickyTable.vue +237 -0
- package/lib/components/systems/table-sticky/_table-sticky.scss +185 -0
- package/lib/components/utils/UluCondText.vue +28 -0
- package/lib/components/utils/UluEmpty.vue +3 -0
- package/lib/components/utils/UluEmptyView.vue +3 -0
- package/lib/components/utils/UluPlaceholderImage.vue +53 -0
- package/lib/components/utils/UluPlaceholderText.vue +25 -0
- package/lib/components/utils/UluRouteAnnouncer.vue +83 -0
- package/lib/components/visualizations/UluAnimateNumber.vue +32 -0
- package/lib/components/visualizations/UluProgressBar.vue +94 -0
- package/lib/components/visualizations/UluProgressDonut.vue +97 -0
- package/lib/composables/index.js +10 -0
- package/lib/composables/useBreakpointManager.js +68 -0
- package/lib/composables/useIcon.js +62 -0
- package/lib/composables/useModifiers.js +93 -0
- package/lib/composables/useWindowResize.js +64 -0
- package/lib/index.js +10 -0
- package/lib/plugins/_index.scss +7 -0
- package/lib/plugins/breakpoints/index.js +47 -0
- package/lib/plugins/index.js +11 -0
- package/lib/plugins/modals/UluModalsDisplay.vue +59 -0
- package/lib/plugins/modals/api.js +76 -0
- package/lib/plugins/modals/index.js +60 -0
- package/lib/plugins/modals/useModals.js +9 -0
- package/lib/plugins/popovers/UluPopover.vue +189 -0
- package/lib/plugins/popovers/UluTooltipDisplay.vue +15 -0
- package/lib/plugins/popovers/UluTooltipPopover.vue +83 -0
- package/lib/plugins/popovers/defaults.js +108 -0
- package/lib/plugins/popovers/directive.js +95 -0
- package/lib/plugins/popovers/index.js +18 -0
- package/lib/plugins/popovers/manager.js +54 -0
- package/lib/plugins/popovers/useFollow.js +80 -0
- package/lib/plugins/popovers/utils.js +5 -0
- package/lib/plugins/toast/UluToast.vue +87 -0
- package/lib/plugins/toast/UluToastDisplay.vue +35 -0
- package/lib/plugins/toast/_toast.scss +198 -0
- package/lib/plugins/toast/defaults.js +30 -0
- package/lib/plugins/toast/index.js +17 -0
- package/lib/plugins/toast/store.js +71 -0
- package/lib/plugins/toast/useToast.js +18 -0
- package/lib/settings.js +119 -0
- package/lib/utils/dom.js +14 -0
- package/lib/utils/placeholder.js +6 -0
- package/lib/utils/vue-router.js +219 -0
- package/package.json +75 -0
|
@@ -0,0 +1,380 @@
|
|
|
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>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<ul class="UluFacets__facet-list">
|
|
3
|
+
<li
|
|
4
|
+
class="UluFacets__facet"
|
|
5
|
+
:class="classFacet"
|
|
6
|
+
v-for="facet in children"
|
|
7
|
+
:key="facet.uid"
|
|
8
|
+
>
|
|
9
|
+
<input
|
|
10
|
+
class="UluFacets__facet-checkbox"
|
|
11
|
+
:id="facetCheckboxId(facet)"
|
|
12
|
+
type="checkbox"
|
|
13
|
+
v-model="facet.selected"
|
|
14
|
+
>
|
|
15
|
+
<label
|
|
16
|
+
class="UluFacets__facet-label"
|
|
17
|
+
:for="facetCheckboxId(facet)"
|
|
18
|
+
>
|
|
19
|
+
{{ facet.label }}
|
|
20
|
+
</label>
|
|
21
|
+
</li>
|
|
22
|
+
</ul>
|
|
23
|
+
</template>
|
|
24
|
+
|
|
25
|
+
<script>
|
|
26
|
+
export default {
|
|
27
|
+
name: 'UluFacetsList',
|
|
28
|
+
props: {
|
|
29
|
+
groupUid: String,
|
|
30
|
+
children: Array,
|
|
31
|
+
classFacet: String
|
|
32
|
+
},
|
|
33
|
+
methods: {
|
|
34
|
+
facetCheckboxId(facet) {
|
|
35
|
+
return `facet-${ this.groupUid }-${ facet.uid }`;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
</script>
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="UluFacets__keyword-search">
|
|
3
|
+
<label :class="classes.searchLabel" :for="id">
|
|
4
|
+
<strong>Search</strong>
|
|
5
|
+
</label>
|
|
6
|
+
<input
|
|
7
|
+
:id="id"
|
|
8
|
+
:class="classes.searchInput"
|
|
9
|
+
v-model="localValue"
|
|
10
|
+
type="text"
|
|
11
|
+
:placeholder="placeholder"
|
|
12
|
+
>
|
|
13
|
+
<!-- <button
|
|
14
|
+
v-if="value"
|
|
15
|
+
:class="classes.searchClear"
|
|
16
|
+
@click="clear"
|
|
17
|
+
:aria-label="classes.searchClearIcon ? 'Clear Search' : false"
|
|
18
|
+
type="button"
|
|
19
|
+
>
|
|
20
|
+
<span
|
|
21
|
+
v-if="classes.searchClearIcon"
|
|
22
|
+
:class="classes.searchClearIcon"
|
|
23
|
+
aria-hidden="true"
|
|
24
|
+
></span>
|
|
25
|
+
<span v-else>
|
|
26
|
+
Clear
|
|
27
|
+
</span>
|
|
28
|
+
</button> -->
|
|
29
|
+
</div>
|
|
30
|
+
</template>
|
|
31
|
+
|
|
32
|
+
<script>
|
|
33
|
+
let uid = 0;
|
|
34
|
+
export default {
|
|
35
|
+
name: 'UluFacetsSearch',
|
|
36
|
+
props: {
|
|
37
|
+
classes: Object,
|
|
38
|
+
modelValue: String,
|
|
39
|
+
placeholder: {
|
|
40
|
+
type: String,
|
|
41
|
+
default: "Keywords…"
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
data() {
|
|
45
|
+
return {
|
|
46
|
+
id: `facet-view-keyword-${ ++uid }`
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
computed: {
|
|
50
|
+
localValue: {
|
|
51
|
+
get() {
|
|
52
|
+
return this.modelValue;
|
|
53
|
+
},
|
|
54
|
+
set(val) {
|
|
55
|
+
this.$emit('update:modelValue', val);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
methods: {
|
|
60
|
+
clear() {
|
|
61
|
+
// this.value = null;
|
|
62
|
+
// this.applied = false;
|
|
63
|
+
// this.$emit("search", null);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
</script>
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
////
|
|
2
|
+
/// @group facets
|
|
3
|
+
/// Filterable/Sortable View
|
|
4
|
+
////
|
|
5
|
+
|
|
6
|
+
@use "sass:map";
|
|
7
|
+
@use "sass:meta";
|
|
8
|
+
|
|
9
|
+
@use "@ulu/frontend/scss/selector";
|
|
10
|
+
@use "@ulu/frontend/scss/utils";
|
|
11
|
+
@use "@ulu/frontend/scss/color";
|
|
12
|
+
@use "@ulu/frontend/scss/element";
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
// Used for function fallback
|
|
16
|
+
$-fallbacks: (
|
|
17
|
+
// "box-shadow" : (
|
|
18
|
+
// "function" : meta.get-function("get", false, "element"),
|
|
19
|
+
// "property" : "box-shadow"
|
|
20
|
+
// ),
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
/// Module Settings
|
|
24
|
+
/// @type Map
|
|
25
|
+
/// @prop {CssValue} example [true] Example
|
|
26
|
+
|
|
27
|
+
$config: (
|
|
28
|
+
) !default;
|
|
29
|
+
|
|
30
|
+
/// Change modules $config
|
|
31
|
+
/// @param {Map} $changes Map of changes
|
|
32
|
+
/// @example scss
|
|
33
|
+
/// @include ulu.component-facets-set(( "property" : value ));
|
|
34
|
+
|
|
35
|
+
@mixin set($changes) {
|
|
36
|
+
$config: map.merge($config, $changes) !global;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/// Get a config option
|
|
40
|
+
/// @param {Map} $name Name of property
|
|
41
|
+
/// @example scss
|
|
42
|
+
/// @include ulu.component-facets-get("property");
|
|
43
|
+
|
|
44
|
+
@function get($name) {
|
|
45
|
+
$value: utils.require-map-get($config, $name, "facets [config]");
|
|
46
|
+
@return utils.function-fallback($name, $value, $-fallbacks);
|
|
47
|
+
}
|
|
48
|
+
/// Prints component styles
|
|
49
|
+
/// @demo facets
|
|
50
|
+
/// @example scss
|
|
51
|
+
/// @include ulu.component-facets-styles();
|
|
52
|
+
|
|
53
|
+
@mixin styles {
|
|
54
|
+
$prefix: selector.class("facets");
|
|
55
|
+
|
|
56
|
+
#{ $prefix }__body {
|
|
57
|
+
.FacetView__body {
|
|
58
|
+
display: flex
|
|
59
|
+
;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export { default as UluFacets } from './facets/UluFacets.vue';
|
|
2
|
+
export { default as UluFacetsSearch } from './facets/UluFacetsSearch.vue';
|
|
3
|
+
export { default as UluFacetsList } from './facets/UluFacetsList.vue';
|
|
4
|
+
export { default as UluScrollAnchors } from './scroll-anchors/UluScrollAnchors.vue';
|
|
5
|
+
export { default as UluScrollAnchorsNav } from './scroll-anchors/UluScrollAnchorsNav.vue';
|
|
6
|
+
export { default as UluScrollAnchorsNavAnimated } from './scroll-anchors/UluScrollAnchorsNavAnimated.vue';
|
|
7
|
+
export { default as UluScrollAnchorsSection } from './scroll-anchors/UluScrollAnchorsSection.vue';
|
|
8
|
+
export { default as UluShowSkeleton } from './skeleton/UluShowSkeleton.vue';
|
|
9
|
+
export { default as UluSkeletonContent } from './skeleton/UluSkeletonContent.vue';
|
|
10
|
+
export { default as UluSkeletonMedia } from './skeleton/UluSkeletonMedia.vue';
|
|
11
|
+
export { default as UluSkeletonTextInline } from './skeleton/UluSkeletonTextInline.vue';
|
|
12
|
+
export { default as UluImageSlideShow } from './slider/UluImageSlideShow.vue';
|
|
13
|
+
export { default as UluSlideShow } from './slider/UluSlideShow.vue';
|
|
14
|
+
export { default as UluSlideShowSlide } from './slider/UluSlideShowSlide.vue';
|
|
15
|
+
export { default as UluTableSticky } from './table-sticky/UluTableSticky.vue';
|
|
16
|
+
export { default as UluTableStickyRows } from './table-sticky/UluTableStickyRows.vue';
|
|
17
|
+
export { default as UluTableStickyTable } from './table-sticky/UluTableStickyTable.vue';
|