preact-components/source/buttons/confirm-button.ts

85 lines
1.9 KiB
TypeScript

import {html} from 'htm/preact';
import {Component, VNode} from 'preact';
/**
* Component properties for {@linkcode ConfirmButton}.
*/
export type ConfirmButtonProps = {
attributes: Record<string, unknown>;
class: string;
click: (event: MouseEvent) => unknown;
confirmClass: string;
confirmText: string;
preventDefault: boolean;
text: string;
timeout: number;
};
/**
* Component state for {@linkcode ConfirmButton}.
*/
export type ConfirmButtonState = {
timeoutHandle: number | undefined;
};
/**
* A {@linkcode https://developer.mozilla.org/docs/Web/HTML/Element/button <button>}
* element wrapper that requires 2 clicks within a given time to call the click
* function. For example to confirm removal of something.
*/
export class ConfirmButton extends Component<
ConfirmButtonProps,
ConfirmButtonState
> {
constructor(props: ConfirmButtonProps) {
super(props);
this.state = {
timeoutHandle: undefined,
};
}
click = (event: MouseEvent) => {
const {click, preventDefault, timeout} = this.props;
const {timeoutHandle} = this.state;
if (preventDefault) {
event.preventDefault();
}
if (timeoutHandle === undefined) {
this.setState({
timeoutHandle: window.setTimeout(this.resetTimeout, timeout),
});
} else {
click(event);
this.resetTimeout();
}
};
resetTimeout = () => {
window.clearTimeout(this.state.timeoutHandle);
this.setState({timeoutHandle: undefined});
};
render(): VNode {
const timeoutActive = this.state.timeoutHandle !== undefined;
let text = this.props.text;
const props: Record<string, string> = {
class: this.props.class,
};
if (timeoutActive) {
text = this.props.confirmText;
props.class = `${props.class} ${this.props.confirmClass}`;
}
return html`
<button ...${this.props.attributes} ...${props} onclick=${this.click}>
${text}
</button>
`;
}
}