UNPKG

@decidables/discountable-elements

Version:

discountable-elements: Web Components for visualizing Hyperbolic Temporal Discounting

308 lines (252 loc) 7.11 kB
import {html, css} from 'lit'; import '@decidables/decidables-elements/button'; import DiscountableElement from '../discountable-element'; /* DiscountableResponse element <discountable-response> Attributes: */ export default class DiscountableResponse extends DiscountableElement { static get properties() { return { feedback: { attribute: 'feedback', type: Boolean, reflect: true, }, trial: { attribute: 'trial', type: Boolean, reflect: true, }, state: { attribute: false, type: String, reflect: false, }, trialCount: { attribute: false, type: Number, reflect: false, }, trialTotal: { attribute: false, type: Number, reflect: false, }, }; } constructor() { super(); // Attributes this.trial = false; // Show trial count? this.feedback = false; // Show response feedback? // Properties this.states = ['off', 'waiting', 'feedback']; // Possible states this.state = 'off'; // Current state this.trialCount = 0; // Current trial this.trialTotal = 0; // Total trials // Private this.as = 0; this.ds = 0; this.al = 0; this.dl = 0; this.responses = ['first', 'second', 'nr']; // Possible values of 'response' this.response = undefined; // Response for current trial } start(as, ds, al, dl, trial) { this.state = 'waiting'; this.as = as; this.ds = ds; this.al = al; this.dl = dl; this.trialCount = trial; this.response = undefined; } stop() { this.state = 'feedback'; if (this.response === undefined) { this.response = 'nr'; } } first() { this.responded('first'); } second() { this.responded('second'); } responded(response) { this.state = 'feedback'; this.response = response; this.dispatchEvent(new CustomEvent('discountable-response', { detail: { trial: this.trialCount, as: this.as, ds: this.ds, al: this.al, dl: this.dl, response: this.response, }, bubbles: true, })); } reset() { this.state = 'off'; this.trialCount = 0; this.response = undefined; } keydown(event) { if (this.state === 'waiting') { if (event.key === 'ArrowLeft') { this.responded('first'); event.preventDefault(); } else if (event.key === 'ArrowRight') { this.responded('second'); event.preventDefault(); } } } connectedCallback() { super.connectedCallback(); window.addEventListener('keydown', this.keydown.bind(this)); } disconnectedCallback() { window.removeEventListener('keydown', this.keydown.bind(this)); super.disconnectedCallback(); } static get styles() { return [ super.styles, css` :host { display: inline-block; } /* Overall container */ .holder { display: flex; flex-direction: column; } /* Trial messages */ .trials { display: flex; flex-direction: column; justify-content: center; } .trial { text-align: center; } .trial .label { font-weight: 600; } /* Response buttons */ .responses { display: flex; flex-direction: row; align-items: stretch; justify-content: center; } .response { width: 5.25rem; } .waiting[disabled] { --decidables-button-background-color: var(---color-element-enabled); } .selected[disabled][name="first"] { --decidables-button-background-color: var(---color-sooner); } .selected[disabled][name="second"] { --decidables-button-background-color: var(---color-later); } /* Feedback messages */ .feedbacks { display: flex; flex-direction: row; justify-content: center; } /* Outcome feedback */ .feedback { display: flex; flex-direction: column; align-items: center; justify-content: center; width: 5.25rem; height: 3.5rem; padding: 0.375rem 0.75rem; margin: 0.25rem; text-align: center; background-color: var(---color-element-background); border: 1px solid var(---color-element-border); } .feedback.first { background-color: var(---color-sooner-light); } .feedback.second { background-color: var(---color-later-light); } .feedback.nr { background-color: var(---color-nr-light); } `, ]; } render() { return html` <div class="holder"> ${(this.trial) ? html` <div class="trials"> <div class="trial"> <span class="label">Trial: </span ><span class="count">${this.trialCount}</span ><span class="of"> of </span ><span class="total">${this.trialTotal}</span> </div> </div>` : html``} <div class="responses"> <decidables-button name="first" class="response ${ (this.state === 'feedback' && this.response === 'first') ? 'selected' : (this.state === 'waiting') ? 'waiting' : '' }" ?disabled=${this.state !== 'waiting' || this.interactive !== true} @click=${this.first.bind(this)} >First</decidables-button> <decidables-button name="second" class="response ${ (this.state === 'feedback' && this.response === 'second') ? 'selected' : (this.state === 'waiting') ? 'waiting' : '' }" ?disabled=${this.state !== 'waiting' || this.interactive !== true} @click=${this.second.bind(this)} >Second</decidables-button> </div> ${this.feedback ? html` <div class="feedbacks"> <div class="feedback ${((this.state === 'feedback') && this.feedback) ? this.response : ''}"> ${((this.state === 'feedback') && this.feedback) ? (this.response === 'first') ? html`<span class="response">First</span>` : (this.response === 'second') ? html`<span class="response">Second</span>` : html`<span class="response">No<br>Response</span>` : ''} </div> </div>` : html``} </div>`; } } customElements.define('discountable-response', DiscountableResponse);