@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,54 @@
|
|
|
1
|
+
import { ref } from "vue";
|
|
2
|
+
import defaults from "./defaults.js";
|
|
3
|
+
|
|
4
|
+
export const options = {
|
|
5
|
+
plugin: { ...defaults.plugin },
|
|
6
|
+
popover: { ...defaults.popover },
|
|
7
|
+
tooltip: { ...defaults.tooltip, ...defaults.popover },
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Whether or not the tooltip is active
|
|
12
|
+
*/
|
|
13
|
+
export const active = ref(false);
|
|
14
|
+
/**
|
|
15
|
+
* Current tooltip config
|
|
16
|
+
*/
|
|
17
|
+
export const activeConfig = ref(null);
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Setup the store options
|
|
21
|
+
* @param {Object} userOptions
|
|
22
|
+
* @param {Object} options Resolved options
|
|
23
|
+
*/
|
|
24
|
+
export function init(userOptions = {}) {
|
|
25
|
+
Object.assign(options.popover, userOptions.popover);
|
|
26
|
+
Object.assign(options.tooltip, userOptions.tooltip);
|
|
27
|
+
Object.assign(options.plugin, userOptions.plugin);
|
|
28
|
+
return options;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Config for a single tooltip instance
|
|
33
|
+
*/
|
|
34
|
+
export function createConfig(userConfig) {
|
|
35
|
+
return Object.assign({}, options.tooltip, userConfig);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Show a tooltip
|
|
40
|
+
* - Set by directive
|
|
41
|
+
*/
|
|
42
|
+
export function show(config) {
|
|
43
|
+
active.value = true;
|
|
44
|
+
activeConfig.value = config;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Hide a tooltip
|
|
49
|
+
* - Set by directive
|
|
50
|
+
*/
|
|
51
|
+
export function hide() {
|
|
52
|
+
active.value = false;
|
|
53
|
+
activeConfig.value = null;
|
|
54
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { ref } from "vue";
|
|
2
|
+
import { show, hide, createConfig } from "./manager.js";
|
|
3
|
+
|
|
4
|
+
const defaults = {
|
|
5
|
+
content: null
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export default function useFollowPoint(userOptions) {
|
|
9
|
+
if (!userOptions.content) {
|
|
10
|
+
console.warn("Missing content for 'useFollowPoint' tooltip", userOptions);
|
|
11
|
+
}
|
|
12
|
+
const options = Object.assign({}, defaults, userOptions);
|
|
13
|
+
|
|
14
|
+
let _update;
|
|
15
|
+
|
|
16
|
+
const x = ref(0);
|
|
17
|
+
const y = ref(0);
|
|
18
|
+
|
|
19
|
+
const config = createConfig({
|
|
20
|
+
trigger: ref({
|
|
21
|
+
getBoundingClientRect() {
|
|
22
|
+
const currentX = x.value;
|
|
23
|
+
const currentY = y.value;
|
|
24
|
+
return {
|
|
25
|
+
width: 0,
|
|
26
|
+
height: 0,
|
|
27
|
+
x: currentX,
|
|
28
|
+
left: currentX,
|
|
29
|
+
right: currentX,
|
|
30
|
+
y: currentY,
|
|
31
|
+
top: currentY,
|
|
32
|
+
bottom: currentY,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
}),
|
|
36
|
+
content: options.content,
|
|
37
|
+
inline: false,
|
|
38
|
+
onReady({ update }) {
|
|
39
|
+
_update = update;
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
/**
|
|
45
|
+
* Reactive X value
|
|
46
|
+
* @type {Object}
|
|
47
|
+
*/
|
|
48
|
+
x,
|
|
49
|
+
/**
|
|
50
|
+
* Reactive Y value
|
|
51
|
+
* @type {Object}
|
|
52
|
+
*/
|
|
53
|
+
y,
|
|
54
|
+
/**
|
|
55
|
+
* Show follow tooltip
|
|
56
|
+
*/
|
|
57
|
+
show() {
|
|
58
|
+
show(config);
|
|
59
|
+
},
|
|
60
|
+
/**
|
|
61
|
+
* Hide follow tooltip
|
|
62
|
+
*/
|
|
63
|
+
hide() {
|
|
64
|
+
hide(config);
|
|
65
|
+
},
|
|
66
|
+
/**
|
|
67
|
+
*
|
|
68
|
+
* @param {Object} changes Updates for virtual element
|
|
69
|
+
* @param {Object} changes.x New 'x' value
|
|
70
|
+
* @param {Object} changes.y New 'y' value
|
|
71
|
+
*/
|
|
72
|
+
update(changes) {
|
|
73
|
+
x.value = changes.x;
|
|
74
|
+
y.value = changes.y;
|
|
75
|
+
if (_update) {
|
|
76
|
+
_update();
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
Using slots so that user can wrap component for custom displays within default template (ie. to render a badge, etc)
|
|
3
|
+
-->
|
|
4
|
+
<template>
|
|
5
|
+
<div
|
|
6
|
+
class="toast"
|
|
7
|
+
:class="[
|
|
8
|
+
{
|
|
9
|
+
'toast--persistent' : !toast.duration
|
|
10
|
+
},
|
|
11
|
+
toast?.class
|
|
12
|
+
]"
|
|
13
|
+
>
|
|
14
|
+
<div v-if="toast.icon || $slots.icon" class="toast__icon" :class="classes.icon">
|
|
15
|
+
<slot name="icon" :toast="toast">
|
|
16
|
+
<FaIcon v-if="toast.icon" :icon="toast.icon"/>
|
|
17
|
+
</slot>
|
|
18
|
+
</div>
|
|
19
|
+
<div class="toast__content" :class="classes.content">
|
|
20
|
+
<slot name="content" :toast="toast">
|
|
21
|
+
<div v-if="toast.title" class="toast__header" :class="classes.header">
|
|
22
|
+
<strong class="toast__title" :class="classes.title">
|
|
23
|
+
{{ toast.title }}
|
|
24
|
+
</strong>
|
|
25
|
+
<span v-if="toast.date" class="toast__date" :class="classes.date">
|
|
26
|
+
{{ toast.date }}
|
|
27
|
+
</span>
|
|
28
|
+
</div>
|
|
29
|
+
<div v-if="toast.description" class="toast__body" :class="classes.body">
|
|
30
|
+
{{ toast.description }}
|
|
31
|
+
</div>
|
|
32
|
+
</slot>
|
|
33
|
+
</div>
|
|
34
|
+
<div v-if="toast.actions?.length" class="toast__actions" :class="classes.actions">
|
|
35
|
+
<button
|
|
36
|
+
v-for="(action, index) in toast.actions"
|
|
37
|
+
:key="index"
|
|
38
|
+
class="toast__action"
|
|
39
|
+
:class="classes.action"
|
|
40
|
+
@click="handleAction($event, action)"
|
|
41
|
+
>
|
|
42
|
+
{{ action.label }}
|
|
43
|
+
</button>
|
|
44
|
+
</div>
|
|
45
|
+
<button class="toast__close" :class="classes.closeButton" @click="toast.close">
|
|
46
|
+
<UluIcon type="close"/>
|
|
47
|
+
</button>
|
|
48
|
+
</div>
|
|
49
|
+
</template>
|
|
50
|
+
|
|
51
|
+
<script>
|
|
52
|
+
import UluIcon from "../../components/elements/UluIcon.vue";
|
|
53
|
+
export default {
|
|
54
|
+
name: 'UluToast',
|
|
55
|
+
components: {
|
|
56
|
+
UluIcon
|
|
57
|
+
},
|
|
58
|
+
props: {
|
|
59
|
+
/**
|
|
60
|
+
* Toast configuration
|
|
61
|
+
*/
|
|
62
|
+
toast: Object,
|
|
63
|
+
/**
|
|
64
|
+
* Icons for each element { icon, header, content, date, actions, action, closeButton, title, body, closeButton }
|
|
65
|
+
*/
|
|
66
|
+
classes: {
|
|
67
|
+
type: Object,
|
|
68
|
+
default: () => ({
|
|
69
|
+
content: "type-small",
|
|
70
|
+
date: "type-small-x",
|
|
71
|
+
actions: "type-small-x",
|
|
72
|
+
action: "button button--small button--outline",
|
|
73
|
+
closeButton: "button button--icon button--transparent"
|
|
74
|
+
})
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
methods: {
|
|
78
|
+
handleAction(event, action) {
|
|
79
|
+
const { toast } = this;
|
|
80
|
+
this.toast.close();
|
|
81
|
+
this.$nextTick(() => {
|
|
82
|
+
action(event, toast, action);
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
</script>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Teleport :to="pluginOptions.teleportTo">
|
|
3
|
+
<TransitionGroup
|
|
4
|
+
class="toast-container"
|
|
5
|
+
:class="classes"
|
|
6
|
+
name="toast"
|
|
7
|
+
tag="div"
|
|
8
|
+
>
|
|
9
|
+
<component
|
|
10
|
+
v-for="toast in toasts"
|
|
11
|
+
:key="toast.uid"
|
|
12
|
+
:is="toast.component"
|
|
13
|
+
:toast="toast"
|
|
14
|
+
/>
|
|
15
|
+
</TransitionGroup>
|
|
16
|
+
</Teleport>
|
|
17
|
+
</template>
|
|
18
|
+
|
|
19
|
+
<script>
|
|
20
|
+
import { store } from "./store.js";
|
|
21
|
+
export default {
|
|
22
|
+
name: 'UluTooltipDisplay',
|
|
23
|
+
data() {
|
|
24
|
+
const { toasts, pluginOptions } = store;
|
|
25
|
+
return { toasts, pluginOptions };
|
|
26
|
+
},
|
|
27
|
+
computed: {
|
|
28
|
+
classes() {
|
|
29
|
+
const { position } = this.pluginOptions;
|
|
30
|
+
const positionClasses = position.map(p => `toast-container--${ p }`);
|
|
31
|
+
return positionClasses;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
</script>
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
////
|
|
2
|
+
/// @group toast
|
|
3
|
+
/// Toast notifications
|
|
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
|
+
@use "@ulu/frontend/scss/layout";
|
|
14
|
+
@use "@ulu/frontend/scss/button";
|
|
15
|
+
@use "@ulu/frontend/scss/typography";
|
|
16
|
+
@use "@ulu/frontend/scss/cssvar";
|
|
17
|
+
|
|
18
|
+
// Used for function fallback
|
|
19
|
+
$-fallbacks: (
|
|
20
|
+
"box-shadow" : (
|
|
21
|
+
"function" : meta.get-function("get", false, "element"),
|
|
22
|
+
"property" : "box-shadow-above"
|
|
23
|
+
),
|
|
24
|
+
"border-radius": (
|
|
25
|
+
"function": meta.get-function("get", false, "button"),
|
|
26
|
+
"property": "border-radius"
|
|
27
|
+
),
|
|
28
|
+
"z-index": (
|
|
29
|
+
"function": meta.get-function("get", false, "layout"),
|
|
30
|
+
"property": "z-index-fixed"
|
|
31
|
+
),
|
|
32
|
+
"date-font-weight": (
|
|
33
|
+
"function": meta.get-function("get", false, "typography"),
|
|
34
|
+
"property": "font-weight-light"
|
|
35
|
+
)
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
/// Module Settings
|
|
39
|
+
/// @type Map
|
|
40
|
+
/// @prop {CssValue} z-index [true] - Z-index of the toast container
|
|
41
|
+
/// @prop {CssValue} box-shadow [true] - Box shadow for the toast
|
|
42
|
+
/// @prop {Color} background-color [white] - Background color of the toast
|
|
43
|
+
/// @prop {CssValue} border-radius [true] - Border radius of the toast
|
|
44
|
+
/// @prop {CssValue} border-width [5px] - Border width of the toast
|
|
45
|
+
/// @prop {Color} border-color [transparent] - Border color of the toast
|
|
46
|
+
/// @prop {CssValue} padding [0 0 0 1rem] - Padding of the toast
|
|
47
|
+
/// @prop {CssValue} line-height [1] - Line height of the toast
|
|
48
|
+
/// @prop {CssValue} margin-bottom [0.5rem] - Margin bottom of the toast
|
|
49
|
+
/// @prop {CssValue} container-top [1rem] - Top position of the toast container
|
|
50
|
+
/// @prop {CssValue} container-right [1rem] - Right position of the toast container
|
|
51
|
+
/// @prop {CssValue} container-width [min(24rem, 100vw - 2rem)] - Width of the toast container
|
|
52
|
+
/// @prop {Color} date-color ["type-tertiary"] - Color of the date
|
|
53
|
+
/// @prop {CssValue} date-font-weight [true] - Font weight of the date
|
|
54
|
+
/// @prop {CssValue} icon-margin-right [0.7rem] - Margin right of the icon
|
|
55
|
+
/// @prop {CssValue} icon-font-size [1.2rem] - Font size of the icon
|
|
56
|
+
/// @prop {CssValue} actions-margin-right [3px] - Margin right of the actions container
|
|
57
|
+
/// @prop {CssValue} action-margin-top [3px] - Margin top of the action buttons
|
|
58
|
+
/// @prop {CssValue} content-padding [0.25rem 0.5rem 0.25rem 0] - Padding of the content
|
|
59
|
+
/// @prop {CssValue} persistent-animation [UluWiggle 4s infinite] - Animation for persistent toasts
|
|
60
|
+
|
|
61
|
+
$config: (
|
|
62
|
+
"z-index": true,
|
|
63
|
+
"box-shadow": true,
|
|
64
|
+
"background-color": white,
|
|
65
|
+
"border-radius": true,
|
|
66
|
+
"border-width": 5px,
|
|
67
|
+
"border-color": transparent,
|
|
68
|
+
"padding": 0 0 0 1rem,
|
|
69
|
+
"line-height": 1,
|
|
70
|
+
"margin-bottom": 0.5rem,
|
|
71
|
+
"container-top": 1rem,
|
|
72
|
+
"container-right": 1rem,
|
|
73
|
+
"container-width": min(24rem, 100vw - 2rem),
|
|
74
|
+
"date-color": "type-tertiary",
|
|
75
|
+
"date-font-weight": true,
|
|
76
|
+
"icon-margin-right": 0.7rem,
|
|
77
|
+
"icon-font-size": 1.2rem,
|
|
78
|
+
"actions-margin-right": 3px,
|
|
79
|
+
"action-margin-top": 3px,
|
|
80
|
+
"content-padding": (0.25rem 0.5rem 0.25rem 0),
|
|
81
|
+
"persistent-animation": (UluWiggle 4s infinite),
|
|
82
|
+
) !default;
|
|
83
|
+
|
|
84
|
+
/// Change modules $config
|
|
85
|
+
/// @param {Map} $changes Map of changes
|
|
86
|
+
/// @example scss
|
|
87
|
+
/// @include ulu-vue.toast-set(( "property" : value ));
|
|
88
|
+
|
|
89
|
+
@mixin set($changes) {
|
|
90
|
+
$config: map.merge($config, $changes) !global;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/// Get a config option
|
|
94
|
+
/// @param {Map} $name Name of property
|
|
95
|
+
/// @example scss
|
|
96
|
+
/// @include ulu.toast-get("property");
|
|
97
|
+
|
|
98
|
+
@function get($name) {
|
|
99
|
+
$value: utils.require-map-get($config, $name, "toast [config]");
|
|
100
|
+
@return utils.function-fallback($name, $value, $-fallbacks);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/// Prints component styles
|
|
104
|
+
/// @demo toast
|
|
105
|
+
/// @example scss
|
|
106
|
+
/// @include ulu.toast-styles();
|
|
107
|
+
|
|
108
|
+
@mixin styles {
|
|
109
|
+
$prefix: selector.class("toast");
|
|
110
|
+
|
|
111
|
+
#{ $prefix }-container {
|
|
112
|
+
position: fixed;
|
|
113
|
+
top: get("container-top");
|
|
114
|
+
right: get("container-right");
|
|
115
|
+
width: get("container-width");
|
|
116
|
+
z-index: get("z-index");
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
#{ $prefix } {
|
|
120
|
+
box-shadow: get("box-shadow");
|
|
121
|
+
background-color: get("background-color");
|
|
122
|
+
border-radius: get("border-radius");
|
|
123
|
+
border: get("border-width") solid get("border-color");
|
|
124
|
+
padding: get("padding");
|
|
125
|
+
line-height: get("line-height");
|
|
126
|
+
margin-bottom: get("margin-bottom");
|
|
127
|
+
display: flex;
|
|
128
|
+
align-items: center;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
#{ $prefix }__header {
|
|
132
|
+
display: flex;
|
|
133
|
+
justify-content: space-between;
|
|
134
|
+
align-items: baseline;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
#{ $prefix }__date {
|
|
138
|
+
color: get("date-color");
|
|
139
|
+
font-weight: get("date-font-weight");
|
|
140
|
+
margin-left: 1em;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
#{ $prefix }__icon {
|
|
144
|
+
margin-right: get("icon-margin-right");
|
|
145
|
+
font-size: get("icon-font-size");
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
#{ $prefix }__actions {
|
|
149
|
+
flex-basis: min-content;
|
|
150
|
+
display: flex;
|
|
151
|
+
flex-direction: column;
|
|
152
|
+
justify-content: center;
|
|
153
|
+
align-items: center;
|
|
154
|
+
margin-right: get("actions-margin-right");
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
#{ $prefix }__action {
|
|
158
|
+
width: 100%;
|
|
159
|
+
margin: 0;
|
|
160
|
+
& + & {
|
|
161
|
+
margin-top: get("action-margin-top");
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
#{ $prefix }__close {
|
|
166
|
+
margin: 0;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
#{ $prefix }__content {
|
|
170
|
+
margin-right: auto;
|
|
171
|
+
flex-grow: 1;
|
|
172
|
+
padding: get("content-padding");
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
#{ $prefix }--persistent {
|
|
176
|
+
animation: get("persistent-animation");
|
|
177
|
+
&:hover,
|
|
178
|
+
&:focus-within {
|
|
179
|
+
animation: none;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Vue animation
|
|
184
|
+
#{ $prefix }--animation-move,
|
|
185
|
+
#{ $prefix }--animation-enter-active,
|
|
186
|
+
#{ $prefix }--animation-leave-active {
|
|
187
|
+
transition: all 0.3s ease;
|
|
188
|
+
}
|
|
189
|
+
#{ $prefix }--animation-enter-from,
|
|
190
|
+
#{ $prefix }--animation-leave-to {
|
|
191
|
+
opacity: 0;
|
|
192
|
+
transform: translateX(30px);
|
|
193
|
+
}
|
|
194
|
+
#{ $prefix }--animation-leave-active {
|
|
195
|
+
position: absolute;
|
|
196
|
+
width: 100%;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { markRaw } from "vue";
|
|
2
|
+
import ToastComponent from "./UluToast.vue";
|
|
3
|
+
/**
|
|
4
|
+
* Default plugin options
|
|
5
|
+
*/
|
|
6
|
+
export default {
|
|
7
|
+
toastOptions: {
|
|
8
|
+
/**
|
|
9
|
+
* Component used to render the toast in the display
|
|
10
|
+
*/
|
|
11
|
+
component: markRaw(ToastComponent),
|
|
12
|
+
/**
|
|
13
|
+
* Duration of toast
|
|
14
|
+
*/
|
|
15
|
+
duration: 6000, // 8.5s
|
|
16
|
+
/**
|
|
17
|
+
* Array of actions { label, click }
|
|
18
|
+
*/
|
|
19
|
+
actions: [],
|
|
20
|
+
},
|
|
21
|
+
pluginOptions: {
|
|
22
|
+
componentName: "UluToast",
|
|
23
|
+
componentNameDisplay: "UluToastDisplay",
|
|
24
|
+
teleportTo: "body",
|
|
25
|
+
/**
|
|
26
|
+
* Position of the toast container (holds toasts)
|
|
27
|
+
*/
|
|
28
|
+
position: ["top", "right"],
|
|
29
|
+
}
|
|
30
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { store, api } from "./store.js";
|
|
2
|
+
import UluToast from "./UluToast.vue";
|
|
3
|
+
import UluToastDisplay from "./UluToastDisplay.vue";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Install plugin
|
|
7
|
+
*/
|
|
8
|
+
export default function install(app, userOptions = {}) {
|
|
9
|
+
const options = store.setPluginOptions(userOptions?.plugin);
|
|
10
|
+
store.setToastOptions(userOptions?.toast);
|
|
11
|
+
|
|
12
|
+
app.component(options.componentName, UluToast);
|
|
13
|
+
app.component(options.componentNameDisplay, UluToastDisplay);
|
|
14
|
+
|
|
15
|
+
app.config.globalProperties.$uluToast = api;
|
|
16
|
+
app.provide('uluToast', api);
|
|
17
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { reactive } from "vue";
|
|
2
|
+
import defaults from "./defaults.js";
|
|
3
|
+
|
|
4
|
+
const { assign: merge } = Object;
|
|
5
|
+
let counter = 0;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Reactive State Object (used inside global components, and as API globally)
|
|
9
|
+
*/
|
|
10
|
+
export const store = reactive({
|
|
11
|
+
toasts: [],
|
|
12
|
+
/**
|
|
13
|
+
* Saveable
|
|
14
|
+
*/
|
|
15
|
+
pluginOptions: defaults.pluginOptions,
|
|
16
|
+
toastOptions: defaults.toastOptions,
|
|
17
|
+
setToastOptions(options) {
|
|
18
|
+
this.toastOptions = merge({}, this.toastOptions, options);
|
|
19
|
+
return this.pluginOptions;
|
|
20
|
+
},
|
|
21
|
+
setPluginOptions(options) {
|
|
22
|
+
this.pluginOptions = merge({}, this.pluginOptions, options);
|
|
23
|
+
return this.pluginOptions;
|
|
24
|
+
},
|
|
25
|
+
createToast(options) {
|
|
26
|
+
const uid = `toast-${ ++counter }`;
|
|
27
|
+
return merge({}, this.toastOptions, options, {
|
|
28
|
+
uid,
|
|
29
|
+
close() {
|
|
30
|
+
api.remove(uid);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Public API
|
|
38
|
+
*/
|
|
39
|
+
export const api = {
|
|
40
|
+
/**
|
|
41
|
+
*
|
|
42
|
+
* @param {Object} options Toast options
|
|
43
|
+
* @returns Toast object (to be used to remove)
|
|
44
|
+
*/
|
|
45
|
+
add(options) {
|
|
46
|
+
const toast = store.createToast(options);
|
|
47
|
+
store.toasts.unshift(toast);
|
|
48
|
+
if (toast.duration) {
|
|
49
|
+
setTimeout(() => {
|
|
50
|
+
this.remove(toast.uid);
|
|
51
|
+
}, toast.duration);
|
|
52
|
+
}
|
|
53
|
+
return toast;
|
|
54
|
+
},
|
|
55
|
+
/**
|
|
56
|
+
*
|
|
57
|
+
* @param {Object} toast Toast uid
|
|
58
|
+
*/
|
|
59
|
+
remove(uid) {
|
|
60
|
+
const index = store.toasts.findIndex(t => t.uid === uid);
|
|
61
|
+
if (index > -1) {
|
|
62
|
+
store.toasts.splice(index, 1);
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
/**
|
|
66
|
+
* Remove all toasts
|
|
67
|
+
*/
|
|
68
|
+
removeAll() {
|
|
69
|
+
store.toasts = [];
|
|
70
|
+
},
|
|
71
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { inject } from 'vue';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Composable for accessing the toast API.
|
|
5
|
+
* @returns {object} The toast API.
|
|
6
|
+
* @throws {Error} If the toast plugin is not installed.
|
|
7
|
+
* @example
|
|
8
|
+
* import { useToast } from './useToast';
|
|
9
|
+
* const toast = useToast();
|
|
10
|
+
* toast.add({ title: 'Hello World' });
|
|
11
|
+
*/
|
|
12
|
+
export const useToast = () => {
|
|
13
|
+
const toast = inject('uluToast');
|
|
14
|
+
if (!toast) {
|
|
15
|
+
throw new Error('Toast plugin not installed');
|
|
16
|
+
}
|
|
17
|
+
return toast;
|
|
18
|
+
};
|