@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,331 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
Notes:
|
|
3
|
+
- Could use anchor links instead of buttons for the nav?
|
|
4
|
+
- How to solve the scrollability with scroll snap
|
|
5
|
+
- Edge detection isn't reliable (scroll snap may prevent the element from reaching the edge of it's scroll)
|
|
6
|
+
- A better technique would be to check if there are any other items that could be scrolled to
|
|
7
|
+
- Could use active state to determine scrollability?
|
|
8
|
+
- This component is passed slide components in the #default slot
|
|
9
|
+
- It uses the default slot property as the reactive var for slides
|
|
10
|
+
- It renders the slides from the slot using <component> instead <slot>
|
|
11
|
+
- Since we know they are all component instances we can use <component> to render the vnode
|
|
12
|
+
- That way no hacks for getting slide DOM references, count, etc
|
|
13
|
+
- Allows us to collest a ref array of all slides
|
|
14
|
+
- Keeps the UX of the component simple, no need for hacks like passing props and asking user of component to set things like active
|
|
15
|
+
- TODO not sure if this is ok to do, what happens with props? User can pass props, we can pass props
|
|
16
|
+
- Should we debounce the scroll or throttle it
|
|
17
|
+
- Throttling would allow active items to happen during scroll
|
|
18
|
+
- Going to try this first
|
|
19
|
+
- Debounce would wait until scrolling ends
|
|
20
|
+
Todo:
|
|
21
|
+
[ ] - Setup active state in nav (need to think this through)
|
|
22
|
+
|
|
23
|
+
-->
|
|
24
|
+
<template>
|
|
25
|
+
<div class="slideshow">
|
|
26
|
+
<div class="slideshow__control-context" ref="context">
|
|
27
|
+
<div class="slideshow__track-crop" ref="crop">
|
|
28
|
+
<ul class="slideshow__track" ref="track">
|
|
29
|
+
<li
|
|
30
|
+
v-for="(slide, index) in slides"
|
|
31
|
+
class="slideshow__slide"
|
|
32
|
+
:class="{ 'is-active' : slide.active }"
|
|
33
|
+
:key="index"
|
|
34
|
+
:tabindex="slideFocusable ? '0' : '-1'"
|
|
35
|
+
:ref="el => { slide.element = el }"
|
|
36
|
+
>
|
|
37
|
+
<slot
|
|
38
|
+
name="slide"
|
|
39
|
+
:item="slide.item"
|
|
40
|
+
:index="index"
|
|
41
|
+
/>
|
|
42
|
+
</li>
|
|
43
|
+
</ul>
|
|
44
|
+
</div>
|
|
45
|
+
<ul class="slideshow__controls">
|
|
46
|
+
<li class="slideshow__controls-item slideshow__controls-item--previous">
|
|
47
|
+
<button
|
|
48
|
+
class="slideshow__control-button slideshow__control-button--previous"
|
|
49
|
+
aria-label="Scroll Right"
|
|
50
|
+
@click="previous"
|
|
51
|
+
:disabled="!canScrollLeft"
|
|
52
|
+
>
|
|
53
|
+
<FaIcon class="slideshow__control-icon" icon="fas fa-chevron-left"/>
|
|
54
|
+
</button>
|
|
55
|
+
</li>
|
|
56
|
+
<li class="slideshow__controls-item slideshow__controls-item--next">
|
|
57
|
+
<button
|
|
58
|
+
class="slideshow__control-button slideshow__control-button--next"
|
|
59
|
+
aria-label="Scroll Left"
|
|
60
|
+
@click="next"
|
|
61
|
+
:disabled="!canScrollRight"
|
|
62
|
+
>
|
|
63
|
+
<FaIcon class="slideshow__control-icon" icon="fas fa-chevron-right"/>
|
|
64
|
+
</button>
|
|
65
|
+
</li>
|
|
66
|
+
</ul>
|
|
67
|
+
</div>
|
|
68
|
+
<ul
|
|
69
|
+
v-if="!noNav"
|
|
70
|
+
class="slideshow__nav"
|
|
71
|
+
ref="nav"
|
|
72
|
+
>
|
|
73
|
+
<li
|
|
74
|
+
class="slideshow__nav-item"
|
|
75
|
+
v-for="(slide, index) in slides"
|
|
76
|
+
:class="{ 'is-active' : slide.active }"
|
|
77
|
+
:ref="el => { slide.navElement = el }"
|
|
78
|
+
:key="index"
|
|
79
|
+
>
|
|
80
|
+
<button
|
|
81
|
+
class="slideshow__nav-button"
|
|
82
|
+
:class="{ 'is-active' : slide.active }"
|
|
83
|
+
@click="to(index)"
|
|
84
|
+
>
|
|
85
|
+
<slot
|
|
86
|
+
name="nav"
|
|
87
|
+
:item="slide.item"
|
|
88
|
+
:index="index"
|
|
89
|
+
:active="slide.active"
|
|
90
|
+
>
|
|
91
|
+
<span class="hidden-visually">Item {{ index + 1 }}</span>
|
|
92
|
+
</slot>
|
|
93
|
+
</button>
|
|
94
|
+
</li>
|
|
95
|
+
</ul>
|
|
96
|
+
</div>
|
|
97
|
+
</template>
|
|
98
|
+
|
|
99
|
+
<script>
|
|
100
|
+
export default {
|
|
101
|
+
name: 'SlideShow',
|
|
102
|
+
props: {
|
|
103
|
+
/**
|
|
104
|
+
* Should slides be focusable by tab key
|
|
105
|
+
*/
|
|
106
|
+
slideFocusable: Boolean,
|
|
107
|
+
/**
|
|
108
|
+
* Setting for element.focus() when navigating to() a specific slide
|
|
109
|
+
*/
|
|
110
|
+
focusOptions: {
|
|
111
|
+
type: Object,
|
|
112
|
+
default: () => ({
|
|
113
|
+
preventScroll: true,
|
|
114
|
+
focusVisible: false
|
|
115
|
+
})
|
|
116
|
+
},
|
|
117
|
+
/**
|
|
118
|
+
* Array of slide items (data)
|
|
119
|
+
* - Use slot (#slide) to template
|
|
120
|
+
*/
|
|
121
|
+
items: Array,
|
|
122
|
+
/**
|
|
123
|
+
* Slideshow without a nav
|
|
124
|
+
*/
|
|
125
|
+
noNav: Boolean,
|
|
126
|
+
/**
|
|
127
|
+
* Allow user to change the scroll behavior when a slide is navigated to()
|
|
128
|
+
*/
|
|
129
|
+
scrollBehaviorNav: {
|
|
130
|
+
type: String,
|
|
131
|
+
default: "instant"
|
|
132
|
+
},
|
|
133
|
+
/**
|
|
134
|
+
* Allow user to change the scroll behavior when a slide is navigated via next/prev
|
|
135
|
+
*/
|
|
136
|
+
scrollBehaviorControl: {
|
|
137
|
+
type: String,
|
|
138
|
+
default: "smooth"
|
|
139
|
+
},
|
|
140
|
+
/**
|
|
141
|
+
* Observe
|
|
142
|
+
*/
|
|
143
|
+
observerOptions: {
|
|
144
|
+
type: Object,
|
|
145
|
+
default: () => ({
|
|
146
|
+
threshhold: 0,
|
|
147
|
+
rootMargin: "-50% 0px"
|
|
148
|
+
})
|
|
149
|
+
},
|
|
150
|
+
/**
|
|
151
|
+
* The intial slide index to use for active slide (zero based)
|
|
152
|
+
*/
|
|
153
|
+
initialActive: {
|
|
154
|
+
type: Number,
|
|
155
|
+
default: 0
|
|
156
|
+
},
|
|
157
|
+
/**
|
|
158
|
+
* Allow user to control scroll amount (element.scrollTo) for prev/next controls
|
|
159
|
+
* - For future scroll implementations (like ulu scroll-slider for cards, etc)
|
|
160
|
+
* - Function is passed (direction, DomRefs)
|
|
161
|
+
* - Number is passed directly
|
|
162
|
+
*/
|
|
163
|
+
scrollAmount: [Number, Function],
|
|
164
|
+
},
|
|
165
|
+
data() {
|
|
166
|
+
return {
|
|
167
|
+
slides: this.createSlides()
|
|
168
|
+
};
|
|
169
|
+
},
|
|
170
|
+
computed: {
|
|
171
|
+
canScrollRight() {
|
|
172
|
+
const { slides } = this;
|
|
173
|
+
return !slides[slides.length - 1].active;
|
|
174
|
+
},
|
|
175
|
+
canScrollLeft() {
|
|
176
|
+
const { slides } = this;
|
|
177
|
+
return !slides[0].active;
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
watch: {
|
|
181
|
+
'items.length'() {
|
|
182
|
+
this.slides = this.createSlides();
|
|
183
|
+
this.$nextTick(() => {
|
|
184
|
+
this.observeSlides();
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
methods: {
|
|
189
|
+
/**
|
|
190
|
+
* Creates the internal array of slides based on user's passed items
|
|
191
|
+
*/
|
|
192
|
+
createSlides() {
|
|
193
|
+
return this.items.map(item => ({
|
|
194
|
+
element: null,
|
|
195
|
+
active: false,
|
|
196
|
+
item
|
|
197
|
+
}));
|
|
198
|
+
},
|
|
199
|
+
/**
|
|
200
|
+
* Find the corresponding slide data by slide element
|
|
201
|
+
*/
|
|
202
|
+
getSlideByElement(el) {
|
|
203
|
+
return this.slides.find(({ element }) => el === element);
|
|
204
|
+
},
|
|
205
|
+
/**
|
|
206
|
+
* Provides scroll measurements
|
|
207
|
+
*/
|
|
208
|
+
getScrollData() {
|
|
209
|
+
const { scrollLeft, offsetWidth, scrollWidth } = this.$refs.track;
|
|
210
|
+
return { scrollLeft, offsetWidth, scrollWidth };
|
|
211
|
+
},
|
|
212
|
+
/**
|
|
213
|
+
* Determines the amount to scroll the track
|
|
214
|
+
*/
|
|
215
|
+
resolveAmount(dir) {
|
|
216
|
+
const isNext = dir === "next";
|
|
217
|
+
const { scrollAmount: amount } = this;
|
|
218
|
+
const { scrollLeft, offsetWidth } = this.getScrollData();
|
|
219
|
+
|
|
220
|
+
if (typeof amount === "function") {
|
|
221
|
+
// Function can be setup by user (ie. scrolling by visible items for example)
|
|
222
|
+
return amount(dir, this.$refs);
|
|
223
|
+
} else if (typeof amount === "number") {
|
|
224
|
+
return isNext ? scrollLeft + amount : scrollLeft - amount;
|
|
225
|
+
} else {
|
|
226
|
+
// No amount set (default 100% scrollable area shift)
|
|
227
|
+
return isNext ? scrollLeft + offsetWidth : scrollLeft - offsetWidth;
|
|
228
|
+
}
|
|
229
|
+
},
|
|
230
|
+
/**
|
|
231
|
+
* Scroll the track to a specified point
|
|
232
|
+
*/
|
|
233
|
+
scrollTo(left, behavior) {
|
|
234
|
+
this.$refs.track.scrollTo({ left, top: 0, behavior });
|
|
235
|
+
},
|
|
236
|
+
/**
|
|
237
|
+
* Scroll to specific index
|
|
238
|
+
* @param {Number} index Slide index
|
|
239
|
+
*/
|
|
240
|
+
to(index) {
|
|
241
|
+
const slide = this.slides[index];
|
|
242
|
+
const { track } = this.$refs;
|
|
243
|
+
if (slide) {
|
|
244
|
+
let amount = slide.element.offsetLeft;
|
|
245
|
+
const end = () => {
|
|
246
|
+
slide.element.focus(this.focusOptions);
|
|
247
|
+
track.removeEventListener('scrollend', end);
|
|
248
|
+
}
|
|
249
|
+
track.addEventListener('scrollend', end);
|
|
250
|
+
this.scrollTo(amount, this.scrollBehaviorNav);
|
|
251
|
+
}
|
|
252
|
+
},
|
|
253
|
+
/**
|
|
254
|
+
* Goto to next slide
|
|
255
|
+
*/
|
|
256
|
+
next() {
|
|
257
|
+
const amount = this.resolveAmount("next");
|
|
258
|
+
this.scrollTo(amount, this.scrollBehaviorControl);
|
|
259
|
+
},
|
|
260
|
+
/**
|
|
261
|
+
* Goto to previous slide
|
|
262
|
+
*/
|
|
263
|
+
previous() {
|
|
264
|
+
const amount = this.resolveAmount("previous");
|
|
265
|
+
this.scrollTo(amount, this.scrollBehaviorControl);
|
|
266
|
+
},
|
|
267
|
+
/**
|
|
268
|
+
* Sets up a new observer to watch the slides visibility (within track)
|
|
269
|
+
*/
|
|
270
|
+
createObserver() {
|
|
271
|
+
const { observerOptions } = this;
|
|
272
|
+
const { track, nav } = this.$refs;
|
|
273
|
+
// Observer callback, basically just sets active state for a given slide
|
|
274
|
+
// - isIntersecting will change when the element enters and leaves
|
|
275
|
+
const onObserve = (entries) => {
|
|
276
|
+
entries.forEach((entry) => {
|
|
277
|
+
|
|
278
|
+
this.$nextTick(() => {
|
|
279
|
+
const slide = this.getSlideByElement(entry.target);
|
|
280
|
+
slide.active = entry.isIntersecting;
|
|
281
|
+
this.$emit('slideChange', { slide, track, nav });
|
|
282
|
+
});
|
|
283
|
+
});
|
|
284
|
+
};
|
|
285
|
+
// Add non-reactive prop for removal and changes to targets
|
|
286
|
+
this.observer = new IntersectionObserver(onObserve, {
|
|
287
|
+
root: track,
|
|
288
|
+
...observerOptions
|
|
289
|
+
});
|
|
290
|
+
},
|
|
291
|
+
/**
|
|
292
|
+
* Add all slide elements as targets in observer
|
|
293
|
+
*/
|
|
294
|
+
observeSlides() {
|
|
295
|
+
const { observer, slides } = this;
|
|
296
|
+
observer.disconnect();
|
|
297
|
+
slides.forEach(({ element }) => {
|
|
298
|
+
if (element) {
|
|
299
|
+
observer.observe(element);
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
},
|
|
303
|
+
/**
|
|
304
|
+
* Remove observer and it's internal DOM references (GC)
|
|
305
|
+
*/
|
|
306
|
+
destroyObserver() {
|
|
307
|
+
this.observer.disconnect();
|
|
308
|
+
this.observer = null;
|
|
309
|
+
},
|
|
310
|
+
},
|
|
311
|
+
mounted() {
|
|
312
|
+
this.createObserver();
|
|
313
|
+
this.observeSlides();
|
|
314
|
+
},
|
|
315
|
+
beforeUnmount() {
|
|
316
|
+
this.destroyObserver();
|
|
317
|
+
},
|
|
318
|
+
}
|
|
319
|
+
</script>
|
|
320
|
+
|
|
321
|
+
<!--
|
|
322
|
+
Old Notes:
|
|
323
|
+
- How to get around access the elements of the children in slots
|
|
324
|
+
- Component element is not available
|
|
325
|
+
- Hacks
|
|
326
|
+
- Add hidden element and use nextSibling (stack overflow suggestion)
|
|
327
|
+
- Don't like this. We could always traverse dom from the parent track ref anyways
|
|
328
|
+
but I'm trying to avoid that
|
|
329
|
+
- Ideas
|
|
330
|
+
- Watch the slot components and use
|
|
331
|
+
-->
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
Notes:
|
|
3
|
+
- This component is used in parent to identify slides in default slot
|
|
4
|
+
-->
|
|
5
|
+
<template>
|
|
6
|
+
<li class="slideshow__slide" :class="{ 'is-active' : active }">
|
|
7
|
+
<slot/>
|
|
8
|
+
</li>
|
|
9
|
+
</template>
|
|
10
|
+
|
|
11
|
+
<script>
|
|
12
|
+
export default {
|
|
13
|
+
name: 'SlideShowSlide',
|
|
14
|
+
props: {
|
|
15
|
+
/**
|
|
16
|
+
* Provided by grandparent, not user
|
|
17
|
+
*/
|
|
18
|
+
active: Boolean,
|
|
19
|
+
someClassTest: String
|
|
20
|
+
},
|
|
21
|
+
mounted() {
|
|
22
|
+
console.log('slide mounted');
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
</script>
|