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
 | 
					// Button Exports
 | 
				
			||||||
export * from './buttons/confirm-button.js';
 | 
					export * from './buttons/confirm-button.js';
 | 
				
			||||||
 | 
					export * from './buttons/feedback-button.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Link Exports
 | 
					// Link Exports
 | 
				
			||||||
export * from './links/privacy-link.js';
 | 
					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