@decidables/discountable-elements 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json ADDED
@@ -0,0 +1,69 @@
1
+ {
2
+ "name": "@decidables/discountable-elements",
3
+ "version": "0.1.0",
4
+ "description": "discountable-elements: Web Components for visualizing Hyperbolic Temporal Discounting",
5
+ "keywords": [
6
+ "web component",
7
+ "explorable explanation",
8
+ "explorable",
9
+ "decision making",
10
+ "decidables",
11
+ "hyperbolic temporal discounting",
12
+ "temporal discounting",
13
+ "delay discounting",
14
+ "discountable"
15
+ ],
16
+ "type": "module",
17
+ "main": "./lib/discountableElements.umd.min.js",
18
+ "browser": "./lib/discountableElements.umd.min.js",
19
+ "module": "./lib/discountableElements.esm.min.js",
20
+ "exports": {
21
+ "./lib/*.js": "./lib/*.js",
22
+ ".": "./src/index.js",
23
+ "./components": "./src/components/index.js",
24
+ "./equations": "./src/equations/index.js",
25
+ "./examples": "./src/examples/index.js",
26
+ "./*": "./src/*.js"
27
+ },
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "https://github.com/decidables/decidables.git",
31
+ "directory": "libraries/discountable-elements"
32
+ },
33
+ "bugs": "https://github.com/decidables/decidables/issues",
34
+ "homepage": "https://github.com/decidables/decidables/tree/main/libraries/discountable-elements",
35
+ "author": "Adam Krawitz (https://web.uvic.ca/psyc/krawitz/)",
36
+ "license": "CC-BY-SA-4.0 AND GPL-3.0-or-later",
37
+ "publishConfig": {
38
+ "access": "public"
39
+ },
40
+ "files": [
41
+ "package.json",
42
+ "*.md",
43
+ "src",
44
+ "lib"
45
+ ],
46
+ "scripts": {
47
+ "lint": "gulp lint",
48
+ "test": "web-test-runner test/**/*.test.js --config ../../.webtestrunnerrc.js",
49
+ "test:watch": "web-test-runner test/**/*.test.js --config ../../.webtestrunnerrc.js --watch",
50
+ "test:file": "web-test-runner $@ --config ../../.webtestrunnerrc.js",
51
+ "build": "gulp build"
52
+ },
53
+ "devDependencies": {
54
+ "@web/test-runner": "^0.17.1",
55
+ "gulp": "^4.0.2"
56
+ },
57
+ "dependencies": {
58
+ "@decidables/decidables-elements": "^0.4.0",
59
+ "@decidables/discountable-math": "^0.1.0",
60
+ "@lit-labs/motion": "^1.0.4",
61
+ "@observablehq/plot": "^0.6.11",
62
+ "bayes.js": "https://github.com/akrawitz/bayes.js.git#commit=c7b091b75f85a86b6a3965a983b31e23d9ef456f",
63
+ "d3": "^7.8.5",
64
+ "jstat": "^1.9.6",
65
+ "lit": "^2.8.0",
66
+ "regenerator-runtime": "^0.14.0"
67
+ },
68
+ "gitHead": "0c1c25702476045288038e7cacaaa70245b84cd1"
69
+ }
@@ -0,0 +1,173 @@
1
+
2
+ import {html, css} from 'lit';
3
+
4
+ import '@decidables/decidables-elements/button';
5
+ import '@decidables/decidables-elements/slider';
6
+
7
+ import DiscountableElement from '../discountable-element';
8
+
9
+ /*
10
+ DiscountableControl element
11
+ <discountable-control>
12
+
13
+ Attributes:
14
+
15
+ */
16
+ export default class DiscountableControl extends DiscountableElement {
17
+ static get properties() {
18
+ return {
19
+ trials: {
20
+ attribute: 'trials',
21
+ type: Number,
22
+ reflect: true,
23
+ },
24
+ duration: {
25
+ attribute: 'duration',
26
+ type: Number,
27
+ reflect: true,
28
+ },
29
+ run: {
30
+ attribute: 'run',
31
+ type: Boolean,
32
+ reflect: true,
33
+ },
34
+ pause: {
35
+ attribute: 'pause',
36
+ type: Boolean,
37
+ reflect: true,
38
+ },
39
+ reset: {
40
+ attribute: 'reset',
41
+ type: Boolean,
42
+ reflect: true,
43
+ },
44
+
45
+ state: {
46
+ atribute: false,
47
+ type: String,
48
+ reflect: false,
49
+ },
50
+ };
51
+ }
52
+
53
+ constructor() {
54
+ super();
55
+
56
+ // Attributes
57
+ this.trials = undefined;
58
+ this.duration = undefined;
59
+ this.run = false;
60
+ this.pause = false;
61
+ this.reset = false;
62
+
63
+ // Properties
64
+ this.states = ['resetted', 'running', 'paused', 'ended'];
65
+ this.state = 'resetted';
66
+ }
67
+
68
+ setTrials(e) {
69
+ this.trials = e.target.value;
70
+ this.dispatchEvent(new CustomEvent('discountable-control-trials', {
71
+ detail: {
72
+ trials: this.trials,
73
+ },
74
+ bubbles: true,
75
+ }));
76
+ }
77
+
78
+ setDuration(e) {
79
+ this.duration = e.target.value;
80
+ this.dispatchEvent(new CustomEvent('discountable-control-duration', {
81
+ detail: {
82
+ duration: this.duration,
83
+ },
84
+ bubbles: true,
85
+ }));
86
+ }
87
+
88
+ doRun() {
89
+ this.state = 'running';
90
+ this.dispatchEvent(new CustomEvent('discountable-control-run', {
91
+ detail: {},
92
+ bubbles: true,
93
+ }));
94
+ }
95
+
96
+ doPause() {
97
+ this.state = 'paused';
98
+ this.dispatchEvent(new CustomEvent('discountable-control-pause', {
99
+ detail: {},
100
+ bubbles: true,
101
+ }));
102
+ }
103
+
104
+ doReset() {
105
+ this.state = 'resetted';
106
+ this.dispatchEvent(new CustomEvent('discountable-control-reset', {
107
+ detail: {},
108
+ bubbles: true,
109
+ }));
110
+ }
111
+
112
+ complete() {
113
+ this.state = 'ended';
114
+ }
115
+
116
+ static get styles() {
117
+ return [
118
+ super.styles,
119
+ css`
120
+ :host {
121
+ display: inline-block;
122
+ }
123
+
124
+ .holder {
125
+ display: flex;
126
+
127
+ flex-direction: row;
128
+
129
+ align-items: stretch;
130
+ justify-content: center;
131
+ }
132
+
133
+ .buttons {
134
+ display: flex;
135
+
136
+ flex-direction: column;
137
+
138
+ align-items: stretch;
139
+ justify-content: center;
140
+ }
141
+ `,
142
+ ];
143
+ }
144
+
145
+ render() {
146
+ return html`
147
+ <div class="holder">
148
+ ${this.trials
149
+ ? html`<decidables-slider min="1" max="100" step="1" .value=${this.trials} @change=${this.setTrials.bind(this)} @input=${this.setTrials.bind(this)}>Trials</decidables-slider>`
150
+ : html``}
151
+ ${this.duration
152
+ ? html`<decidables-slider min="10" max="4000" step="10" .value=${this.duration} @change=${this.setDuration.bind(this)} @input=${this.setDuration.bind(this)}>Duration</decidables-slider>`
153
+ : html``}
154
+ ${this.run || this.pause || this.reset
155
+ ? html`
156
+ <div class="buttons">
157
+ ${this.run
158
+ ? html`<decidables-button name="run" ?disabled=${this.state === 'running' || this.state === 'ended'} @click=${this.doRun.bind(this)}>Run</decidables-button>`
159
+ : html``}
160
+ ${this.pause
161
+ ? html`<decidables-button name="pause" ?disabled=${this.state !== 'running'} @click=${this.doPause.bind(this)}>Pause</decidables-button>`
162
+ : html``}
163
+ ${this.reset
164
+ ? html`<decidables-button name="reset" ?disabled=${this.state === 'resetted'} @click=${this.doReset.bind(this)}>Reset</decidables-button>`
165
+ : html``}
166
+ </div>
167
+ `
168
+ : html``}
169
+ </div>`;
170
+ }
171
+ }
172
+
173
+ customElements.define('discountable-control', DiscountableControl);
@@ -0,0 +1,283 @@
1
+
2
+ import {html, css} from 'lit';
3
+
4
+ import '@decidables/decidables-elements/button';
5
+
6
+ import DiscountableElement from '../discountable-element';
7
+
8
+ /*
9
+ DiscountableResponse element
10
+ <discountable-response>
11
+
12
+ Attributes:
13
+
14
+ */
15
+ export default class DiscountableResponse extends DiscountableElement {
16
+ static get properties() {
17
+ return {
18
+ trial: {
19
+ attribute: 'trial',
20
+ type: Boolean,
21
+ reflect: true,
22
+ },
23
+ feedback: {
24
+ attribute: 'feedback',
25
+ type: Boolean,
26
+ reflect: true,
27
+ },
28
+
29
+ state: {
30
+ attribute: false,
31
+ type: String,
32
+ reflect: false,
33
+ },
34
+ trialCount: {
35
+ attribute: false,
36
+ type: Number,
37
+ reflect: false,
38
+ },
39
+ trialTotal: {
40
+ attribute: false,
41
+ type: Number,
42
+ reflect: false,
43
+ },
44
+ };
45
+ }
46
+
47
+ constructor() {
48
+ super();
49
+
50
+ // Attributes
51
+ this.trial = false; // Show trial count?
52
+ this.feedback = false; // Show response feedback?
53
+
54
+ // Properties
55
+ this.states = ['off', 'waiting', 'feedback']; // Possible states
56
+ this.state = 'off'; // Current state
57
+
58
+ this.trialCount = 0; // Current trial
59
+ this.trialTotal = 0; // Total trials
60
+
61
+ // Private
62
+ this.as = 0;
63
+ this.ds = 0;
64
+ this.al = 0;
65
+ this.dl = 0;
66
+ this.responses = ['first', 'second', 'nr']; // Possible values of 'response'
67
+ this.response = undefined; // Response for current trial
68
+ }
69
+
70
+ start(as, ds, al, dl, trial) {
71
+ this.state = 'waiting';
72
+
73
+ this.as = as;
74
+ this.ds = ds;
75
+ this.al = al;
76
+ this.dl = dl;
77
+ this.trialCount = trial;
78
+
79
+ this.response = undefined;
80
+ }
81
+
82
+ stop() {
83
+ this.state = 'feedback';
84
+ if (this.response === undefined) {
85
+ this.response = 'nr';
86
+ }
87
+ }
88
+
89
+ first() {
90
+ this.responded('first');
91
+ }
92
+
93
+ second() {
94
+ this.responded('second');
95
+ }
96
+
97
+ responded(response) {
98
+ this.state = 'feedback';
99
+ this.response = response;
100
+
101
+ this.dispatchEvent(new CustomEvent('discountable-response', {
102
+ detail: {
103
+ trial: this.trialCount,
104
+ as: this.as,
105
+ ds: this.ds,
106
+ al: this.al,
107
+ dl: this.dl,
108
+ response: this.response,
109
+ },
110
+ bubbles: true,
111
+ }));
112
+ }
113
+
114
+ reset() {
115
+ this.state = 'off';
116
+ this.trialCount = 0;
117
+ this.response = undefined;
118
+ }
119
+
120
+ static get styles() {
121
+ return [
122
+ super.styles,
123
+ css`
124
+ :host {
125
+ display: inline-block;
126
+ }
127
+
128
+ /* Overall container */
129
+ .holder {
130
+ display: flex;
131
+
132
+ flex-direction: column;
133
+ }
134
+
135
+ /* Trial messages */
136
+ .trials {
137
+ display: flex;
138
+
139
+ flex-direction: column;
140
+
141
+ justify-content: center;
142
+ }
143
+
144
+ .trial {
145
+ text-align: center;
146
+ }
147
+
148
+ .trial .label {
149
+ font-weight: 600;
150
+ }
151
+
152
+ /* Response buttons */
153
+ .responses {
154
+ display: flex;
155
+
156
+ flex-direction: row;
157
+
158
+ align-items: stretch;
159
+ justify-content: center;
160
+ }
161
+
162
+ .response {
163
+ width: 5.25rem;
164
+ }
165
+
166
+ .waiting[disabled] {
167
+ --decidables-button-background-color: var(---color-element-enabled);
168
+ }
169
+
170
+ .selected[disabled][name="first"] {
171
+ --decidables-button-background-color: var(---color-worse);
172
+ }
173
+
174
+ .selected[disabled][name="second"] {
175
+ --decidables-button-background-color: var(---color-better);
176
+ }
177
+
178
+ /* Feedback messages */
179
+ .feedbacks {
180
+ display: flex;
181
+
182
+ flex-direction: row;
183
+
184
+ justify-content: center;
185
+ }
186
+
187
+ /* Outcome feedback */
188
+ .feedback {
189
+ display: flex;
190
+
191
+ flex-direction: column;
192
+
193
+ align-items: center;
194
+ justify-content: center;
195
+
196
+ width: 5.25rem;
197
+ height: 3.5rem;
198
+ padding: 0.375rem 0.75rem;
199
+ margin: 0.25rem;
200
+
201
+ text-align: center;
202
+
203
+ background-color: var(---color-element-background);
204
+ border: 1px solid var(---color-element-border);
205
+ }
206
+
207
+ .feedback.first {
208
+ background-color: var(---color-worse-light);
209
+ }
210
+
211
+ .feedback.second {
212
+ background-color: var(---color-better-light);
213
+ }
214
+
215
+ .feedback.nr {
216
+ background-color: var(---color-nr-light);
217
+ }
218
+ `,
219
+ ];
220
+ }
221
+
222
+ render() {
223
+ return html`
224
+ <div class="holder">
225
+ ${(this.trial)
226
+ ? html`
227
+ <div class="trials">
228
+ <div class="trial">
229
+ <span class="label">Trial: </span
230
+ ><span class="count">${this.trialCount}</span
231
+ ><span class="of"> of </span
232
+ ><span class="total">${this.trialTotal}</span>
233
+ </div>
234
+ </div>`
235
+ : html``}
236
+ <div class="responses">
237
+ <decidables-button
238
+ name="first"
239
+ class="response ${
240
+ (this.state === 'feedback' && this.response === 'first')
241
+ ? 'selected'
242
+ : (this.state === 'waiting')
243
+ ? 'waiting'
244
+ : ''
245
+ }"
246
+ ?disabled=${this.state !== 'waiting' || this.interactive !== true}
247
+ @click=${this.first.bind(this)}
248
+ >First</decidables-button>
249
+ <decidables-button
250
+ name="second"
251
+ class="response ${
252
+ (this.state === 'feedback' && this.response === 'second')
253
+ ? 'selected'
254
+ : (this.state === 'waiting')
255
+ ? 'waiting'
256
+ : ''
257
+ }"
258
+ ?disabled=${this.state !== 'waiting' || this.interactive !== true}
259
+ @click=${this.second.bind(this)}
260
+ >Second</decidables-button>
261
+ </div>
262
+ ${this.feedback
263
+ ? html`
264
+ <div class="feedbacks">
265
+ <div class="feedback
266
+ ${((this.state === 'feedback') && this.feedback)
267
+ ? this.response
268
+ : ''}">
269
+ ${((this.state === 'feedback') && this.feedback)
270
+ ? (this.response === 'first')
271
+ ? html`<span class="response">First</span>`
272
+ : (this.response === 'second')
273
+ ? html`<span class="response">Second</span>`
274
+ : html`<span class="response">No<br>Response</span>`
275
+ : ''}
276
+ </div>
277
+ </div>`
278
+ : html``}
279
+ </div>`;
280
+ }
281
+ }
282
+
283
+ customElements.define('discountable-response', DiscountableResponse);