Created
June 11, 2021 05:07
-
-
Save Neophen/877f8662cfe46f39cfb6f6393a6fff4a to your computer and use it in GitHub Desktop.
Vue.js Snippets - useDialog
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<div class="flex items-center justify-center bg-gray-100 h-screen"> | |
<DialogsDemo /> | |
</div> | |
<Dialogs :state="dialogState" /> <!-- This is important --> | |
</template> | |
<script> | |
import { provideDialogs } from "./composables/useDialog.js"; // This is important | |
import DialogsDemo from "./components/Dialogs/DialogsDemo.vue"; | |
import Dialogs from "./components/Dialogs/Dialogs.vue"; | |
export default { | |
components: { | |
DialogsDemo, | |
Dialogs, | |
}, | |
setup() { | |
const dialogState = provideDialogs(); // This is important | |
return { | |
dialogState, // This is important | |
}; | |
}, | |
}; | |
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<div | |
v-if="dialogIsShowing" | |
class=" | |
fixed | |
inset-0 | |
h-screen | |
w-screen | |
z-10 | |
flex | |
justify-center | |
items-center | |
bg-black bg-opacity-50 | |
" | |
@click="onResolve(false)" | |
> | |
<div @click.stop> | |
<div class="p-8 bg-white rounded shadow-lg w-96"> | |
<h1 class="text-4xl">{{ dialog.titleText }}</h1> | |
<p class="text-gray-500 mt-4">{{ dialog.messageText }}</p> | |
<div class="flex items-center justify-between mt-8"> | |
<button | |
@click="onResolve(false)" | |
:disabled="dialog.isLoading" | |
type="button" | |
class="px-4 py-2 bg-white" | |
> | |
{{ dialog.cancelText }} | |
</button> | |
<button | |
@click="onResolve(true)" | |
:disabled="dialog.isLoading" | |
type="button" | |
class="px-4 py-2 bg-indigo-500 text-white" | |
> | |
{{ dialog.isLoading ? "Loading..." : dialog.confirmText }} | |
</button> | |
</div> | |
</div> | |
</div> | |
</div> | |
</template> | |
<script> | |
export default { | |
name: "Dialogs", | |
props: { | |
state: { // This is important | |
type: Object, | |
required: true, | |
}, | |
}, | |
setup(props) { | |
// This component can be whatever you want! | |
return props.state; // This is important | |
}, | |
}; | |
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<div | |
class=" | |
rounded-xl | |
shadow-md | |
bg-white | |
flex flex-col | |
items-center | |
w-80 | |
p-8 | |
space-y-4 | |
" | |
> | |
<h1 class="text-4xl font-bold">useDialog</h1> | |
<p>Result: {{ result }}</p> | |
<button | |
@click="onShow" | |
type="button" | |
class=" | |
rounded | |
px-4 | |
py-2 | |
text-white | |
font-bold | |
bg-blue-500 | |
hover:bg-blue-600 | |
shadow | |
" | |
> | |
await | |
</button> | |
</div> | |
</template> | |
<script> | |
import { ref } from "vue"; | |
import { Dialog, useDialogs } from "../../composables/useDialog"; | |
export default { | |
name: "DialogsDemo", | |
setup() { | |
const sleep = (milliseconds) => { | |
return new Promise((resolve) => setTimeout(resolve, milliseconds)); | |
}; | |
const result = ref(null); | |
const showDialog = useDialogs(); | |
const sayHelloDialog = Dialog.info() | |
.title("Hello") | |
.message("Is this not awesome") | |
.confirm("Well hello to you to!") | |
.cancel("Speak to the hand") | |
.onConfirm(async () => { | |
await sleep(2000); | |
result.value = "Confirmed"; | |
}) | |
.onCancel(() => { | |
result.value = "Cancelled"; | |
}); | |
const onShow = () => { | |
showDialog(sayHelloDialog); | |
}; | |
return { | |
result, | |
onShow, | |
}; | |
}, | |
}; | |
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { inject, provide, reactive, toRefs } from "vue"; | |
/** | |
* @typedef DialogsState | |
* @type {object} | |
* @property {Dialog} dialog - the current dialog | |
* @property {bool} dialogIsShowing - is the dialog showing | |
*/ | |
const DIALOG_SYMBOL = Symbol("DIALOG_SYMBOL"); | |
export const provideDialogs = () => { | |
/** | |
* @type {DialogsState} | |
*/ | |
const state = reactive({ | |
dialog: null, | |
dialogIsShowing: false, | |
}); | |
/** | |
* @param {Dialog} dialog | |
*/ | |
const showDialog = (dialog) => { | |
state.dialog = dialog.__onClose(() => { | |
state.dialogIsShowing = false; | |
}); | |
state.dialogIsShowing = true; | |
}; | |
const onResolve = (result) => { | |
state.dialog.onResolve(result); | |
}; | |
provide(DIALOG_SYMBOL, showDialog); | |
return { ...toRefs(state), onResolve }; | |
}; | |
export const useDialogs = () => inject(DIALOG_SYMBOL); | |
// Make your own types, to use with your components | |
const DIALOG_TYPE = { | |
DANGER: "DANGER", | |
INFO: "INFO", | |
}; | |
export class Dialog { | |
__titleText = ""; | |
__messageText = null; | |
__cancelText = "Cancel"; | |
__confirmText = "Confirm"; | |
__isLoading = false; | |
__onConfirmCallback = () => {}; | |
__onCancelCallback = () => {}; | |
__onCloseCallback = () => {}; | |
static danger(title = "", message = "") { | |
return new Dialog(DIALOG_TYPE.DANGER).title(title).message(message); | |
} | |
static info(title = "", message = "") { | |
return new Dialog(DIALOG_TYPE.INFO).title(title).message(message); | |
} | |
/** | |
* @param {DIALOG_TYPE} type | |
*/ | |
constructor(type) { | |
this.__type = type; | |
} | |
/** | |
* @return {string} | |
*/ | |
get type() { | |
return this.__type; | |
} | |
/** | |
* @return {boolean} | |
*/ | |
get isLoading() { | |
return this.__isLoading; | |
} | |
/** | |
* @param {string} text | |
* @returns Dialog | |
*/ | |
title(text) { | |
this.__titleText = text; | |
return this; | |
} | |
/** | |
* @return {string} | |
*/ | |
get titleText() { | |
return this.__titleText; | |
} | |
/** | |
* @param {string} text | |
*/ | |
message(text) { | |
this.__messageText = text; | |
return this; | |
} | |
/** | |
* @return {string} | |
*/ | |
get messageText() { | |
return this.__messageText; | |
} | |
/** | |
* @param {string} text | |
*/ | |
cancel(text) { | |
this.__cancelText = text; | |
return this; | |
} | |
/** | |
* @return {string} | |
*/ | |
get cancelText() { | |
return this.__cancelText; | |
} | |
/** | |
* @param {string} text | |
*/ | |
confirm(text) { | |
this.__confirmText = text; | |
return this; | |
} | |
/** | |
* @return {string} | |
*/ | |
get confirmText() { | |
return this.__confirmText; | |
} | |
/** | |
* @param {Function} callback | |
*/ | |
onConfirm(callback) { | |
this.__onConfirmCallback = callback; | |
return this; | |
} | |
/** | |
* @param {Function} callback | |
*/ | |
onCancel(callback) { | |
this.__onCancelCallback = callback; | |
return this; | |
} | |
/** | |
* @param {Function} callback | |
*/ | |
__onClose(callback) { | |
this.__onCloseCallback = callback; | |
return this; | |
} | |
async onResolve(result) { | |
if (result === false) { | |
try { | |
this.__isLoading = true; | |
await this.__onCancelCallback(result); | |
} catch (error) { | |
throw error; | |
} finally { | |
this.__isLoading = false; | |
this.__onCloseCallback(); | |
} | |
return; | |
} | |
try { | |
this.__isLoading = true; | |
await this.__onConfirmCallback(result); | |
} catch (error) { | |
throw error; | |
} finally { | |
this.__isLoading = false; | |
this.__onCloseCallback(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment