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