Skip to content

Commit 68f0dbc

Browse files
authored
RND-7464: confirm in content kit button (#3488)
1 parent 39c4f76 commit 68f0dbc

File tree

3 files changed

+119
-33
lines changed

3 files changed

+119
-33
lines changed

.changeset/seven-mails-stare.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"gitbook": patch
3+
---
4+
5+
Add confirmation modal to contentkit button

packages/gitbook/src/components/DocumentView/Integration/contentkit.css

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,3 +195,18 @@
195195
.contentkit-hstack > .contentkit-divider-large {
196196
@apply mx-4;
197197
}
198+
199+
/** Confirmation modal */
200+
201+
.contentkit-modal-confirm {
202+
@apply p-4;
203+
}
204+
.contentkit-modal-confirm .contentkit-modal-footer {
205+
@apply flex gap-2 justify-end;
206+
}
207+
.contentkit-button-confirm {
208+
@apply w-auto flex-grow-0 flex-shrink-0;
209+
}
210+
.contentkit-button-style-danger {
211+
@apply bg-danger text-danger hover:bg-danger-hover hover:text-danger-strong contrast-more:bg-tint-subtle;
212+
}

packages/react-contentkit/src/ElementButton.tsx

Lines changed: 99 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -18,41 +18,107 @@ export function ElementButton(
1818
const clientContext = useContentKitClientContext();
1919

2020
const [loading, setLoading] = React.useState(false);
21+
const [confirm, setConfirm] = React.useState<boolean>(false);
2122

22-
// TODO:
23-
// - confirm dialog
23+
const wrapLoading = React.useCallback(async <T,>(fn: Promise<T> | (() => Promise<T>)) => {
24+
setLoading(true);
25+
try {
26+
return fn instanceof Promise ? await fn : await fn();
27+
} finally {
28+
setLoading(false);
29+
}
30+
}, []);
2431

2532
return (
26-
<button
27-
title={element.tooltip}
28-
className={classNames(
29-
'contentkit-button',
30-
`contentkit-button-style-${element.style ?? 'secondary'}`
31-
)}
32-
onClick={(event) => {
33-
if (element.disabled || loading) {
34-
return;
35-
}
36-
37-
event.stopPropagation();
38-
39-
setLoading(true);
40-
clientContext.dispatchAction(element.onPress).finally(() => {
41-
setLoading(false);
42-
});
43-
}}
44-
>
45-
{loading ? (
46-
<Icon icon="spinner" className="contentkit-button-loading" />
47-
) : (
48-
<>
49-
{icon}
50-
{element.label ? (
51-
<span className="contentkit-button-label">{element.label}</span>
52-
) : null}
53-
{trailingIcon}
54-
</>
55-
)}
56-
</button>
33+
<>
34+
<button
35+
type="button"
36+
title={element.tooltip}
37+
className={classNames(
38+
'contentkit-button',
39+
`contentkit-button-style-${element.style ?? 'secondary'}`
40+
)}
41+
onClick={(event) => {
42+
if (element.disabled || loading) {
43+
return;
44+
}
45+
46+
event.stopPropagation();
47+
event.preventDefault();
48+
49+
if (element.confirm && !confirm) {
50+
setConfirm(true);
51+
return;
52+
}
53+
54+
wrapLoading(async () => await clientContext.dispatchAction(element.onPress));
55+
}}
56+
>
57+
{loading ? (
58+
<Icon icon="spinner" className="contentkit-button-loading" />
59+
) : (
60+
<>
61+
{icon}
62+
{element.label ? (
63+
<span className="contentkit-button-label">{element.label}</span>
64+
) : null}
65+
{trailingIcon}
66+
</>
67+
)}
68+
</button>
69+
{element.confirm && confirm ? (
70+
<ConfirmDialog
71+
open={confirm}
72+
{...element.confirm}
73+
onConfirm={() => {
74+
setConfirm(false);
75+
wrapLoading(
76+
async () => await clientContext.dispatchAction(element.onPress)
77+
);
78+
}}
79+
onCancel={() => setConfirm(false)}
80+
/>
81+
) : null}
82+
</>
83+
);
84+
}
85+
86+
function ConfirmDialog({ open, onCancel, onConfirm, style, title, text, confirm }: any) {
87+
return (
88+
<div className="contentkit-modal-backdrop" onClick={onCancel}>
89+
<div
90+
className={classNames(
91+
'contentkit-modal contentkit-modal-confirm',
92+
open ? 'contentkit-modal-opened' : null
93+
)}
94+
onClick={(event) => {
95+
event.stopPropagation();
96+
}}
97+
>
98+
<div className="contentkit-modal-header">
99+
{title ? <h1 className="contentkit-modal-title">{title}</h1> : null}
100+
{text ? <div className="contentkit-modal-subtitle">{text}</div> : null}
101+
</div>
102+
<div className="contentkit-modal-footer">
103+
<button
104+
type="button"
105+
className="contentkit-button contentkit-button-confirm contentkit-button-style-secondary"
106+
onClick={onCancel}
107+
>
108+
Cancel
109+
</button>
110+
<button
111+
type="button"
112+
className={classNames(
113+
'contentkit-button contentkit-button-confirm',
114+
`contentkit-button-style-${style ?? 'primary'}`
115+
)}
116+
onClick={onConfirm}
117+
>
118+
{confirm ?? 'OK'}
119+
</button>
120+
</div>
121+
</div>
122+
</div>
57123
);
58124
}

0 commit comments

Comments
 (0)