Add the FeedbackButton component.
This commit is contained in:
parent
c78d088d00
commit
dfeaa5db22
|
@ -0,0 +1,68 @@
|
|||
import {html} from 'htm/preact';
|
||||
import {Component, VNode} from 'preact';
|
||||
|
||||
/**
|
||||
* Component properties for {@linkcode FeedbackButton}.
|
||||
*/
|
||||
export type FeedbackButtonProps = {
|
||||
click: (event: MouseEvent) => unknown;
|
||||
extraAttributes: Record<string, string>;
|
||||
feedbackText: string;
|
||||
text: string;
|
||||
timeout: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* Component state for {@linkcode FeedbackButton}.
|
||||
*/
|
||||
export type FeedbackButtonState = {
|
||||
currentText: string;
|
||||
timeoutHandle: number | undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
* A {@linkcode https://developer.mozilla.org/docs/Web/HTML/Element/button <button>}
|
||||
* element wrapper that changes its text for a given time after being clicked.
|
||||
*/
|
||||
export class FeedbackButton extends Component<
|
||||
FeedbackButtonProps,
|
||||
FeedbackButtonState
|
||||
> {
|
||||
constructor(props: FeedbackButtonProps) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
currentText: this.props.text,
|
||||
timeoutHandle: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
click = (event: MouseEvent) => {
|
||||
this.props.click(event);
|
||||
|
||||
let {timeoutHandle} = this.state;
|
||||
if (timeoutHandle !== undefined) {
|
||||
window.clearTimeout(timeoutHandle);
|
||||
}
|
||||
|
||||
timeoutHandle = window.setTimeout(() => {
|
||||
this.setState({
|
||||
currentText: this.props.text,
|
||||
timeoutHandle: undefined,
|
||||
});
|
||||
}, this.props.timeout);
|
||||
|
||||
this.setState({
|
||||
currentText: this.props.feedbackText,
|
||||
timeoutHandle,
|
||||
});
|
||||
};
|
||||
|
||||
render(): VNode {
|
||||
return html`
|
||||
<button ...${this.props.extraAttributes} onclick=${this.click}>
|
||||
${this.state.currentText}
|
||||
</button>
|
||||
`;
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
// Button Exports
|
||||
export * from './buttons/confirm-button.js';
|
||||
export * from './buttons/feedback-button.js';
|
||||
|
||||
// Link Exports
|
||||
export * from './links/privacy-link.js';
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
import {GlobalRegistrator} from '@happy-dom/global-registrator';
|
||||
import test from 'ava';
|
||||
import {html} from 'htm/preact';
|
||||
import {render} from 'preact';
|
||||
|
||||
import {FeedbackButton, FeedbackButtonProps} from '../../source/gram.js';
|
||||
import {sleep} from '../utilities.js';
|
||||
|
||||
test.before(() => {
|
||||
GlobalRegistrator.register();
|
||||
});
|
||||
|
||||
test('FeedbackButton', async (t) => {
|
||||
t.plan(5);
|
||||
|
||||
const props: FeedbackButtonProps = {
|
||||
click: (event) => t.true(event !== undefined),
|
||||
extraAttributes: {
|
||||
id: 'feedback-button',
|
||||
},
|
||||
feedbackText: 'Feedback Example',
|
||||
text: 'Example',
|
||||
timeout: 1000,
|
||||
};
|
||||
|
||||
render(html`<${FeedbackButton} ...${props} />`, document);
|
||||
|
||||
const buttonElement =
|
||||
document.querySelector<HTMLButtonElement>('#feedback-button')!;
|
||||
|
||||
t.snapshot(buttonElement.outerHTML, 'Default state');
|
||||
buttonElement.click();
|
||||
|
||||
// Wait for Preact to do its stuff.
|
||||
await sleep();
|
||||
|
||||
t.snapshot(buttonElement.outerHTML, 'Feedback state');
|
||||
buttonElement.click();
|
||||
|
||||
await sleep(props.timeout);
|
||||
|
||||
t.snapshot(buttonElement.outerHTML, 'Back to default state');
|
||||
});
|
|
@ -0,0 +1,19 @@
|
|||
# Snapshot report for `tests/buttons/feedback-button.test.ts`
|
||||
|
||||
The actual snapshot is saved in `feedback-button.test.ts.snap`.
|
||||
|
||||
Generated by [AVA](https://avajs.dev).
|
||||
|
||||
## FeedbackButton
|
||||
|
||||
> Default state
|
||||
|
||||
'<button id="feedback-button">Example</button>'
|
||||
|
||||
> Feedback state
|
||||
|
||||
'<button id="feedback-button">Feedback Example</button>'
|
||||
|
||||
> Back to default state
|
||||
|
||||
'<button id="feedback-button">Example</button>'
|
Binary file not shown.
Loading…
Reference in New Issue