You've already forked focalboard
mirror of
https://github.com/mattermost/focalboard.git
synced 2025-07-15 23:54:29 +02:00
[GH-1278] Confirm delete when deleting board (#1339)
* Delete board confirmation modal (#1278) * dialog should fill the screen on small resolution * Updating delete board confirm UI * Pass onClose callback to Dialog props * lint * removing danger-button-bg-rgb from shared variables, adjusting dialog styles to work both in plugin and standalone version of focalboard * lint * remove set timeout * Update button.scss * update snpashot Co-authored-by: Asaad Mahmood <asaadmahmood@users.noreply.github.com> Co-authored-by: Hossein Ahmadian-Yazdi <hyazdi1997@gmail.com> Co-authored-by: Harshil Sharma <harshilsharma63@gmail.com>
This commit is contained in:
@ -117,6 +117,8 @@ describe('Create and delete board / card', () => {
|
|||||||
|
|
||||||
cy.contains('Delete board').click({force: true});
|
cy.contains('Delete board').click({force: true});
|
||||||
|
|
||||||
|
cy.get('.DeleteBoardDialog button.danger').click({force: true});
|
||||||
|
|
||||||
// Board should not exist
|
// Board should not exist
|
||||||
cy.contains(boardTitle).should('not.exist');
|
cy.contains(boardTitle).should('not.exist');
|
||||||
});
|
});
|
||||||
|
@ -47,6 +47,10 @@
|
|||||||
"DashboardPage.CenterPanel.NoWorkspacesDescription": "Please try searching for another term",
|
"DashboardPage.CenterPanel.NoWorkspacesDescription": "Please try searching for another term",
|
||||||
"DashboardPage.showEmpty": "Show empty",
|
"DashboardPage.showEmpty": "Show empty",
|
||||||
"DashboardPage.title": "Dashboard",
|
"DashboardPage.title": "Dashboard",
|
||||||
|
"DeleteBoardDialog.confirm-cancel": "Cancel",
|
||||||
|
"DeleteBoardDialog.confirm-delete": "Delete",
|
||||||
|
"DeleteBoardDialog.confirm-info": "Are you sure you want to delete the board “{boardTitle}”? Deleting it will delete the property from all cards in this board.",
|
||||||
|
"DeleteBoardDialog.confirm-tite": "Confirm Delete Board",
|
||||||
"Dialog.closeDialog": "Close dialog",
|
"Dialog.closeDialog": "Close dialog",
|
||||||
"EditableDayPicker.today": "Today",
|
"EditableDayPicker.today": "Today",
|
||||||
"EmptyCenterPanel.no-content": "Add or select a board from the sidebar to get started.",
|
"EmptyCenterPanel.no-content": "Add or select a board from the sidebar to get started.",
|
||||||
|
@ -24,9 +24,6 @@ exports[`components/cardDialog return a cardDialog readonly 1`] = `
|
|||||||
class="CompassIcon icon-close CloseIcon"
|
class="CompassIcon icon-close CloseIcon"
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
<div
|
|
||||||
class="octo-spacer"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="CardDetail content"
|
class="CardDetail content"
|
||||||
@ -123,9 +120,6 @@ exports[`components/cardDialog return cardDialog menu content 1`] = `
|
|||||||
class="CompassIcon icon-close CloseIcon"
|
class="CompassIcon icon-close CloseIcon"
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
<div
|
|
||||||
class="octo-spacer"
|
|
||||||
/>
|
|
||||||
<div
|
<div
|
||||||
aria-label="menuwrapper"
|
aria-label="menuwrapper"
|
||||||
class="MenuWrapper"
|
class="MenuWrapper"
|
||||||
@ -628,9 +622,6 @@ exports[`components/cardDialog should match snapshot 1`] = `
|
|||||||
class="CompassIcon icon-close CloseIcon"
|
class="CompassIcon icon-close CloseIcon"
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
<div
|
|
||||||
class="octo-spacer"
|
|
||||||
/>
|
|
||||||
<div
|
<div
|
||||||
aria-label="menuwrapper"
|
aria-label="menuwrapper"
|
||||||
class="MenuWrapper"
|
class="MenuWrapper"
|
||||||
|
@ -64,6 +64,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
> .content {
|
> .content {
|
||||||
|
@ -50,7 +50,6 @@ const Dialog = React.memo((props: Props) => {
|
|||||||
className='IconButton--large'
|
className='IconButton--large'
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
<div className='octo-spacer'/>
|
|
||||||
{toolsMenu && <MenuWrapper>
|
{toolsMenu && <MenuWrapper>
|
||||||
<IconButton
|
<IconButton
|
||||||
className='IconButton--large'
|
className='IconButton--large'
|
||||||
|
@ -0,0 +1,17 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`components/sidebar/DeleteBoardDialog Cancel should not submit 1`] = `
|
||||||
|
<div
|
||||||
|
id="focalboard-root-portal"
|
||||||
|
>
|
||||||
|
exists
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`components/sidebar/DeleteBoardDialog Delete should submit 1`] = `
|
||||||
|
<div
|
||||||
|
id="focalboard-root-portal"
|
||||||
|
>
|
||||||
|
deleted
|
||||||
|
</div>
|
||||||
|
`;
|
49
webapp/src/components/sidebar/deleteBoardDialog.scss
Normal file
49
webapp/src/components/sidebar/deleteBoardDialog.scss
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
.DeleteBoardDialog {
|
||||||
|
.dialog {
|
||||||
|
@media not screen and (max-width: 975px) {
|
||||||
|
max-width: 512px;
|
||||||
|
height: max-content;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .toolbar {
|
||||||
|
padding-bottom: 0;
|
||||||
|
justify-content: end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex-grow: 1;
|
||||||
|
padding: 0 40px;
|
||||||
|
max-width: 100%;
|
||||||
|
|
||||||
|
.header {
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.body {
|
||||||
|
display: flex;
|
||||||
|
flex-grow: 1;
|
||||||
|
justify-content: center;
|
||||||
|
text-align: center;
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-shrink: 0;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 20px 0 40px;
|
||||||
|
|
||||||
|
button:first-child {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
57
webapp/src/components/sidebar/deleteBoardDialog.test.tsx
Normal file
57
webapp/src/components/sidebar/deleteBoardDialog.test.tsx
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
import React, {useState} from 'react'
|
||||||
|
import {IntlProvider} from 'react-intl'
|
||||||
|
|
||||||
|
import userEvent from '@testing-library/user-event'
|
||||||
|
import {act, render} from '@testing-library/react'
|
||||||
|
|
||||||
|
import DeleteBoardDialog from './deleteBoardDialog'
|
||||||
|
|
||||||
|
describe('components/sidebar/DeleteBoardDialog', () => {
|
||||||
|
it('Cancel should not submit', async () => {
|
||||||
|
const container = renderTest()
|
||||||
|
|
||||||
|
const cancelButton = container.querySelector('.dialog .footer button:not(.danger)')
|
||||||
|
expect(cancelButton).not.toBeFalsy()
|
||||||
|
expect(cancelButton?.textContent).toBe('Cancel')
|
||||||
|
await act(async () => userEvent.click(cancelButton as Element))
|
||||||
|
|
||||||
|
expect(container).toMatchSnapshot()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Delete should submit', async () => {
|
||||||
|
const container = renderTest()
|
||||||
|
|
||||||
|
const deleteButton = container.querySelector('.dialog .footer button.danger')
|
||||||
|
expect(deleteButton).not.toBeFalsy()
|
||||||
|
expect(deleteButton?.textContent).toBe('Delete')
|
||||||
|
await act(async () => userEvent.click(deleteButton as Element))
|
||||||
|
|
||||||
|
expect(container).toMatchSnapshot()
|
||||||
|
})
|
||||||
|
|
||||||
|
function renderTest() {
|
||||||
|
const rootPortalDiv = document.createElement('div')
|
||||||
|
rootPortalDiv.id = 'focalboard-root-portal'
|
||||||
|
|
||||||
|
const {container} = render(<TestComponent/>, {container: document.body.appendChild(rootPortalDiv)})
|
||||||
|
return container
|
||||||
|
}
|
||||||
|
|
||||||
|
function TestComponent() {
|
||||||
|
const [isDeleted, setDeleted] = useState(false)
|
||||||
|
const [isOpen, setOpen] = useState(true)
|
||||||
|
|
||||||
|
return (<IntlProvider locale='en'>
|
||||||
|
{isDeleted ? 'deleted' : 'exists'}
|
||||||
|
{isOpen &&
|
||||||
|
<DeleteBoardDialog
|
||||||
|
boardTitle={'Delete'}
|
||||||
|
onClose={() => setOpen(false)}
|
||||||
|
onDelete={async () => setDeleted(true)}
|
||||||
|
/>}
|
||||||
|
</IntlProvider>)
|
||||||
|
}
|
||||||
|
})
|
85
webapp/src/components/sidebar/deleteBoardDialog.tsx
Normal file
85
webapp/src/components/sidebar/deleteBoardDialog.tsx
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
import React, {useState} from 'react'
|
||||||
|
import {FormattedMessage} from 'react-intl'
|
||||||
|
|
||||||
|
import {Utils} from '../../utils'
|
||||||
|
import Button from '../../widgets/buttons/button'
|
||||||
|
|
||||||
|
import Dialog from '../dialog'
|
||||||
|
import RootPortal from '../rootPortal'
|
||||||
|
|
||||||
|
import './deleteBoardDialog.scss'
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
boardTitle: string;
|
||||||
|
onClose: () => void;
|
||||||
|
onDelete: () => Promise<void>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function DeleteBoardDialog(props: Props): JSX.Element {
|
||||||
|
const [isSubmitting, setSubmitting] = useState(false)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<RootPortal>
|
||||||
|
<Dialog
|
||||||
|
onClose={props.onClose}
|
||||||
|
toolsMenu={null}
|
||||||
|
className='DeleteBoardDialog'
|
||||||
|
>
|
||||||
|
<div className='container'>
|
||||||
|
<h2 className='header text-heading5'>
|
||||||
|
<FormattedMessage
|
||||||
|
id='DeleteBoardDialog.confirm-tite'
|
||||||
|
defaultMessage='Confirm Delete Board'
|
||||||
|
/>
|
||||||
|
</h2>
|
||||||
|
<p className='body'>
|
||||||
|
<FormattedMessage
|
||||||
|
id='DeleteBoardDialog.confirm-info'
|
||||||
|
defaultMessage='Are you sure you want to delete the board “{boardTitle}”? Deleting it will delete the property from all cards in this board.'
|
||||||
|
values={{
|
||||||
|
boardTitle: props.boardTitle,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
<div className='footer'>
|
||||||
|
<Button
|
||||||
|
size={'medium'}
|
||||||
|
emphasis={'tertiary'}
|
||||||
|
onClick={() => !isSubmitting && props.onClose()}
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
id='DeleteBoardDialog.confirm-cancel'
|
||||||
|
defaultMessage='Cancel'
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
size={'medium'}
|
||||||
|
filled={true}
|
||||||
|
danger={true}
|
||||||
|
onClick={async () => {
|
||||||
|
try {
|
||||||
|
setSubmitting(true)
|
||||||
|
await props.onDelete()
|
||||||
|
setSubmitting(false)
|
||||||
|
props.onClose()
|
||||||
|
} catch (e) {
|
||||||
|
setSubmitting(false)
|
||||||
|
Utils.logError(`Delete board ERROR: ${e}`)
|
||||||
|
|
||||||
|
// TODO: display error on screen
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
id='DeleteBoardDialog.confirm-delete'
|
||||||
|
defaultMessage='Delete'
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Dialog>
|
||||||
|
</RootPortal>
|
||||||
|
)
|
||||||
|
}
|
@ -18,6 +18,9 @@ import OptionsIcon from '../../widgets/icons/options'
|
|||||||
import TableIcon from '../../widgets/icons/table'
|
import TableIcon from '../../widgets/icons/table'
|
||||||
import Menu from '../../widgets/menu'
|
import Menu from '../../widgets/menu'
|
||||||
import MenuWrapper from '../../widgets/menuWrapper'
|
import MenuWrapper from '../../widgets/menuWrapper'
|
||||||
|
|
||||||
|
import DeleteBoardDialog from './deleteBoardDialog'
|
||||||
|
|
||||||
import './sidebarBoardItem.scss'
|
import './sidebarBoardItem.scss'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@ -33,6 +36,7 @@ const SidebarBoardItem = React.memo((props: Props) => {
|
|||||||
const [collapsed, setCollapsed] = useState(false)
|
const [collapsed, setCollapsed] = useState(false)
|
||||||
const intl = useIntl()
|
const intl = useIntl()
|
||||||
const history = useHistory()
|
const history = useHistory()
|
||||||
|
const [deleteBoardOpen, setDeleteBoardOpen] = useState(false)
|
||||||
const match = useRouteMatch<{boardId: string, viewId?: string, cardId?: string, workspaceId?: string}>()
|
const match = useRouteMatch<{boardId: string, viewId?: string, cardId?: string, workspaceId?: string}>()
|
||||||
|
|
||||||
const showBoard = useCallback((boardId) => {
|
const showBoard = useCallback((boardId) => {
|
||||||
@ -127,23 +131,8 @@ const SidebarBoardItem = React.memo((props: Props) => {
|
|||||||
id='deleteBoard'
|
id='deleteBoard'
|
||||||
name={intl.formatMessage({id: 'Sidebar.delete-board', defaultMessage: 'Delete board'})}
|
name={intl.formatMessage({id: 'Sidebar.delete-board', defaultMessage: 'Delete board'})}
|
||||||
icon={<DeleteIcon/>}
|
icon={<DeleteIcon/>}
|
||||||
onClick={async () => {
|
onClick={() => {
|
||||||
TelemetryClient.trackEvent(TelemetryCategory, TelemetryActions.DeleteBoard, {board: board.id})
|
setDeleteBoardOpen(true)
|
||||||
mutator.deleteBlock(
|
|
||||||
board,
|
|
||||||
intl.formatMessage({id: 'Sidebar.delete-board', defaultMessage: 'Delete board'}),
|
|
||||||
async () => {
|
|
||||||
if (props.nextBoardId) {
|
|
||||||
// This delay is needed because WSClient has a default 100 ms notification delay before updates
|
|
||||||
setTimeout(() => {
|
|
||||||
showBoard(props.nextBoardId)
|
|
||||||
}, 120)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async () => {
|
|
||||||
showBoard(board.id)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@ -189,6 +178,30 @@ const SidebarBoardItem = React.memo((props: Props) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
|
{deleteBoardOpen &&
|
||||||
|
<DeleteBoardDialog
|
||||||
|
boardTitle={props.board.title}
|
||||||
|
onClose={() => setDeleteBoardOpen(false)}
|
||||||
|
onDelete={async () => {
|
||||||
|
TelemetryClient.trackEvent(TelemetryCategory, TelemetryActions.DeleteBoard, {board: board.id})
|
||||||
|
mutator.deleteBlock(
|
||||||
|
board,
|
||||||
|
intl.formatMessage({id: 'Sidebar.delete-board', defaultMessage: 'Delete board'}),
|
||||||
|
async () => {
|
||||||
|
if (props.nextBoardId) {
|
||||||
|
// This delay is needed because WSClient has a default 100 ms notification delay before updates
|
||||||
|
setTimeout(() => {
|
||||||
|
showBoard(props.nextBoardId)
|
||||||
|
}, 120)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async () => {
|
||||||
|
showBoard(board.id)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
/>}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -41,8 +41,4 @@
|
|||||||
background: rgba(var(--center-channel-color-rgb), 0.1);
|
background: rgba(var(--center-channel-color-rgb), 0.1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.octo-spacer {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
.Button {
|
.Button {
|
||||||
|
--danger-button-bg-rgb: 247, 67, 67;
|
||||||
|
|
||||||
font-family: 'Open Sans', sans-serif;
|
font-family: 'Open Sans', sans-serif;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
@ -15,6 +17,7 @@
|
|||||||
color: inherit;
|
color: inherit;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
padding: 0 10px;
|
padding: 0 10px;
|
||||||
|
font-weight: 600;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: rgba(var(--center-channel-color-rgb), 0.08);
|
background-color: rgba(var(--center-channel-color-rgb), 0.08);
|
||||||
@ -43,6 +46,18 @@
|
|||||||
&:hover {
|
&:hover {
|
||||||
background-color: rgb(var(--button-bg-rgb), 0.8);
|
background-color: rgb(var(--button-bg-rgb), 0.8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.danger {
|
||||||
|
background: linear-gradient(rgb(var(--danger-button-bg-rgb)), rgb(var(--danger-button-bg-rgb)));
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: linear-gradient(rgba(0, 0, 0, 0.08), rgba(0, 0, 0, 0.08)), linear-gradient(rgb(var(--danger-button-bg-rgb)), rgb(var(--danger-button-bg-rgb)));
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background: linear-gradient(rgba(0, 0, 0, 0.16), rgba(0, 0, 0, 0.16)), linear-gradient(rgb(var(--danger-button-bg-rgb)), rgb(var(--danger-button-bg-rgb)));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.emphasis--secondary {
|
&.emphasis--secondary {
|
||||||
@ -58,6 +73,19 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.emphasis--tertiary {
|
||||||
|
color: rgb(var(--button-bg-rgb));
|
||||||
|
background-color: rgb(var(--button-bg-rgb), 0.08);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: rgb(var(--button-bg-rgb), 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background-color: rgb(var(--button-bg-rgb), 0.16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&.emphasis--danger {
|
&.emphasis--danger {
|
||||||
color: rgb(var(--button-danger-color-rgb));
|
color: rgb(var(--button-danger-color-rgb));
|
||||||
background-color: rgb(var(--button-danger-bg-rgb));
|
background-color: rgb(var(--button-danger-bg-rgb));
|
||||||
@ -65,25 +93,27 @@
|
|||||||
&:hover {
|
&:hover {
|
||||||
background-color: rgb(var(--button-danger-bg-rgb), 0.8);
|
background-color: rgb(var(--button-danger-bg-rgb), 0.8);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.active {
|
&.active {
|
||||||
background: rgba(var(--button-bg-rgb), 0.08);
|
background: rgba(var(--button-bg-rgb), 0.08);
|
||||||
color: rgb(var(--button-bg-rgb));
|
color: rgb(var(--button-bg-rgb));
|
||||||
font-weight: 600;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.size--small {
|
&.size--small {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: 600;
|
|
||||||
padding: 0 16px;
|
padding: 0 16px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.size--medium {
|
||||||
|
font-size: 14px;
|
||||||
|
padding: 0 20px;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
&.size--large {
|
&.size--large {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: 600;
|
|
||||||
height: 48px;
|
height: 48px;
|
||||||
padding: 0 24px;
|
padding: 0 24px;
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ type Props = {
|
|||||||
submit?: boolean
|
submit?: boolean
|
||||||
emphasis?: string
|
emphasis?: string
|
||||||
size?: string
|
size?: string
|
||||||
|
danger?: boolean
|
||||||
className?: string
|
className?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24,6 +25,7 @@ function Button(props: Props): JSX.Element {
|
|||||||
Button: true,
|
Button: true,
|
||||||
active: Boolean(props.active),
|
active: Boolean(props.active),
|
||||||
filled: Boolean(props.filled),
|
filled: Boolean(props.filled),
|
||||||
|
danger: Boolean(props.danger),
|
||||||
}
|
}
|
||||||
classNames[`emphasis--${props.emphasis}`] = Boolean(props.emphasis)
|
classNames[`emphasis--${props.emphasis}`] = Boolean(props.emphasis)
|
||||||
classNames[`size--${props.size}`] = Boolean(props.size)
|
classNames[`size--${props.size}`] = Boolean(props.size)
|
||||||
|
Reference in New Issue
Block a user