@webwriter/quiz 1.0.2 → 1.0.4

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.
Files changed (45) hide show
  1. package/LICENSE +6 -6
  2. package/custom.d.ts +175 -175
  3. package/dist/widgets/webwriter-choice-item.js +3257 -59
  4. package/dist/widgets/webwriter-choice.js +4941 -79
  5. package/dist/widgets/webwriter-cloze-gap.js +4092 -179
  6. package/dist/widgets/webwriter-cloze.js +2415 -36
  7. package/dist/widgets/webwriter-mark.js +2471 -61
  8. package/dist/widgets/webwriter-order-item.js +2447 -68
  9. package/dist/widgets/webwriter-order.js +4990 -135
  10. package/dist/widgets/webwriter-pairing-item.js +1581 -48
  11. package/dist/widgets/webwriter-pairing.js +3686 -72
  12. package/dist/widgets/webwriter-quiz.js +6938 -76
  13. package/dist/widgets/webwriter-speech.js +6265 -76
  14. package/dist/widgets/webwriter-task-explainer.js +1564 -31
  15. package/dist/widgets/webwriter-task-hint.js +1523 -28
  16. package/dist/widgets/webwriter-task-prompt.js +1586 -29
  17. package/dist/widgets/webwriter-task.js +7132 -101
  18. package/dist/widgets/webwriter-text.js +4044 -54
  19. package/package.json +200 -200
  20. package/src/lib/combobox.ts +455 -455
  21. package/src/snippets/choice.html +7 -7
  22. package/src/snippets/cloze.html +3 -3
  23. package/src/snippets/mark.html +3 -3
  24. package/src/snippets/order.html +7 -7
  25. package/src/snippets/pairing.html +9 -9
  26. package/src/snippets/speech.html +3 -3
  27. package/src/snippets/text.html +3 -3
  28. package/src/snippets/wordsearch.html +3 -3
  29. package/src/widgets/webwriter-choice-item.ts +250 -250
  30. package/src/widgets/webwriter-choice.ts +309 -309
  31. package/src/widgets/webwriter-cloze-gap.ts +216 -216
  32. package/src/widgets/webwriter-cloze.ts +135 -135
  33. package/src/widgets/webwriter-mark.ts +434 -434
  34. package/src/widgets/webwriter-order-item.ts +444 -444
  35. package/src/widgets/webwriter-order.ts +272 -272
  36. package/src/widgets/webwriter-pairing-item.ts +155 -155
  37. package/src/widgets/webwriter-pairing.ts +187 -187
  38. package/src/widgets/webwriter-quiz.ts +280 -280
  39. package/src/widgets/webwriter-speech.ts +267 -267
  40. package/src/widgets/webwriter-task-explainer.ts +37 -37
  41. package/src/widgets/webwriter-task-hint.ts +16 -16
  42. package/src/widgets/webwriter-task-prompt.ts +17 -17
  43. package/src/widgets/webwriter-task.ts +543 -543
  44. package/src/widgets/webwriter-text.ts +130 -130
  45. package/tsconfig.json +6 -6
@@ -1,217 +1,217 @@
1
- import {LitElement, html, css, RenderOptions} from "lit"
2
- import {LitElementWw} from "@webwriter/lit"
3
- import {customElement, query} from "lit/decorators.js"
4
-
5
- import SlIconButton from "@shoelace-style/shoelace/dist/components/icon-button/icon-button.component.js"
6
- import SlOption from "@shoelace-style/shoelace/dist/components/option/option.component.js"
7
- import IconPlus from "bootstrap-icons/icons/plus.svg"
8
- import IconSlashCircle from "bootstrap-icons/icons/slash-circle.svg"
9
- import IconCheckCircle from "bootstrap-icons/icons/check-circle.svg"
10
- import IconX from "bootstrap-icons/icons/x.svg"
11
-
12
- import { Combobox } from "../lib/combobox"
13
- import { property } from "lit/decorators/property.js"
14
- import { queryAsync } from "lit/decorators/query-async.js"
15
- import "@shoelace-style/shoelace/dist/themes/light.css"
16
-
17
- declare global {interface HTMLElementTagNameMap {
18
- "webwriter-cloze-gap": WebwriterClozeGap;
19
- }}
20
-
21
- @customElement("webwriter-cloze-gap")
22
- export class WebwriterClozeGap extends LitElementWw {
23
-
24
- static localization = {}
25
-
26
- @property({type: Array, attribute: true, reflect: true})
27
- accessor solution: string[]
28
-
29
- @property({type: String, attribute: true, reflect: true})
30
- accessor value: string
31
-
32
- @property({type: Array, attribute: true, reflect: true})
33
- accessor distraction: string[] = []
34
-
35
-
36
- @property({type: Boolean, attribute: true, reflect: true})
37
- accessor showOptions = false
38
-
39
- msg = (str: string) => this.lang in WebwriterClozeGap.localization? WebwriterClozeGap.localization[this.lang][str] ?? str: str
40
-
41
-
42
- static scopedElements = {
43
- "ww-combobox": Combobox,
44
- "sl-icon-button": SlIconButton,
45
- "sl-option": SlOption
46
- }
47
-
48
- static styles = css`
49
- :host {
50
- display: inline-block !important;
51
- vertical-align: top;
52
- margin: 0 1ch;
53
- max-width: calc(100% - 2ch);
54
- max-height: 1lh;
55
- }
56
-
57
- :host(::after) {
58
- content: " ";
59
- display: block;
60
- }
61
-
62
- sl-icon-button[data-hidden] {
63
- visibility: hidden;
64
- }
65
-
66
- sl-icon-button::part(base) {
67
- padding: 0;
68
- }
69
-
70
- :host(:not(:focus-within)) #add {
71
- visibility: hidden;
72
- }
73
-
74
- sl-icon-button {
75
- overflow: visible;
76
- margin-right: 0;
77
- }
78
-
79
- ww-combobox::part(base) {
80
- min-height: unset;
81
- padding: 2px 2px;
82
- }
83
-
84
- :host(:is([contenteditable=true], [contenteditable=""])) ww-combobox::part(input) {
85
- color: var(--sl-color-success-700);
86
- }
87
-
88
- sl-option::part(base) {
89
- padding: 0;
90
- font-size: var(--sl-input-font-size-small);
91
- }
92
-
93
- sl-option::part(label) {
94
- padding: var(--sl-spacing-2x-small) 0;
95
- }
96
-
97
- sl-option::part(label):hover {
98
- color: var(--sl-color-primary-600);
99
- }
100
-
101
- sl-option::part(checked-icon) {
102
- display: none;
103
- }
104
-
105
- .remove::part(base):hover {
106
- color: var(--sl-color-danger-600) !important;
107
- }
108
-
109
- .remove::part(base):active {
110
- color: var(--sl-color-danger-800) !important;
111
- }
112
-
113
- :is(.toggle, .remove)::part(base) {
114
- padding: var(--sl-spacing-2x-small);
115
- }
116
-
117
- .solution::part(base) {
118
- color: var(--sl-color-success-700);
119
- }
120
-
121
- .toggle {
122
- color: inherit;
123
- }
124
-
125
-
126
- `
127
- @query("ww-combobox")
128
- accessor input: Combobox
129
-
130
- async focus() {
131
- (await this.input).focus()
132
- }
133
-
134
- handleChange = (e: CustomEvent) => {
135
- e.preventDefault()
136
- if(!this.isContentEditable) {
137
- this.value = this.input.value as string
138
- }
139
- }
140
-
141
- addSolution(value: string) {
142
- this.solution = Array.from(new Set([...(this.solution ?? []), value]))
143
- }
144
-
145
- toggleOptionType(value: string) {
146
- if(this.solution.includes(value)) {
147
- this.solution = this.solution.filter(v => v !== value)
148
- this.distraction = Array.from(new Set([...(this.distraction ?? []), value]))
149
- }
150
- else if(this.distraction.includes(value)) {
151
- this.distraction = this.distraction.filter(v => v !== value)
152
- this.solution = Array.from(new Set([...(this.solution ?? []), value]))
153
- }
154
- }
155
-
156
- removeOption(value: string) {
157
- this.solution = this.solution.filter(v => v !== value)
158
- this.distraction = this.distraction.filter(v => v !== value)
159
- if(this.allOptions.length === 0) {
160
- this.isAdding = false
161
- }
162
- }
163
-
164
- handleAddClick = (e: MouseEvent) => {
165
- e.stopImmediatePropagation()
166
- e.preventDefault()
167
- this.addSolution(this.input.value as string)
168
- this.isAdding = true
169
- this.input.value = ""
170
- this.input.open = true
171
- }
172
-
173
- handleToggleClick = (e: MouseEvent, value: string) => {
174
- e.stopImmediatePropagation()
175
- e.preventDefault()
176
- this.toggleOptionType(value)
177
- }
178
-
179
- handleRemoveClick = (e: MouseEvent, value: string) => {
180
- e.stopImmediatePropagation()
181
- e.preventDefault()
182
- this.removeOption(value)
183
- }
184
-
185
- handleKeydown = (e: KeyboardEvent) => {
186
- if(e.key === "Enter") {
187
- this.handleAddClick(e as any)
188
- }
189
- }
190
-
191
- handleBlur = (e: FocusEvent) => {
192
- this.isAdding = false
193
- if(this.solution.length === 1) {
194
- this.input.value = this.solution[0]
195
- }
196
- }
197
-
198
- get allOptions() {
199
- return [...(this.solution ?? []), ...this.distraction]
200
- }
201
-
202
- @property({type: Boolean, attribute: false})
203
- accessor isAdding = false
204
-
205
- render() {
206
- return html`<ww-combobox @blur=${this.handleBlur} ?suggestions=${this.allOptions.length > 1 || this.isAdding || this.distraction.length > 0} size="small" autosize .value=${this.value} @sl-change=${this.handleChange} @sl-input=${() => this.requestUpdate()} @keydown=${this.handleKeydown} >
207
- <sl-icon-button id="add" title="Add another solution" ?disabled=${this.allOptions.includes(this.input?.value as string)} ?data-hidden=${!this.input?.value} src=${IconPlus} size="small" slot="prefix" @click=${this.handleAddClick} @mousedown=${(e: Event) => {e.stopPropagation(); e.preventDefault()}} @focus=${e => e.stopPropagation()} ></sl-icon-button>
208
- ${this.allOptions.sort().map(value => html`
209
- <sl-option size="small" value=${value} class=${this.solution.includes(value)? "solution": "distraction"} >
210
- <sl-icon-button title=${this.solution.includes(value)? "Change to a distraction": "Change to a solution"} class="toggle" slot="prefix" src=${this.solution.includes(value)? IconCheckCircle: IconSlashCircle} @click=${(e: any) => this.handleToggleClick(e, value)} @mousedown=${(e: Event) => {e.stopPropagation(); e.preventDefault()}}></sl-icon-button>
211
- <span title=${this.solution.includes(value)? "Solution": "Distraction"}>${value}</span>
212
- <sl-icon-button title="Remove" class="remove" slot="suffix" src=${IconX} @click=${(e: any) => this.handleRemoveClick(e, value)} @mousedown=${(e: Event) => {e.stopPropagation(); e.preventDefault()}}></sl-icon-button>
213
- </sl-option>
214
- `)}
215
- </ww-combobox>`
216
- }
1
+ import {LitElement, html, css, RenderOptions} from "lit"
2
+ import {LitElementWw} from "@webwriter/lit"
3
+ import {customElement, query} from "lit/decorators.js"
4
+
5
+ import SlIconButton from "@shoelace-style/shoelace/dist/components/icon-button/icon-button.component.js"
6
+ import SlOption from "@shoelace-style/shoelace/dist/components/option/option.component.js"
7
+ import IconPlus from "bootstrap-icons/icons/plus.svg"
8
+ import IconSlashCircle from "bootstrap-icons/icons/slash-circle.svg"
9
+ import IconCheckCircle from "bootstrap-icons/icons/check-circle.svg"
10
+ import IconX from "bootstrap-icons/icons/x.svg"
11
+
12
+ import { Combobox } from "../lib/combobox"
13
+ import { property } from "lit/decorators/property.js"
14
+ import { queryAsync } from "lit/decorators/query-async.js"
15
+ import "@shoelace-style/shoelace/dist/themes/light.css"
16
+
17
+ declare global {interface HTMLElementTagNameMap {
18
+ "webwriter-cloze-gap": WebwriterClozeGap;
19
+ }}
20
+
21
+ @customElement("webwriter-cloze-gap")
22
+ export class WebwriterClozeGap extends LitElementWw {
23
+
24
+ static localization = {}
25
+
26
+ @property({type: Array, attribute: true, reflect: true})
27
+ accessor solution: string[]
28
+
29
+ @property({type: String, attribute: true, reflect: true})
30
+ accessor value: string
31
+
32
+ @property({type: Array, attribute: true, reflect: true})
33
+ accessor distraction: string[] = []
34
+
35
+
36
+ @property({type: Boolean, attribute: true, reflect: true})
37
+ accessor showOptions = false
38
+
39
+ msg = (str: string) => this.lang in WebwriterClozeGap.localization? WebwriterClozeGap.localization[this.lang][str] ?? str: str
40
+
41
+
42
+ static scopedElements = {
43
+ "ww-combobox": Combobox,
44
+ "sl-icon-button": SlIconButton,
45
+ "sl-option": SlOption
46
+ }
47
+
48
+ static styles = css`
49
+ :host {
50
+ display: inline-block !important;
51
+ vertical-align: top;
52
+ margin: 0 1ch;
53
+ max-width: calc(100% - 2ch);
54
+ max-height: 1lh;
55
+ }
56
+
57
+ :host(::after) {
58
+ content: " ";
59
+ display: block;
60
+ }
61
+
62
+ sl-icon-button[data-hidden] {
63
+ visibility: hidden;
64
+ }
65
+
66
+ sl-icon-button::part(base) {
67
+ padding: 0;
68
+ }
69
+
70
+ :host(:not(:focus-within)) #add {
71
+ visibility: hidden;
72
+ }
73
+
74
+ sl-icon-button {
75
+ overflow: visible;
76
+ margin-right: 0;
77
+ }
78
+
79
+ ww-combobox::part(base) {
80
+ min-height: unset;
81
+ padding: 2px 2px;
82
+ }
83
+
84
+ :host(:is([contenteditable=true], [contenteditable=""])) ww-combobox::part(input) {
85
+ color: var(--sl-color-success-700);
86
+ }
87
+
88
+ sl-option::part(base) {
89
+ padding: 0;
90
+ font-size: var(--sl-input-font-size-small);
91
+ }
92
+
93
+ sl-option::part(label) {
94
+ padding: var(--sl-spacing-2x-small) 0;
95
+ }
96
+
97
+ sl-option::part(label):hover {
98
+ color: var(--sl-color-primary-600);
99
+ }
100
+
101
+ sl-option::part(checked-icon) {
102
+ display: none;
103
+ }
104
+
105
+ .remove::part(base):hover {
106
+ color: var(--sl-color-danger-600) !important;
107
+ }
108
+
109
+ .remove::part(base):active {
110
+ color: var(--sl-color-danger-800) !important;
111
+ }
112
+
113
+ :is(.toggle, .remove)::part(base) {
114
+ padding: var(--sl-spacing-2x-small);
115
+ }
116
+
117
+ .solution::part(base) {
118
+ color: var(--sl-color-success-700);
119
+ }
120
+
121
+ .toggle {
122
+ color: inherit;
123
+ }
124
+
125
+
126
+ `
127
+ @query("ww-combobox")
128
+ accessor input: Combobox
129
+
130
+ async focus() {
131
+ (await this.input).focus()
132
+ }
133
+
134
+ handleChange = (e: CustomEvent) => {
135
+ e.preventDefault()
136
+ if(!this.isContentEditable) {
137
+ this.value = this.input.value as string
138
+ }
139
+ }
140
+
141
+ addSolution(value: string) {
142
+ this.solution = Array.from(new Set([...(this.solution ?? []), value]))
143
+ }
144
+
145
+ toggleOptionType(value: string) {
146
+ if(this.solution.includes(value)) {
147
+ this.solution = this.solution.filter(v => v !== value)
148
+ this.distraction = Array.from(new Set([...(this.distraction ?? []), value]))
149
+ }
150
+ else if(this.distraction.includes(value)) {
151
+ this.distraction = this.distraction.filter(v => v !== value)
152
+ this.solution = Array.from(new Set([...(this.solution ?? []), value]))
153
+ }
154
+ }
155
+
156
+ removeOption(value: string) {
157
+ this.solution = this.solution.filter(v => v !== value)
158
+ this.distraction = this.distraction.filter(v => v !== value)
159
+ if(this.allOptions.length === 0) {
160
+ this.isAdding = false
161
+ }
162
+ }
163
+
164
+ handleAddClick = (e: MouseEvent) => {
165
+ e.stopImmediatePropagation()
166
+ e.preventDefault()
167
+ this.addSolution(this.input.value as string)
168
+ this.isAdding = true
169
+ this.input.value = ""
170
+ this.input.open = true
171
+ }
172
+
173
+ handleToggleClick = (e: MouseEvent, value: string) => {
174
+ e.stopImmediatePropagation()
175
+ e.preventDefault()
176
+ this.toggleOptionType(value)
177
+ }
178
+
179
+ handleRemoveClick = (e: MouseEvent, value: string) => {
180
+ e.stopImmediatePropagation()
181
+ e.preventDefault()
182
+ this.removeOption(value)
183
+ }
184
+
185
+ handleKeydown = (e: KeyboardEvent) => {
186
+ if(e.key === "Enter") {
187
+ this.handleAddClick(e as any)
188
+ }
189
+ }
190
+
191
+ handleBlur = (e: FocusEvent) => {
192
+ this.isAdding = false
193
+ if(this.solution.length === 1) {
194
+ this.input.value = this.solution[0]
195
+ }
196
+ }
197
+
198
+ get allOptions() {
199
+ return [...(this.solution ?? []), ...this.distraction]
200
+ }
201
+
202
+ @property({type: Boolean, attribute: false})
203
+ accessor isAdding = false
204
+
205
+ render() {
206
+ return html`<ww-combobox @blur=${this.handleBlur} ?suggestions=${this.allOptions.length > 1 || this.isAdding || this.distraction.length > 0} size="small" autosize .value=${this.value} @sl-change=${this.handleChange} @sl-input=${() => this.requestUpdate()} @keydown=${this.handleKeydown} >
207
+ <sl-icon-button id="add" title="Add another solution" ?disabled=${this.allOptions.includes(this.input?.value as string)} ?data-hidden=${!this.input?.value} src=${IconPlus} size="small" slot="prefix" @click=${this.handleAddClick} @mousedown=${(e: Event) => {e.stopPropagation(); e.preventDefault()}} @focus=${e => e.stopPropagation()} ></sl-icon-button>
208
+ ${this.allOptions.sort().map(value => html`
209
+ <sl-option size="small" value=${value} class=${this.solution.includes(value)? "solution": "distraction"} >
210
+ <sl-icon-button title=${this.solution.includes(value)? "Change to a distraction": "Change to a solution"} class="toggle" slot="prefix" src=${this.solution.includes(value)? IconCheckCircle: IconSlashCircle} @click=${(e: any) => this.handleToggleClick(e, value)} @mousedown=${(e: Event) => {e.stopPropagation(); e.preventDefault()}}></sl-icon-button>
211
+ <span title=${this.solution.includes(value)? "Solution": "Distraction"}>${value}</span>
212
+ <sl-icon-button title="Remove" class="remove" slot="suffix" src=${IconX} @click=${(e: any) => this.handleRemoveClick(e, value)} @mousedown=${(e: Event) => {e.stopPropagation(); e.preventDefault()}}></sl-icon-button>
213
+ </sl-option>
214
+ `)}
215
+ </ww-combobox>`
216
+ }
217
217
  }