diff --git a/src/components/ActionPanel/ActionPanel.stories.js b/src/components/ActionPanel/ActionPanel.stories.js index 887cc67ca..ec02c6f6b 100644 --- a/src/components/ActionPanel/ActionPanel.stories.js +++ b/src/components/ActionPanel/ActionPanel.stories.js @@ -35,6 +35,7 @@ export const Default = { callback: (close) => close(), }, ], + modalStyle: 'negative', }); } return { diff --git a/src/components/Composer/Composer.vue b/src/components/Composer/Composer.vue index 0c740dbae..87abe7085 100644 --- a/src/components/Composer/Composer.vue +++ b/src/components/Composer/Composer.vue @@ -906,6 +906,7 @@ export default { callback: (close) => close(), }, ], + modalStyle: 'primary', }); }, diff --git a/src/components/Container/DecisionPage.vue b/src/components/Container/DecisionPage.vue index be9b2c579..2a3f9ee7e 100644 --- a/src/components/Container/DecisionPage.vue +++ b/src/components/Container/DecisionPage.vue @@ -182,6 +182,7 @@ export default { callback: (close) => close(), }, ], + modalStyle: 'negative', }); }, @@ -266,6 +267,7 @@ export default { message: this.decisionCompleteDescription, actions, close, + modalStyle: 'success', }); }, diff --git a/src/components/Container/ManageEmailsPage.vue b/src/components/Container/ManageEmailsPage.vue index d685a9b1b..86cdfb11e 100644 --- a/src/components/Container/ManageEmailsPage.vue +++ b/src/components/Container/ManageEmailsPage.vue @@ -151,6 +151,7 @@ export default { callback: (close) => close(), }, ], + modalStyle: 'negative', }); }, @@ -187,6 +188,7 @@ export default { callback: (close) => close(), }, ], + modalStyle: 'negative', }); }, @@ -224,6 +226,7 @@ export default { callback: (close) => close(), }, ], + modalStyle: 'negative', }); }, @@ -325,7 +328,7 @@ export default { title: mailable ? mailable.name : '', mailable: this.currentMailable, onOpenTemplate: this.openTemplate, - onConfirmResetTemplate: this.confirmRemoveTemplate, + onConfirmResetTemplate: this.confirmResetTemplate, onConfirmRemoveTemplate: this.confirmRemoveTemplate, }); }); diff --git a/src/components/Container/SubmissionWizardPage.vue b/src/components/Container/SubmissionWizardPage.vue index cc49e8a61..d9fbc8bc3 100644 --- a/src/components/Container/SubmissionWizardPage.vue +++ b/src/components/Container/SubmissionWizardPage.vue @@ -432,6 +432,7 @@ export default { callback: (close) => close(), }, ], + modalStyle: 'negative', }); }, @@ -661,6 +662,7 @@ export default { callback: (close) => close(), }, ], + modalStyle: 'primary', }); }, diff --git a/src/components/Container/WorkflowPage.vue b/src/components/Container/WorkflowPage.vue index 965a02a7a..89053b37b 100644 --- a/src/components/Container/WorkflowPage.vue +++ b/src/components/Container/WorkflowPage.vue @@ -352,6 +352,7 @@ export default { callback: (close) => close(), }, ], + modalStyle: 'primary', }); }, diff --git a/src/components/Form/context/NotifyUsersForm.vue b/src/components/Form/context/NotifyUsersForm.vue index c7b6d7adb..5cf6a10a8 100644 --- a/src/components/Form/context/NotifyUsersForm.vue +++ b/src/components/Form/context/NotifyUsersForm.vue @@ -53,6 +53,7 @@ export default { callback: (close) => close(), }, ], + modalStyle: 'primary', }); }, }, diff --git a/src/components/Form/fields/FieldShowEnsuringLink.vue b/src/components/Form/fields/FieldShowEnsuringLink.vue index 078da1856..92f7acd4e 100644 --- a/src/components/Form/fields/FieldShowEnsuringLink.vue +++ b/src/components/Form/fields/FieldShowEnsuringLink.vue @@ -23,7 +23,7 @@ export default { }, mounted() { /** - * Show the requested message in a modal when the link in the messgae is + * Show the requested message in a modal when the link in the message is * clicked. */ $('.pkpFormField--options__option button', this.$el).click(() => { @@ -36,6 +36,7 @@ export default { callback: (close) => { close(); }, + modalStyle: 'primary', }, { height: 'auto', diff --git a/src/components/ListPanel/announcements/AnnouncementsListPanel.vue b/src/components/ListPanel/announcements/AnnouncementsListPanel.vue index 916245723..e4f9ef03c 100644 --- a/src/components/ListPanel/announcements/AnnouncementsListPanel.vue +++ b/src/components/ListPanel/announcements/AnnouncementsListPanel.vue @@ -209,7 +209,7 @@ export default { actions: [ { label: this.t('common.yes'), - isPrimary: true, + isWarnable: true, callback: (close) => { var self = this; $.ajax({ @@ -233,10 +233,10 @@ export default { }, { label: this.t('common.no'), - isWarnable: true, callback: (close) => close(), }, ], + modalStyle: 'negative', }); }, diff --git a/src/components/ListPanel/contributors/ContributorsListPanel.vue b/src/components/ListPanel/contributors/ContributorsListPanel.vue index 6ac8992b1..c665bdaa6 100644 --- a/src/components/ListPanel/contributors/ContributorsListPanel.vue +++ b/src/components/ListPanel/contributors/ContributorsListPanel.vue @@ -359,6 +359,7 @@ export default { callback: (close) => close(), }, ], + modalStyle: 'negative', }); }, diff --git a/src/components/ListPanel/doi/DoiListPanel.vue b/src/components/ListPanel/doi/DoiListPanel.vue index cdc06db7a..65609012d 100644 --- a/src/components/ListPanel/doi/DoiListPanel.vue +++ b/src/components/ListPanel/doi/DoiListPanel.vue @@ -789,6 +789,7 @@ export default { callback: (close) => close(), }, ], + modalStyle: 'primary', }); }, /** diff --git a/src/components/ListPanel/highlights/HighlightsListPanel.vue b/src/components/ListPanel/highlights/HighlightsListPanel.vue index f245415c1..a8257c884 100644 --- a/src/components/ListPanel/highlights/HighlightsListPanel.vue +++ b/src/components/ListPanel/highlights/HighlightsListPanel.vue @@ -228,7 +228,7 @@ export default { actions: [ { label: this.t('common.yes'), - isPrimary: true, + isWarnable: true, callback: (close) => { $.ajax({ url: this.apiUrl + '/' + id, @@ -251,10 +251,10 @@ export default { }, { label: this.t('common.no'), - isWarnable: true, callback: (close) => close(), }, ], + modalStyle: 'negative', }); }, diff --git a/src/components/ListPanel/institutions/InstitutionsListPanel.vue b/src/components/ListPanel/institutions/InstitutionsListPanel.vue index 59240f1ca..33e19e4fc 100644 --- a/src/components/ListPanel/institutions/InstitutionsListPanel.vue +++ b/src/components/ListPanel/institutions/InstitutionsListPanel.vue @@ -211,7 +211,7 @@ export default { actions: [ { label: this.t('common.yes'), - isPrimary: true, + isWarnable: true, callback: (close) => { var self = this; $.ajax({ @@ -235,10 +235,10 @@ export default { }, { label: this.t('common.no'), - isWarnable: true, callback: (close) => close(), }, ], + modalStyle: 'negative', }); }, diff --git a/src/components/ListPanel/submissionFiles/SubmissionFilesListPanel.vue b/src/components/ListPanel/submissionFiles/SubmissionFilesListPanel.vue index 229f16639..897c46d49 100644 --- a/src/components/ListPanel/submissionFiles/SubmissionFilesListPanel.vue +++ b/src/components/ListPanel/submissionFiles/SubmissionFilesListPanel.vue @@ -259,7 +259,7 @@ export default { actions: [ { label: this.t('common.yes'), - isPrimary: true, + isWarnable: true, callback: (close) => { $.ajax({ url: this.apiUrl + '/' + item.id + '?stageId=' + this.stageId, @@ -281,10 +281,10 @@ export default { }, { label: this.t('common.no'), - isWarnable: true, callback: (close) => close(), }, ], + modalStyle: 'negative', }); }, diff --git a/src/components/ListPanel/submissions/SubmissionsListItem.vue b/src/components/ListPanel/submissions/SubmissionsListItem.vue index 84fb6e968..e66332bf6 100644 --- a/src/components/ListPanel/submissions/SubmissionsListItem.vue +++ b/src/components/ListPanel/submissions/SubmissionsListItem.vue @@ -813,15 +813,15 @@ export default { actions: [ { label: this.t('common.yes'), - isPrimary: true, + isWarnable: true, callback: this.deleteSubmission, }, { label: this.t('common.no'), - isWarnable: true, callback: (close) => close(), }, ], + modalStyle: 'negative', }); }, diff --git a/src/components/Modal/Dialog.mdx b/src/components/Modal/Dialog.mdx index 3e298eae3..e3fb1f1f5 100644 --- a/src/components/Modal/Dialog.mdx +++ b/src/components/Modal/Dialog.mdx @@ -19,6 +19,15 @@ Dialog purpose is to display simple feedback like success and error messages. Or Dialog are opened via method `openDialog` from [useModal](../?path=/docs/composables-usemodal--docs#opensidemodal) composable. Check out the props description for details. +## Styling + +The style of the modal can be changed by passing the prop `modalStyle`. It accepts the following values: + +- **`default`**: The standard modal style, which has no special border styling. This serves as the default value for the modal style. +- **`primary`**: A modal style that uses the primary color scheme. +- **`negative`**: Indicates a negative state, typically for error messages or alerts. +- **`success`**: Represents a positive state, often used for success notifications. + ## Accessibility To correctly handle accessibility (title, description) and focus management - [headless-ui](https://headlessui.com) library is used. diff --git a/src/components/Modal/Dialog.stories.js b/src/components/Modal/Dialog.stories.js index 25b577c15..f594966c1 100644 --- a/src/components/Modal/Dialog.stories.js +++ b/src/components/Modal/Dialog.stories.js @@ -100,6 +100,50 @@ export const WithBodyComponent = { }, }; +export const NonDismissible = { + args: { + buttonName: 'Show non-dismissible modal', + name: 'non-dismissible-modal', + title: 'Non-Dismissible Modal', + message: + 'Clicking outside will not close this modal. Use the "Cancel" button to close it.', + actions: [ + { + label: 'Cancel', + callback: (close) => close(), + }, + ], + isDismissible: false, + close: () => console.log('closed example dialog'), // eslint-disable-line, + }, + play: async ({canvasElement}) => { + // Assigns canvas to the component root element + const canvas = within(canvasElement); + const user = userEvent.setup(); + + await user.click(canvas.getByText('Show non-dismissible modal')); + }, +}; + +export const NoActionButtons = { + args: { + buttonName: 'Show modal', + name: 'no-actions-modal', + title: 'Non Action Buttons Modal', + message: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', + actions: [], + close: () => console.log('closed example dialog'), // eslint-disable-line, + }, + play: async ({canvasElement}) => { + // Assigns canvas to the component root element + const canvas = within(canvasElement); + const user = userEvent.setup(); + + await user.click(canvas.getByText('Show modal')); + }, +}; + export const DialogComplex = { args: { buttonName: 'Full Example', @@ -138,3 +182,108 @@ export const DialogComplex = { await user.click(canvas.getByText('Full Example')); }, }; + +const ErrorBodyComponent = { + template: ` + Cancelling the invitation sent to Emma Stone will deactivate the acceptance link sent to her via email. Here are the invitation details: + + `, + props: { + failedDoiActions: {type: Array, required: true}, + }, +}; + +export const NegativeState = { + args: { + buttonName: 'Show modal', + name: 'error', + title: 'Cancel Invitation', + bodyComponent: ErrorBodyComponent, + actions: [ + { + label: 'Cancel Invitation', + isPrimary: true, + callback: (close) => { + // Simulate a server request + setTimeout(() => close(), 2000); + }, + }, + { + label: 'Cancel', + isWarnable: true, + callback: (close) => close(), + }, + ], + close: () => console.log('closed example dialog'), // eslint-disable-line, + modalStyle: 'negative', + }, + play: async ({canvasElement}) => { + // Assigns canvas to the component root element + const canvas = within(canvasElement); + const user = userEvent.setup(); + + await user.click(canvas.getByText('Show modal')); + }, +}; + +export const SuccessState = { + args: { + buttonName: 'Show modal', + name: 'error', + title: "You've been added as a section editor in OJS", + message: + 'Congratulations! As a section editor you might get access to more options in OJS. If you need any assistance in understanding the system, please click on "Help" buttons throughout the system to guide you through the interface.', + actions: [ + { + label: 'View All Submissions', + callback: (close) => close(), + }, + ], + close: () => console.log('closed example dialog'), // eslint-disable-line, + modalStyle: 'success', + }, + play: async ({canvasElement}) => { + // Assigns canvas to the component root element + const canvas = within(canvasElement); + const user = userEvent.setup(); + + await user.click(canvas.getByText('Show modal')); + }, +}; + +export const PrimaryStyle = { + args: { + buttonName: 'Show modal', + name: 'primary', + title: 'Primary Color', + message: "This dialog uses the application's primary color.", + actions: [ + { + label: 'Ok', + callback: (close) => close(), + }, + ], + close: () => console.log('closed example dialog'), // eslint-disable-line, + modalStyle: 'primary', + }, + play: async ({canvasElement}) => { + // Assigns canvas to the component root element + const canvas = within(canvasElement); + const user = userEvent.setup(); + + await user.click(canvas.getByText('Show modal')); + }, +}; diff --git a/src/components/Modal/Dialog.vue b/src/components/Modal/Dialog.vue index face7c085..010871027 100644 --- a/src/components/Modal/Dialog.vue +++ b/src/components/Modal/Dialog.vue @@ -1,6 +1,6 @@