@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
package/lib/_index.scss
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
////
|
|
2
|
+
/// @group index
|
|
3
|
+
////
|
|
4
|
+
/// Main entry for library as single module use
|
|
5
|
+
/// - All modules get namespaced
|
|
6
|
+
/// @example scss - Example of color modules
|
|
7
|
+
/// // Namespaced
|
|
8
|
+
/// ulu-vue.component-table-sticky-styles();
|
|
9
|
+
/// // Versus
|
|
10
|
+
/// table-sticky.styles();
|
|
11
|
+
///
|
|
12
|
+
|
|
13
|
+
@forward "components" as component-*;
|
|
14
|
+
@forward "plugins" as plugin-*;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Disclosure :defaultOpen="defaultOpen" v-slot="{ open }">
|
|
3
|
+
<div
|
|
4
|
+
class="accordion"
|
|
5
|
+
:class="[
|
|
6
|
+
{ [activeClass]: open },
|
|
7
|
+
classes.container,
|
|
8
|
+
resolvedModifiers
|
|
9
|
+
]"
|
|
10
|
+
>
|
|
11
|
+
<DisclosureButton
|
|
12
|
+
class="accordion__summary"
|
|
13
|
+
:class="[
|
|
14
|
+
{ [activeClass]: open },
|
|
15
|
+
classes.summary
|
|
16
|
+
]"
|
|
17
|
+
>
|
|
18
|
+
<slot name="summary" :open="open">
|
|
19
|
+
<component :is="summaryTextElement">
|
|
20
|
+
{{ summaryText }}
|
|
21
|
+
</component>
|
|
22
|
+
</slot>
|
|
23
|
+
<slot name="icon" :open="open">
|
|
24
|
+
<span class="accordion__icon" :class="classes.icon">
|
|
25
|
+
<UluIcon
|
|
26
|
+
:type="open ? 'collapse' : 'expand'"
|
|
27
|
+
style="display: inline;"
|
|
28
|
+
/>
|
|
29
|
+
</span>
|
|
30
|
+
</slot>
|
|
31
|
+
</DisclosureButton>
|
|
32
|
+
<DisclosurePanel class="accordion__content" :class="classes.content">
|
|
33
|
+
<slot :open="open"/>
|
|
34
|
+
</DisclosurePanel>
|
|
35
|
+
</div>
|
|
36
|
+
</Disclosure>
|
|
37
|
+
</template>
|
|
38
|
+
|
|
39
|
+
<script setup>
|
|
40
|
+
import UluIcon from "../elements/UluIcon.vue";
|
|
41
|
+
import { useModifiers } from "../../composables/useModifiers.js";
|
|
42
|
+
import { Disclosure, DisclosureButton, DisclosurePanel } from "@headlessui/vue";
|
|
43
|
+
const props = defineProps({
|
|
44
|
+
/**
|
|
45
|
+
* Whether the accordion is open by default
|
|
46
|
+
*/
|
|
47
|
+
defaultOpen: Boolean,
|
|
48
|
+
/**
|
|
49
|
+
* Test to use for accordion, alternatively use #toggle slot
|
|
50
|
+
*/
|
|
51
|
+
summaryText: String,
|
|
52
|
+
/**
|
|
53
|
+
* If using summary text sets the inner element the text is wrapped in, usually a headline or strong
|
|
54
|
+
*/
|
|
55
|
+
summaryTextElement: {
|
|
56
|
+
type: String,
|
|
57
|
+
default: "strong"
|
|
58
|
+
},
|
|
59
|
+
/**
|
|
60
|
+
* Classes for elements ({ container, summary, icon, content })
|
|
61
|
+
* - Any valid class binding value per element
|
|
62
|
+
*/
|
|
63
|
+
classes: {
|
|
64
|
+
type: Object,
|
|
65
|
+
default: () => ({})
|
|
66
|
+
},
|
|
67
|
+
/**
|
|
68
|
+
* Active class output on container and toggle elements
|
|
69
|
+
*/
|
|
70
|
+
activeClass: {
|
|
71
|
+
type: String,
|
|
72
|
+
default: "is-active"
|
|
73
|
+
},
|
|
74
|
+
/**
|
|
75
|
+
* Modifiers for tag class
|
|
76
|
+
*/
|
|
77
|
+
modifiers: [String, Array]
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
const { resolvedModifiers } = useModifiers({ props, baseClass: "button" });
|
|
81
|
+
|
|
82
|
+
</script>
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
class="CollapsibleRegion"
|
|
4
|
+
@keydown.esc="handleEscape"
|
|
5
|
+
:class="{
|
|
6
|
+
'CollapsibleRegion--open' : isOpen,
|
|
7
|
+
'CollapsibleRegion--closed' : !isOpen,
|
|
8
|
+
'CollapsibleRegion--transitioning' : isTransitioning
|
|
9
|
+
}"
|
|
10
|
+
>
|
|
11
|
+
<button
|
|
12
|
+
class="CollapsibleRegion__toggle"
|
|
13
|
+
:id="toggleId"
|
|
14
|
+
:aria-controls="contentId"
|
|
15
|
+
:aria-expanded="isOpen"
|
|
16
|
+
@click="toggle"
|
|
17
|
+
>
|
|
18
|
+
<slot name="toggle" :isOpen="isOpen">
|
|
19
|
+
{{ title }}
|
|
20
|
+
</slot>
|
|
21
|
+
</button>
|
|
22
|
+
<div
|
|
23
|
+
class="CollapsibleRegion__content"
|
|
24
|
+
tabindex="-1"
|
|
25
|
+
ref="content"
|
|
26
|
+
:id="contentId"
|
|
27
|
+
:aria-hidden="!isOpen"
|
|
28
|
+
:aria-labelledby="toggleId"
|
|
29
|
+
:style="contentStyles"
|
|
30
|
+
v-show="!isHidden"
|
|
31
|
+
>
|
|
32
|
+
<!--
|
|
33
|
+
Using inner container to allow no styles on content container
|
|
34
|
+
as they interfere with getting accurate measurements of the content
|
|
35
|
+
when it's hidden (scrollHeight)
|
|
36
|
+
-->
|
|
37
|
+
<div class="CollapsibleRegion__content-inner">
|
|
38
|
+
<slot/>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
</template>
|
|
43
|
+
|
|
44
|
+
<script>
|
|
45
|
+
|
|
46
|
+
let uid = 0;
|
|
47
|
+
/**
|
|
48
|
+
* Utility component for creating disclosure type behaviors (show/hide)
|
|
49
|
+
*/
|
|
50
|
+
export default {
|
|
51
|
+
name: "UluCollapsibleRegion",
|
|
52
|
+
props: {
|
|
53
|
+
/**
|
|
54
|
+
* Set title for toggle (instead of using slot)
|
|
55
|
+
*/
|
|
56
|
+
title: String,
|
|
57
|
+
/**
|
|
58
|
+
* Closes with escape key
|
|
59
|
+
*/
|
|
60
|
+
closeOnEscape: Boolean,
|
|
61
|
+
/**
|
|
62
|
+
* When the component is shown it should start visible or hidden
|
|
63
|
+
*/
|
|
64
|
+
startOpen: Boolean,
|
|
65
|
+
/**
|
|
66
|
+
* Whether or not to transition the show and hide
|
|
67
|
+
*/
|
|
68
|
+
transitionHeight: Boolean,
|
|
69
|
+
/**
|
|
70
|
+
* Transition should fade as it expands
|
|
71
|
+
*/
|
|
72
|
+
transitionFades: Boolean,
|
|
73
|
+
/**
|
|
74
|
+
* Transition Timing Function
|
|
75
|
+
*/
|
|
76
|
+
transitionTiming: {
|
|
77
|
+
type: String,
|
|
78
|
+
default: "ease-out"
|
|
79
|
+
},
|
|
80
|
+
/**
|
|
81
|
+
* Transition Duration (css duration string), use comma seperation if different for opacity (fade).
|
|
82
|
+
* Note: This is used to calculate a fallback timer if transitions fail
|
|
83
|
+
*/
|
|
84
|
+
transitionDuration: {
|
|
85
|
+
type: String,
|
|
86
|
+
default: "400ms",
|
|
87
|
+
validator(value) {
|
|
88
|
+
// Make sure that it's a valid css duration (ms|s)
|
|
89
|
+
return value.includes("s");
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
data() {
|
|
94
|
+
const isOpen = this.startOpen;
|
|
95
|
+
// Note (isOpen vs isHidden): 'isOpen' is the actaul state of the content,
|
|
96
|
+
// and 'isHidden' is just used for display none
|
|
97
|
+
return {
|
|
98
|
+
isOpen,
|
|
99
|
+
toggleId: this.getUid(),
|
|
100
|
+
contentId: this.getUid(),
|
|
101
|
+
contentHeight: isOpen ? "auto" : "0px",
|
|
102
|
+
contentOpacity: this.transitionFades && !isOpen ? 0 : 1,
|
|
103
|
+
transitionsDisabled: false,
|
|
104
|
+
transitionTimeout: Math.ceil(this.getUnitlessDuration(this.transitionDuration) + 500),
|
|
105
|
+
isTransitioning: false,
|
|
106
|
+
isHidden: isOpen ? false : true,
|
|
107
|
+
onCleanupTransition: null, // Transitions add function here used if needing to cancel
|
|
108
|
+
};
|
|
109
|
+
},
|
|
110
|
+
computed: {
|
|
111
|
+
contentStyles() {
|
|
112
|
+
if (this.transitionHeight) {
|
|
113
|
+
return {
|
|
114
|
+
overflow: "hidden",
|
|
115
|
+
height: this.contentHeight,
|
|
116
|
+
transitionDuration: this.transitionDuration,
|
|
117
|
+
transitionTiming: this.transitionTiming,
|
|
118
|
+
opacity: this.contentOpacity,
|
|
119
|
+
transitionProperty: this.transitionsDisabled ? "none" : `height${ this.transitionFades ? ",opacity" : "" }`
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
return {};
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
methods: {
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Function used to toggle the collapsible
|
|
129
|
+
*/
|
|
130
|
+
toggle() {
|
|
131
|
+
// console.log('Toggle Click', this.isOpen);
|
|
132
|
+
if (this.isOpen && !this.isTransitioning) {
|
|
133
|
+
this.close();
|
|
134
|
+
} else {
|
|
135
|
+
this.open();
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
handleEscape() {
|
|
139
|
+
if (this.closeOnEscape && this.isOpen) {
|
|
140
|
+
this.close();
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
removeTransition(_canceled) {
|
|
144
|
+
if (this.onCleanupTransition) this.onCleanupTransition();
|
|
145
|
+
this.isTransitioning = false;
|
|
146
|
+
this.onCleanupTransition = null;
|
|
147
|
+
},
|
|
148
|
+
/**
|
|
149
|
+
* Function that will handle setting the styles in a way that allows for
|
|
150
|
+
* transitioning from display: none to height: auto. With optional fade.
|
|
151
|
+
*/
|
|
152
|
+
open() {
|
|
153
|
+
// If there are no animations
|
|
154
|
+
if (!this.transitionHeight) {
|
|
155
|
+
this.isOpen = true;
|
|
156
|
+
this.isHidden = false;
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
this.removeTransition(true);
|
|
161
|
+
|
|
162
|
+
let tid;
|
|
163
|
+
const element = this.$refs.content;
|
|
164
|
+
// When finished clear the fallback and set the height to auto
|
|
165
|
+
// incase something else on the page changes this elements layout/height,
|
|
166
|
+
// remove the one time listener, and call the ending callback
|
|
167
|
+
// and user callbacks
|
|
168
|
+
const complete = () => {
|
|
169
|
+
this.contentHeight = "auto";
|
|
170
|
+
this.isOpen = true;
|
|
171
|
+
this.removeTransition();
|
|
172
|
+
this.$emit("collapsible-opened");
|
|
173
|
+
};
|
|
174
|
+
this.onCleanupTransition = () => {
|
|
175
|
+
clearTimeout(tid);
|
|
176
|
+
element.removeEventListener("transitionend", complete);
|
|
177
|
+
};
|
|
178
|
+
// Listen for the end of the transition we are about to trigger on
|
|
179
|
+
element.addEventListener("transitionend", complete);
|
|
180
|
+
this.isHidden = false;
|
|
181
|
+
this.isTransitioning = true;
|
|
182
|
+
this.$emit("collapsible-opening");
|
|
183
|
+
// Waiting for vue to update the elements style.display from none
|
|
184
|
+
// so we can measure it's hidden height, set it statically,
|
|
185
|
+
// to then trigger the transition to that static height
|
|
186
|
+
this.$nextTick(() => {
|
|
187
|
+
this.contentHeight = element.scrollHeight + "px";
|
|
188
|
+
if (this.transitionFades) this.contentOpacity = 1;
|
|
189
|
+
// Setting a fallback incase anything interupts the browsers
|
|
190
|
+
// ability to fire the 'transitionend' event, the element will
|
|
191
|
+
// still be functional
|
|
192
|
+
tid = setTimeout(complete, this.transitionTimeout);
|
|
193
|
+
});
|
|
194
|
+
},
|
|
195
|
+
/**
|
|
196
|
+
* Function that will handle setting the styles in a way that allows for
|
|
197
|
+
* transitioning from height: auto to display: none
|
|
198
|
+
*/
|
|
199
|
+
close() {
|
|
200
|
+
// If there are no animations
|
|
201
|
+
if (!this.transitionHeight) {
|
|
202
|
+
this.isOpen = false;
|
|
203
|
+
this.isHidden = true;
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
this.removeTransition(true);
|
|
208
|
+
|
|
209
|
+
let tid;
|
|
210
|
+
// Measure the elements height, to set it from auto
|
|
211
|
+
// to static so that we can transition it
|
|
212
|
+
const element = this.$refs.content;
|
|
213
|
+
const height = element.scrollHeight;
|
|
214
|
+
// Set the elements height to a static value so we can transition it
|
|
215
|
+
// then on next tick when that value is set, start the transition
|
|
216
|
+
const setup = () => {
|
|
217
|
+
element.addEventListener("transitionend", complete);
|
|
218
|
+
this.contentHeight = height + "px";
|
|
219
|
+
this.$nextTick(init);
|
|
220
|
+
};
|
|
221
|
+
// Enable transitions and then on next update start it
|
|
222
|
+
// by setting the height to 0
|
|
223
|
+
const init = () => {
|
|
224
|
+
this.transitionsDisabled = false;
|
|
225
|
+
this.$nextTick(() => {
|
|
226
|
+
requestAnimationFrame(transition);
|
|
227
|
+
});
|
|
228
|
+
};
|
|
229
|
+
const transition = () => {
|
|
230
|
+
this.contentHeight = "0px";
|
|
231
|
+
if (this.transitionFades) this.contentOpacity = 0;
|
|
232
|
+
};
|
|
233
|
+
const complete = () => {
|
|
234
|
+
this.isOpen = false;
|
|
235
|
+
this.isHidden = true;
|
|
236
|
+
this.removeTransition();
|
|
237
|
+
this.$emit("collapsible-closed");
|
|
238
|
+
};
|
|
239
|
+
const fallback = () => {
|
|
240
|
+
transition();
|
|
241
|
+
complete();
|
|
242
|
+
};
|
|
243
|
+
this.onCleanupTransition = () => {
|
|
244
|
+
clearTimeout(tid);
|
|
245
|
+
element.removeEventListener("transitionend", complete);
|
|
246
|
+
};
|
|
247
|
+
// Temporarily disable the transitions on the element,
|
|
248
|
+
// on next tick when transistions are disabled (removing transiton-property)
|
|
249
|
+
// attach the fallback and setup the transition
|
|
250
|
+
this.transitionsDisabled = true;
|
|
251
|
+
this.isTransitioning = true;
|
|
252
|
+
this.$emit("collapsible-closing");
|
|
253
|
+
this.$nextTick(() => {
|
|
254
|
+
requestAnimationFrame(setup);
|
|
255
|
+
tid = setTimeout(fallback, this.transitionTimeout);
|
|
256
|
+
});
|
|
257
|
+
},
|
|
258
|
+
/**
|
|
259
|
+
* Returns unitless duration
|
|
260
|
+
* @param {String} duration - Css duration string
|
|
261
|
+
*/
|
|
262
|
+
getUnitlessDuration(value) {
|
|
263
|
+
// Grab only first value in string
|
|
264
|
+
let duration = parseFloat( value.split(",")[0] );
|
|
265
|
+
// If not milliseconds we need to convert assumed if
|
|
266
|
+
// not milliseconds it's seconds (only other valid duration)
|
|
267
|
+
return value.includes("ms") ? duration : duration * 1000;
|
|
268
|
+
},
|
|
269
|
+
/**
|
|
270
|
+
* Recursive function to generate and test id uniqueness
|
|
271
|
+
*/
|
|
272
|
+
getUid() {
|
|
273
|
+
const id = `Ulu-C-${ ++uid }`;
|
|
274
|
+
return document.getElementById(id) ? this.getUid() : id;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
</script>
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<UluPopover :classes="popoverClasses">
|
|
3
|
+
<template #trigger="{ isOpen }">
|
|
4
|
+
<slot :isOpen="isOpen"/>
|
|
5
|
+
</template>
|
|
6
|
+
<template #content>
|
|
7
|
+
<UluMenuStack :items="items"/>
|
|
8
|
+
</template>
|
|
9
|
+
</UluPopover>
|
|
10
|
+
</template>
|
|
11
|
+
|
|
12
|
+
<script>
|
|
13
|
+
import UluPopover from "../../plugins/popovers/UluPopover.vue";
|
|
14
|
+
import UluMenuStack from "../navigation/UluMenuStack.vue";
|
|
15
|
+
export default {
|
|
16
|
+
name: "UluDropdown",
|
|
17
|
+
components: {
|
|
18
|
+
UluPopover,
|
|
19
|
+
UluMenuStack
|
|
20
|
+
},
|
|
21
|
+
props: {
|
|
22
|
+
/**
|
|
23
|
+
* Dropdown menu items (to be passed to UluMenu)
|
|
24
|
+
*/
|
|
25
|
+
items: Array,
|
|
26
|
+
/**
|
|
27
|
+
* Class to use on trigger
|
|
28
|
+
*/
|
|
29
|
+
triggerClass: {
|
|
30
|
+
type: [String, Object, Array],
|
|
31
|
+
default: "button"
|
|
32
|
+
},
|
|
33
|
+
/**
|
|
34
|
+
* Pass classes object to UluPopover classes prop
|
|
35
|
+
*/
|
|
36
|
+
popoverClasses: {
|
|
37
|
+
type: Object,
|
|
38
|
+
default: () => ({})
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
</script>
|