@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,188 +1,188 @@
1
- import {html, css, PropertyValues} from "lit"
2
- import {LitElementWw, option} from "@webwriter/lit"
3
- import {customElement, property, queryAll} from "lit/decorators.js"
4
- import "@shoelace-style/shoelace/dist/themes/light.css"
5
-
6
- import IconPlus from "bootstrap-icons/icons/plus.svg"
7
- import SlButton from "@shoelace-style/shoelace/dist/components/button/button.component.js"
8
- import SlIcon from "@shoelace-style/shoelace/dist/components/icon/icon.component.js"
9
- import { WebwriterPairingItem } from "./webwriter-pairing-item"
10
-
11
- declare global {interface HTMLElementTagNameMap {
12
- "webwriter-pairing": WebwriterPairing;
13
- }}
14
-
15
- @customElement("webwriter-pairing")
16
- export class WebwriterPairing extends LitElementWw {
17
-
18
- static shadowRootOptions = {...LitElementWw.shadowRootOptions, slotAssignment: "manual" as const}
19
-
20
- static scopedElements = {
21
- "sl-button": SlButton,
22
- "sl-icon": SlIcon
23
- }
24
-
25
- static styles = css`
26
- :host {
27
- display: flex !important;
28
- flex-direction: row;
29
- flex-wrap: wrap;
30
- gap: 30px;
31
- padding-bottom: 30px;
32
- }
33
-
34
- sl-button {
35
-
36
- &::part(base) {
37
- width: 125px;
38
- height: 125px;
39
- border: 1px solid darkgray;
40
- border-radius: 2px;
41
- padding: 10px;
42
- overflow: hidden;
43
- }
44
-
45
- &::part(label) {
46
- padding: 0;
47
- display: flex;
48
- flex-direction: row;
49
- align-items: center;
50
- justify-content: center;
51
- }
52
- }
53
-
54
- .pair {
55
- position: relative;
56
-
57
- & .a-slot, & .b-slot {
58
- display: block;
59
-
60
- &:is(:focus-within, :has(::selection)) {
61
- background: green;
62
- }
63
- }
64
-
65
- & .b-slot {
66
- position: absolute;
67
- left: 20px;
68
- top: 20px;
69
- z-index: 1000;
70
- }
71
- }
72
-
73
- `
74
-
75
- @property({attribute: true, reflect: true})
76
- @option({type: "select", options: [
77
- {value: "drag"},
78
- {value: "memory"}
79
- ]})
80
- accessor mode: "drag" | "memory" = "drag"
81
-
82
- @property({type: Array, attribute: true, reflect: true})
83
- accessor solution: ([string, string] | string)[] = []
84
-
85
- addItem = () => {
86
- const item = document.createElement("webwriter-pairing-item")
87
- const picture = document.createElement("picture")
88
- item.appendChild(picture)
89
- this.appendChild(item)
90
- }
91
-
92
- Pair = (i: number) => {
93
- return html`<div class="pair">
94
- <slot class="a-slot" name=${`${i}a`}></slot>
95
- <slot class="b-slot" name=${`${i}b`}></slot>
96
- </div>`
97
- }
98
-
99
- getPairSlot() {}
100
-
101
-
102
- get pairs() {
103
- let allPairs = Array.from(this.children) as (WebwriterPairingItem | [WebwriterPairingItem, WebwriterPairingItem])[]
104
- for(const [a, b] of this.solution) {
105
- const elA = this.querySelector(`webwriter-pairing-item#${a}`) as WebwriterPairingItem
106
- const elB = this.querySelector(`webwriter-pairing-item#${b}`) as WebwriterPairingItem
107
- allPairs.splice(allPairs.indexOf(elA), 1, [elA, elB])
108
- allPairs.splice(allPairs.indexOf(elB), 1)
109
- }
110
- return allPairs
111
- }
112
-
113
- pair(a: string, b?: string) {
114
- let pairIds = this.pairs.map(entry => Array.isArray(entry)? [entry[0].id, entry[1].id]: entry.id)
115
- const pairIndexOfA = this.solution.findIndex(val => Array.isArray(val) && val.includes(a))
116
- const pairIndexOfB = this.solution.findIndex(val => Array.isArray(val) && val.includes(b))
117
- if(!b) {
118
- pairIds.splice(pairIndexOfA, 1, (pairIds[pairIndexOfA] as [string, string]).filter(id => id !== a)[0])
119
- pairIds.push(a)
120
- }
121
- else {
122
- if(pairIndexOfB !== -1) {
123
- pairIds.splice(pairIndexOfB, 1, (pairIds[pairIndexOfB] as [string, string]).filter(id => id !== b)[0])
124
- }
125
- const indexOfA = this.solution.indexOf(a)
126
- pairIds.splice(indexOfA, 1, [a, b])
127
- pairIds = pairIds.filter(id => id !== b)
128
- }
129
- this.solution = pairIds.filter(entry => Array.isArray(entry)) as any
130
- }
131
-
132
- handlePairWith(e: CustomEvent) {
133
- if(e.type === "ww-pairwith") {
134
- this.pair((e.target as HTMLElement).id, e.detail.with)
135
- }
136
- }
137
-
138
- observer: MutationObserver
139
-
140
- connectedCallback(): void {
141
- super.connectedCallback()
142
- this.observer = new MutationObserver(() => {
143
- let childIds = Array.from(this.children).map(child => child.id)
144
- let solution = [...this.solution]
145
- // solution = solution.filter(k => childIds.includes(k as any))
146
- // solution = [...solution, ...childIds]
147
- this.requestUpdate()
148
- })
149
- this.observer.observe(this, {childList: true})
150
- this.addEventListener("ww-pairwith", this.handlePairWith)
151
- }
152
-
153
- disconnectedCallback(): void {
154
- super.disconnectedCallback()
155
- this.observer.disconnect()
156
- }
157
-
158
- protected willUpdate(_changedProperties: PropertyValues): void {
159
- // this.solution = this.solution.filter(id => childIds.includes(id))
160
- }
161
-
162
- protected updated(_changedProperties: PropertyValues): void {
163
- const slots = Array.from(this.slots)
164
- for(const value of this.pairs) {
165
- if(Array.isArray(value)) {
166
- const [a, b] = value
167
- slots.shift().assign(a)
168
- slots.shift().assign(b)
169
- }
170
- else {
171
- slots.shift().assign(value)
172
- slots.shift()
173
- }
174
- }
175
- }
176
-
177
- @queryAll("slot")
178
- accessor slots: NodeListOf<HTMLSlotElement>
179
-
180
- render() {
181
- return html`
182
- ${this.pairs.map((el, i) => this.Pair(i))}
183
- <sl-button @click=${this.addItem}>
184
- <sl-icon src=${IconPlus}></sl-icon>
185
- </sl-button>
186
- `
187
- }
1
+ import {html, css, PropertyValues} from "lit"
2
+ import {LitElementWw, option} from "@webwriter/lit"
3
+ import {customElement, property, queryAll} from "lit/decorators.js"
4
+ import "@shoelace-style/shoelace/dist/themes/light.css"
5
+
6
+ import IconPlus from "bootstrap-icons/icons/plus.svg"
7
+ import SlButton from "@shoelace-style/shoelace/dist/components/button/button.component.js"
8
+ import SlIcon from "@shoelace-style/shoelace/dist/components/icon/icon.component.js"
9
+ import { WebwriterPairingItem } from "./webwriter-pairing-item"
10
+
11
+ declare global {interface HTMLElementTagNameMap {
12
+ "webwriter-pairing": WebwriterPairing;
13
+ }}
14
+
15
+ @customElement("webwriter-pairing")
16
+ export class WebwriterPairing extends LitElementWw {
17
+
18
+ static shadowRootOptions = {...LitElementWw.shadowRootOptions, slotAssignment: "manual" as const}
19
+
20
+ static scopedElements = {
21
+ "sl-button": SlButton,
22
+ "sl-icon": SlIcon
23
+ }
24
+
25
+ static styles = css`
26
+ :host {
27
+ display: flex !important;
28
+ flex-direction: row;
29
+ flex-wrap: wrap;
30
+ gap: 30px;
31
+ padding-bottom: 30px;
32
+ }
33
+
34
+ sl-button {
35
+
36
+ &::part(base) {
37
+ width: 125px;
38
+ height: 125px;
39
+ border: 1px solid darkgray;
40
+ border-radius: 2px;
41
+ padding: 10px;
42
+ overflow: hidden;
43
+ }
44
+
45
+ &::part(label) {
46
+ padding: 0;
47
+ display: flex;
48
+ flex-direction: row;
49
+ align-items: center;
50
+ justify-content: center;
51
+ }
52
+ }
53
+
54
+ .pair {
55
+ position: relative;
56
+
57
+ & .a-slot, & .b-slot {
58
+ display: block;
59
+
60
+ &:is(:focus-within, :has(::selection)) {
61
+ background: green;
62
+ }
63
+ }
64
+
65
+ & .b-slot {
66
+ position: absolute;
67
+ left: 20px;
68
+ top: 20px;
69
+ z-index: 1000;
70
+ }
71
+ }
72
+
73
+ `
74
+
75
+ @property({attribute: true, reflect: true})
76
+ @option({type: "select", options: [
77
+ {value: "drag"},
78
+ {value: "memory"}
79
+ ]})
80
+ accessor mode: "drag" | "memory" = "drag"
81
+
82
+ @property({type: Array, attribute: true, reflect: true})
83
+ accessor solution: ([string, string] | string)[] = []
84
+
85
+ addItem = () => {
86
+ const item = document.createElement("webwriter-pairing-item")
87
+ const picture = document.createElement("picture")
88
+ item.appendChild(picture)
89
+ this.appendChild(item)
90
+ }
91
+
92
+ Pair = (i: number) => {
93
+ return html`<div class="pair">
94
+ <slot class="a-slot" name=${`${i}a`}></slot>
95
+ <slot class="b-slot" name=${`${i}b`}></slot>
96
+ </div>`
97
+ }
98
+
99
+ getPairSlot() {}
100
+
101
+
102
+ get pairs() {
103
+ let allPairs = Array.from(this.children) as (WebwriterPairingItem | [WebwriterPairingItem, WebwriterPairingItem])[]
104
+ for(const [a, b] of this.solution) {
105
+ const elA = this.querySelector(`webwriter-pairing-item#${a}`) as WebwriterPairingItem
106
+ const elB = this.querySelector(`webwriter-pairing-item#${b}`) as WebwriterPairingItem
107
+ allPairs.splice(allPairs.indexOf(elA), 1, [elA, elB])
108
+ allPairs.splice(allPairs.indexOf(elB), 1)
109
+ }
110
+ return allPairs
111
+ }
112
+
113
+ pair(a: string, b?: string) {
114
+ let pairIds = this.pairs.map(entry => Array.isArray(entry)? [entry[0].id, entry[1].id]: entry.id)
115
+ const pairIndexOfA = this.solution.findIndex(val => Array.isArray(val) && val.includes(a))
116
+ const pairIndexOfB = this.solution.findIndex(val => Array.isArray(val) && val.includes(b))
117
+ if(!b) {
118
+ pairIds.splice(pairIndexOfA, 1, (pairIds[pairIndexOfA] as [string, string]).filter(id => id !== a)[0])
119
+ pairIds.push(a)
120
+ }
121
+ else {
122
+ if(pairIndexOfB !== -1) {
123
+ pairIds.splice(pairIndexOfB, 1, (pairIds[pairIndexOfB] as [string, string]).filter(id => id !== b)[0])
124
+ }
125
+ const indexOfA = this.solution.indexOf(a)
126
+ pairIds.splice(indexOfA, 1, [a, b])
127
+ pairIds = pairIds.filter(id => id !== b)
128
+ }
129
+ this.solution = pairIds.filter(entry => Array.isArray(entry)) as any
130
+ }
131
+
132
+ handlePairWith(e: CustomEvent) {
133
+ if(e.type === "ww-pairwith") {
134
+ this.pair((e.target as HTMLElement).id, e.detail.with)
135
+ }
136
+ }
137
+
138
+ observer: MutationObserver
139
+
140
+ connectedCallback(): void {
141
+ super.connectedCallback()
142
+ this.observer = new MutationObserver(() => {
143
+ let childIds = Array.from(this.children).map(child => child.id)
144
+ let solution = [...this.solution]
145
+ // solution = solution.filter(k => childIds.includes(k as any))
146
+ // solution = [...solution, ...childIds]
147
+ this.requestUpdate()
148
+ })
149
+ this.observer.observe(this, {childList: true})
150
+ this.addEventListener("ww-pairwith", this.handlePairWith)
151
+ }
152
+
153
+ disconnectedCallback(): void {
154
+ super.disconnectedCallback()
155
+ this.observer.disconnect()
156
+ }
157
+
158
+ protected willUpdate(_changedProperties: PropertyValues): void {
159
+ // this.solution = this.solution.filter(id => childIds.includes(id))
160
+ }
161
+
162
+ protected updated(_changedProperties: PropertyValues): void {
163
+ const slots = Array.from(this.slots)
164
+ for(const value of this.pairs) {
165
+ if(Array.isArray(value)) {
166
+ const [a, b] = value
167
+ slots.shift().assign(a)
168
+ slots.shift().assign(b)
169
+ }
170
+ else {
171
+ slots.shift().assign(value)
172
+ slots.shift()
173
+ }
174
+ }
175
+ }
176
+
177
+ @queryAll("slot")
178
+ accessor slots: NodeListOf<HTMLSlotElement>
179
+
180
+ render() {
181
+ return html`
182
+ ${this.pairs.map((el, i) => this.Pair(i))}
183
+ <sl-button @click=${this.addItem}>
184
+ <sl-icon src=${IconPlus}></sl-icon>
185
+ </sl-button>
186
+ `
187
+ }
188
188
  }