Skip to content

Commit

Permalink
Update src/components/NcDialogButton/NcDialogButton.vue
Browse files Browse the repository at this point in the history
Co-authored-by: Grigorii K. Shartsev <[email protected]>
Signed-off-by: Ferdinand Thiessen <[email protected]>
  • Loading branch information
susnux and ShGKme committed Aug 30, 2024
1 parent 3fbf2d8 commit ef493ec
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 108 deletions.
54 changes: 36 additions & 18 deletions src/components/NcDialog/NcDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ Sometimes a dialog ends with a request and this request might fail due to server
In this case it is often desired to keep the dialog open, this can be done by returning `false` from the button callback,
to not block this callback should return a `Promise<false>`.

It is also possible to get the result of the callback from the dialog, as the result is passed as the payload of the `closing` event.

While the promise is awaited the button will have a loading state,
this means, as long as no custom `icon`-slot is used, a loading icon will be shown.
Please note that the **button will not be disabled or accessibility reasons**,
Expand All @@ -141,12 +143,14 @@ because disabled elements cannot be focused and so the loading state could not b
```vue
<template>
<div>
<NcButton @click="showDialog = true">Show dialog</NcButton>
<NcButton @click="openDialog">Show dialog</NcButton>
<NcDialog :buttons="buttons"
name="Create user"
:message="message"
:open.sync="showDialog"
@closing="response = $event"
@update:open="clickClosesDialog = false" />
<div style="margin-top: 8px;">Dialog response: {{ response }}</div>
</div>
</template>
<script>
Expand All @@ -155,26 +159,37 @@ export default {
return {
showDialog: false,
clickClosesDialog: false,
response: 'none',
}
},
methods: {
async callback() {
// wait 3 seconds
await new Promise((resolve) => window.setTimeout(resolve, 3000))
this.clickClosesDialog = !this.clickClosesDialog
console.warn(this.clickClosesDialog)
// Do not close the dialog on first and then every second button click
if (this.clickClosesDialog) {
// return false means the dialog stays open
return false
}
return ''
},
openDialog() {
this.response = 'none'
this.showDialog = true
},
},
computed: {
buttons() {
return [
{
label: 'Create user',
type: 'primary',
callback: async () => {
// wait 3 seconds
await new Promise((resolve) => window.setTimeout(resolve, 3000))
this.clickClosesDialog = !this.clickClosesDialog
console.warn(this.clickClosesDialog)
// Do not close the dialog on first and then every second button click
if (this.clickClosesDialog) {
// return false means the dialog stays open
return false
}
},
callback: this.callback,
}
]
},
Expand All @@ -198,7 +213,7 @@ export default {
:enable-swipe="false"
v-bind="modalProps"
@close="handleClosed"
@update:show="handleClosing">
@update:show="handleClosing()">
<!-- The dialog name / header -->
<h2 :id="navigationId" class="dialog__name" v-text="name" />
<component :is="dialogTagName"
Expand Down Expand Up @@ -507,25 +522,28 @@ export default defineComponent({
// Because NcModal does not emit `close` when show prop is changed
/**
* Handle clicking a dialog button -> should close
* @param {MouseEvent} event The click event
* @param {unknown} result Result of the callback function
*/
const handleButtonClose = () => {
const handleButtonClose = (event, result) => {
// Skip close if invalid dialog
if (dialogTagName.value === 'form' && !dialogElement.value.reportValidity()) {
return
}
handleClosing()
handleClosing(result)
window.setTimeout(() => handleClosed(), 300)
}
/**

Check warning on line 537 in src/components/NcDialog/NcDialog.vue

View workflow job for this annotation

GitHub Actions / NPM lint

Missing JSDoc @param "result" declaration
* Handle closing the dialog, optional out transition did not run yet
*/
const handleClosing = () => {
const handleClosing = (result) => {
showModal.value = false
/**
* Emitted when the dialog is closing, so the out transition did not finish yet
* Emitted when the dialog is closing, so the out transition did not finish yet.
* @param result The result of the button callback (`undefined` if closing because of clicking the 'close'-button)
*/
emit('closing')
emit('closing', result)
}
/**
Expand Down
170 changes: 80 additions & 90 deletions src/components/NcDialogButton/NcDialogButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,110 +25,100 @@ Dialog button component used by NcDialog in the actions slot to display the butt
</NcButton>
</template>

<script>
import { defineComponent, ref } from 'vue'
<script setup>
import { ref } from 'vue'
import NcButton from '../NcButton/index.js'
import NcIconSvgWrapper from '../NcIconSvgWrapper/index.js'
import NcLoadingIcon from '../NcLoadingIcon/index.js'
import { t } from '../../l10n.js'
export default defineComponent({
name: 'NcDialogButton',

Check failure on line 35 in src/components/NcDialogButton/NcDialogButton.vue

View workflow job for this annotation

GitHub Actions / NPM lint

More than 1 blank line not allowed
components: {
NcButton,
NcIconSvgWrapper,
NcLoadingIcon,
const props = defineProps({
/**
* The function that will be called when the button is pressed.
* If the function returns `false` the click is ignored and the dialog will not be closed.
* @type {() => unknown|false|Promise<unknown|false>}
*/
callback: {
type: Function,
required: false,
default: () => {},
},
props: {
/**
* The function that will be called when the button is pressed.
* If the function returns `false` the click is ignored and the dialog will not be closed.
* @type {() => void|false|Promise<void|false>}
*/
callback: {
type: Function,
required: false,
default: () => {},
},
/**
* The label of the button
*/
label: {
type: String,
required: true,
},
/**
* Optional inline SVG icon for the button
*/
icon: {
type: String,
required: false,
default: undefined,
},
/**
* The label of the button
*/
label: {
type: String,
required: true,
},
/**
* The button type, see NcButton
* @type {'primary'|'secondary'|'error'|'warning'|'success'}
*/
type: {
type: String,
required: false,
default: 'secondary',
validator: (type) => typeof type === 'string' && ['primary', 'secondary', 'tertiary', 'error', 'warning', 'success'].includes(type),
},
/**
* Optional inline SVG icon for the button
*/
icon: {
type: String,
required: false,
default: undefined,
},
/**
* See `nativeType` of `NcButton`
*/
nativeType: {
type: String,
required: false,
default: 'button',
validator(value) {
return ['submit', 'reset', 'button'].includes(value)
},
},
/**
* The button type, see NcButton
* @type {'primary'|'secondary'|'error'|'warning'|'success'}
*/
type: {
type: String,
required: false,
default: 'secondary',
validator: (type) => typeof type === 'string' && ['primary', 'secondary', 'tertiary', 'error', 'warning', 'success'].includes(type),
},
/**
* If the button should be shown as disabled
*/
disabled: {
type: Boolean,
default: false,
/**
* See `nativeType` of `NcButton`
*/
nativeType: {
type: String,
required: false,
default: 'button',
validator(value) {
return ['submit', 'reset', 'button'].includes(value)
},
},
emits: ['click'],
setup(props, { emit }) {
const isLoading = ref(false)
/**
* Handle clicking the button
* @param {MouseEvent} e The click event
*/
const handleClick = async (e) => {
// Do not re-emit while loading
if (isLoading.value) {
return
}
isLoading.value = true
try {
const response = await props.callback?.()
if (response !== false) {
emit('click', e)
}
} finally {
isLoading.value = false
}
}
return { handleClick, isLoading, t }
/**
* If the button should be shown as disabled
*/
disabled: {
type: Boolean,
default: false,
},
})
const emit = defineEmits(['click'])
const isLoading = ref(false)
/**
* Handle clicking the button
* @param {MouseEvent} e The click event
*/
const handleClick = async (e) => {
// Do not re-emit while loading
if (isLoading.value) {
return
}
isLoading.value = true
try {
const result = await props.callback?.()
if (result !== false) {
/**
* The click event (`MouseEvent`) and the value returned by the callback
*/
emit('click', e, result)
}
} finally {
isLoading.value = false
}
}
</script>

0 comments on commit ef493ec

Please sign in to comment.