@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,8 +1,8 @@
1
- <webwriter-task>
2
- <webwriter-task-prompt slot="prompt"><p></p></webwriter-task-prompt>
3
- <webwriter-choice>
4
- <webwriter-choice-item>
5
- <p></p>
6
- </webwriter-choice-item>
7
- </webwriter-choice>
1
+ <webwriter-task>
2
+ <webwriter-task-prompt slot="prompt"><p></p></webwriter-task-prompt>
3
+ <webwriter-choice>
4
+ <webwriter-choice-item>
5
+ <p></p>
6
+ </webwriter-choice-item>
7
+ </webwriter-choice>
8
8
  </webwriter-task>
@@ -1,4 +1,4 @@
1
- <webwriter-task>
2
- <webwriter-task-prompt slot="prompt"><p></p></webwriter-task-prompt>
3
- <webwriter-cloze><p></p></webwriter-cloze>
1
+ <webwriter-task>
2
+ <webwriter-task-prompt slot="prompt"><p></p></webwriter-task-prompt>
3
+ <webwriter-cloze><p></p></webwriter-cloze>
4
4
  </webwriter-task>
@@ -1,4 +1,4 @@
1
- <webwriter-task>
2
- <webwriter-task-prompt slot="prompt"><p></p></webwriter-task-prompt>
3
- <webwriter-mark><p></p></webwriter-mark>
1
+ <webwriter-task>
2
+ <webwriter-task-prompt slot="prompt"><p></p></webwriter-task-prompt>
3
+ <webwriter-mark><p></p></webwriter-mark>
4
4
  </webwriter-task>
@@ -1,8 +1,8 @@
1
- <webwriter-task>
2
- <webwriter-task-prompt slot="prompt"><p></p></webwriter-task-prompt>
3
- <webwriter-order>
4
- <webwriter-order-item>
5
- <p></p>
6
- </webwriter-order-item>
7
- </webwriter-order>
1
+ <webwriter-task>
2
+ <webwriter-task-prompt slot="prompt"><p></p></webwriter-task-prompt>
3
+ <webwriter-order>
4
+ <webwriter-order-item>
5
+ <p></p>
6
+ </webwriter-order-item>
7
+ </webwriter-order>
8
8
  </webwriter-task>
@@ -1,10 +1,10 @@
1
- <webwriter-task>
2
- <webwriter-task-prompt slot="prompt"><p></p></webwriter-task-prompt>
3
- <webwriter-pairing>
4
- <webwriter-pairing-item>
5
- <picture>
6
- <img>
7
- </picture>
8
- </webwriter-pairing-item>
9
- </webwriter-pairing>
1
+ <webwriter-task>
2
+ <webwriter-task-prompt slot="prompt"><p></p></webwriter-task-prompt>
3
+ <webwriter-pairing>
4
+ <webwriter-pairing-item>
5
+ <picture>
6
+ <img>
7
+ </picture>
8
+ </webwriter-pairing-item>
9
+ </webwriter-pairing>
10
10
  </webwriter-task>
@@ -1,4 +1,4 @@
1
- <webwriter-task>
2
- <webwriter-task-prompt slot="prompt"><p></p></webwriter-task-prompt>
3
- <webwriter-speech></webwriter-speech>
1
+ <webwriter-task>
2
+ <webwriter-task-prompt slot="prompt"><p></p></webwriter-task-prompt>
3
+ <webwriter-speech></webwriter-speech>
4
4
  </webwriter-task>
@@ -1,4 +1,4 @@
1
- <webwriter-task>
2
- <webwriter-task-prompt slot="prompt"><p></p></webwriter-task-prompt>
3
- <webwriter-text></webwriter-text>
1
+ <webwriter-task>
2
+ <webwriter-task-prompt slot="prompt"><p></p></webwriter-task-prompt>
3
+ <webwriter-text></webwriter-text>
4
4
  </webwriter-task>
@@ -1,4 +1,4 @@
1
- <webwriter-task>
2
- <webwriter-task-prompt slot="prompt"><p></p></webwriter-task-prompt>
3
- <webwriter-wordsearch></webwriter-wordsearch>
1
+ <webwriter-task>
2
+ <webwriter-task-prompt slot="prompt"><p></p></webwriter-task-prompt>
3
+ <webwriter-wordsearch></webwriter-wordsearch>
4
4
  </webwriter-task>
@@ -1,251 +1,251 @@
1
- import {css, html, PropertyValues} from "lit"
2
- import {styleMap} from "lit/directives/style-map.js"
3
- import {classMap} from "lit/directives/class-map.js"
4
- import {unsafeStatic} from "lit/static-html.js"
5
- import {LitElementWw} from "@webwriter/lit"
6
- import {customElement, property, query} from "lit/decorators.js"
7
-
8
- import SlRadio from "@shoelace-style/shoelace/dist/components/radio/radio.component.js"
9
- import SlCheckbox from "@shoelace-style/shoelace/dist/components/checkbox/checkbox.component.js"
10
- import SlIcon from "@shoelace-style/shoelace/dist/components/icon/icon.component.js"
11
- import "@shoelace-style/shoelace/dist/themes/light.css"
12
- import { keyed } from "lit/directives/keyed.js"
13
- import IconX from "bootstrap-icons/icons/x.svg"
14
- import IconCheck from "bootstrap-icons/icons/check.svg"
15
-
16
-
17
- declare global {interface HTMLElementTagNameMap {
18
- "webwriter-choice-item": WebwriterChoiceItem;
19
- }}
20
-
21
- @customElement("webwriter-choice-item")
22
- export class WebwriterChoiceItem extends LitElementWw {
23
-
24
- static localization = {}
25
-
26
- msg = (str: string) => this.lang in WebwriterChoiceItem.localization? WebwriterChoiceItem.localization[this.lang][str] ?? str: str
27
-
28
- @property({type: Boolean, attribute: false})
29
- accessor active = false
30
-
31
- @property({type: Boolean, attribute: false})
32
- accessor valid: true | false | undefined
33
-
34
- // inactive + invalid/no validity -> nothing
35
- // active + no validity -> blue circle
36
- // inactive/active + valid -> green upper checkmark
37
- // active + invalid -> red upper cross
38
-
39
-
40
- @property({type: String, attribute: true, reflect: true})
41
- accessor layout: "list" | "tiles" = "list"
42
-
43
- static scopedElements = {
44
- "sl-radio": SlRadio,
45
- "sl-checkbox": SlCheckbox,
46
- "sl-icon": SlIcon
47
- }
48
-
49
- static styles = css`
50
-
51
- :host {
52
- width: 100%;
53
- position: relative;
54
- }
55
-
56
- :host(:not([contenteditable=true]):not([contenteditable=""])) .author-only {
57
- display: none;
58
- }
59
-
60
- :host(:is([contenteditable=true], [contenteditable=""])) .user-only {
61
- display: none;
62
- }
63
-
64
- :host(:is([contenteditable=true], [contenteditable=""])) sl-checkbox.valid {
65
- --webwriter-control-color-600: var(--sl-color-success-600);
66
- --webwriter-control-color-400: var(--sl-color-success-400);
67
- }
68
-
69
- sl-checkbox {
70
- display: block;
71
- width: 100%;
72
- &::part(base) {
73
- width: 100%;
74
- display: flex;
75
- flex-direction: row;
76
- align-items: center;
77
- cursor: unset;
78
- }
79
-
80
- &::part(control) {
81
- cursor: pointer;
82
- border-radius: var(--webwriter-choice-radius, 2px);
83
- border-width: 2px;
84
- }
85
-
86
- &::part(control):not(:hover){
87
- border-color: var(--sl-color-gray-500);
88
- }
89
-
90
- &::part(control):hover {
91
- border-color: var(--sl-color-gray-700);
92
- }
93
-
94
- &::part(control--checked):not(:hover) {
95
- background-color: var(--webwriter-control-color-600, var(--sl-color-primary-600));
96
- border-color: var(--sl-color-gray-500);
97
- }
98
- &::part(control--checked):hover {
99
- background-color: var(--webwriter-control-color-400, var(--sl-color-primary-400));
100
- border-color: var(--webwriter-control-color-600, var(--sl-color-primary-600));
101
- }
102
-
103
- &::part(label) {
104
- width: 100%;
105
- }
106
- }
107
-
108
- .solution {
109
- position: absolute;
110
- top: -6px;
111
- left: -6px;
112
- border: 2px solid var(--sl-color-gray-500);
113
- border-radius: var(--webwriter-choice-radius, 2px);
114
- width: 12px;
115
- height: 12px;
116
- z-index: 1;
117
- color: white;
118
-
119
- &[data-valid] {
120
- background: var(--sl-color-success-600);
121
- }
122
-
123
- &:not([data-valid]) {
124
- background: var(--sl-color-danger-600);
125
- }
126
- }
127
-
128
- :host([layout=tiles]) {
129
- position: relative;
130
- overflow: visible !important;
131
-
132
- & ::slotted(:is(picture, audio, video, img, iframe)) {
133
- height: 100%;
134
- width: 100%;
135
- }
136
-
137
- & ::slotted(:not(:is(picture, audio, video, img, iframe))) {
138
- margin: 5px !important;
139
- }
140
-
141
- sl-checkbox {
142
- display: block;
143
- &::part(base) {
144
- display: flex;
145
- flex-direction: row;
146
- align-items: center;
147
- cursor: unset;
148
- position: static;
149
- }
150
-
151
- &::part(control) {
152
- position: absolute;
153
- bottom: -10px;
154
- left: -10px;
155
- cursor: pointer;
156
- border-radius: var(--webwriter-choice-radius, 2px);
157
- z-index: 100;
158
- border-color: var(--sl-color-gray-500);
159
- }
160
-
161
- &::part(control--checked):not(:hover) {
162
- background-color: var(--webwriter-control-color-600, var(--sl-color-primary-600));
163
- border-color: var(--sl-color-gray-500);
164
- }
165
- &::part(control--checked):hover {
166
- background-color: var(--webwriter-control-color-400, var(--sl-color-primary-400));
167
- border-color: var(--webwriter-control-color-600, var(--sl-color-primary-600));
168
- }
169
-
170
- &::part(label) {
171
- aspect-ratio: 1;
172
- min-width: 125px;
173
- max-width: 350px;
174
- min-height: 125px;
175
- max-height: 350px;
176
- overflow: hidden;
177
- resize: both;
178
- margin-inline-start: 0;
179
- overflow-y: auto;
180
- scrollbar-width: thin;
181
- }
182
- }
183
- }
184
- `
185
-
186
- handleClick = (e: PointerEvent) => {
187
- const checkboxClicked = e.composedPath().some(v => (v as HTMLElement)?.classList?.contains("checkbox__control"))
188
- const editable = this.isContentEditable
189
- if(editable && !checkboxClicked) {
190
- e.preventDefault()
191
- }
192
- else {
193
- e.stopImmediatePropagation()
194
- }
195
- }
196
-
197
- handleChange = (e: CustomEvent) => {
198
- if(this.isContentEditable) {
199
- this.valid = !this.valid
200
- }
201
- else {
202
- this.active = !this.active
203
- }
204
- }
205
-
206
- @query("sl-checkbox")
207
- accessor checkbox: SlCheckbox
208
-
209
- observer: MutationObserver
210
-
211
- protected async updated(_changedProperties: PropertyValues) {
212
- await this.checkbox.updateComplete
213
- const labelEl = this.checkbox.shadowRoot.querySelector(".checkbox__label") as HTMLElement
214
-
215
- if(_changedProperties.has("layout") && this.layout === "list") {
216
- this.syncSize(true)
217
- this.observer?.disconnect()
218
- }
219
- else if(_changedProperties.has("layout") && this.layout === "tiles") {
220
- this.syncSize()
221
- this.observer = new MutationObserver(() => this.syncSize())
222
- this.observer.observe(labelEl, {attributeFilter: ["style"], attributes: true})
223
- }
224
- }
225
-
226
- syncSize(clear=false) {
227
- const labelEl = this.checkbox?.shadowRoot.querySelector(".checkbox__label") as HTMLElement
228
- if(labelEl && !clear) {
229
- this.style.width = labelEl.style.width
230
- this.style.height = labelEl.style.height
231
- }
232
- else if(labelEl && clear) {
233
- this.style.width = labelEl.style.width = null
234
- this.style.height = labelEl.style.height = null
235
- }
236
- }
237
-
238
- disconnectedCallback(): void {
239
- super.disconnectedCallback()
240
- this.observer?.disconnect()
241
- }
242
-
243
- render() {
244
- return keyed(this.layout, html`
245
- ${this.valid !== undefined && (this.active || !this.active && this.valid)? html`<sl-icon class="solution user-only" ?data-valid=${this.valid} src=${this.valid? IconCheck: IconX}></sl-icon>`: null}
246
- <sl-checkbox class=${classMap({valid: this.valid, active: this.active})} exportparts="base, control, label" @click=${this.handleClick} @sl-change=${this.handleChange} ?checked=${this.isContentEditable? this.valid: this.active}>
247
- <slot part="slot" style=${styleMap({"--ww-placeholder": `"${this.msg("Option")}"`})}></slot>
248
- </sl-checkbox>
249
- `)
250
- }
1
+ import {css, html, PropertyValues} from "lit"
2
+ import {styleMap} from "lit/directives/style-map.js"
3
+ import {classMap} from "lit/directives/class-map.js"
4
+ import {unsafeStatic} from "lit/static-html.js"
5
+ import {LitElementWw} from "@webwriter/lit"
6
+ import {customElement, property, query} from "lit/decorators.js"
7
+
8
+ import SlRadio from "@shoelace-style/shoelace/dist/components/radio/radio.component.js"
9
+ import SlCheckbox from "@shoelace-style/shoelace/dist/components/checkbox/checkbox.component.js"
10
+ import SlIcon from "@shoelace-style/shoelace/dist/components/icon/icon.component.js"
11
+ import "@shoelace-style/shoelace/dist/themes/light.css"
12
+ import { keyed } from "lit/directives/keyed.js"
13
+ import IconX from "bootstrap-icons/icons/x.svg"
14
+ import IconCheck from "bootstrap-icons/icons/check.svg"
15
+
16
+
17
+ declare global {interface HTMLElementTagNameMap {
18
+ "webwriter-choice-item": WebwriterChoiceItem;
19
+ }}
20
+
21
+ @customElement("webwriter-choice-item")
22
+ export class WebwriterChoiceItem extends LitElementWw {
23
+
24
+ static localization = {}
25
+
26
+ msg = (str: string) => this.lang in WebwriterChoiceItem.localization? WebwriterChoiceItem.localization[this.lang][str] ?? str: str
27
+
28
+ @property({type: Boolean, attribute: false})
29
+ accessor active = false
30
+
31
+ @property({type: Boolean, attribute: false})
32
+ accessor valid: true | false | undefined
33
+
34
+ // inactive + invalid/no validity -> nothing
35
+ // active + no validity -> blue circle
36
+ // inactive/active + valid -> green upper checkmark
37
+ // active + invalid -> red upper cross
38
+
39
+
40
+ @property({type: String, attribute: true, reflect: true})
41
+ accessor layout: "list" | "tiles" = "list"
42
+
43
+ static scopedElements = {
44
+ "sl-radio": SlRadio,
45
+ "sl-checkbox": SlCheckbox,
46
+ "sl-icon": SlIcon
47
+ }
48
+
49
+ static styles = css`
50
+
51
+ :host {
52
+ width: 100%;
53
+ position: relative;
54
+ }
55
+
56
+ :host(:not([contenteditable=true]):not([contenteditable=""])) .author-only {
57
+ display: none;
58
+ }
59
+
60
+ :host(:is([contenteditable=true], [contenteditable=""])) .user-only {
61
+ display: none;
62
+ }
63
+
64
+ :host(:is([contenteditable=true], [contenteditable=""])) sl-checkbox.valid {
65
+ --webwriter-control-color-600: var(--sl-color-success-600);
66
+ --webwriter-control-color-400: var(--sl-color-success-400);
67
+ }
68
+
69
+ sl-checkbox {
70
+ display: block;
71
+ width: 100%;
72
+ &::part(base) {
73
+ width: 100%;
74
+ display: flex;
75
+ flex-direction: row;
76
+ align-items: center;
77
+ cursor: unset;
78
+ }
79
+
80
+ &::part(control) {
81
+ cursor: pointer;
82
+ border-radius: var(--webwriter-choice-radius, 2px);
83
+ border-width: 2px;
84
+ }
85
+
86
+ &::part(control):not(:hover){
87
+ border-color: var(--sl-color-gray-500);
88
+ }
89
+
90
+ &::part(control):hover {
91
+ border-color: var(--sl-color-gray-700);
92
+ }
93
+
94
+ &::part(control--checked):not(:hover) {
95
+ background-color: var(--webwriter-control-color-600, var(--sl-color-primary-600));
96
+ border-color: var(--sl-color-gray-500);
97
+ }
98
+ &::part(control--checked):hover {
99
+ background-color: var(--webwriter-control-color-400, var(--sl-color-primary-400));
100
+ border-color: var(--webwriter-control-color-600, var(--sl-color-primary-600));
101
+ }
102
+
103
+ &::part(label) {
104
+ width: 100%;
105
+ }
106
+ }
107
+
108
+ .solution {
109
+ position: absolute;
110
+ top: -6px;
111
+ left: -6px;
112
+ border: 2px solid var(--sl-color-gray-500);
113
+ border-radius: var(--webwriter-choice-radius, 2px);
114
+ width: 12px;
115
+ height: 12px;
116
+ z-index: 1;
117
+ color: white;
118
+
119
+ &[data-valid] {
120
+ background: var(--sl-color-success-600);
121
+ }
122
+
123
+ &:not([data-valid]) {
124
+ background: var(--sl-color-danger-600);
125
+ }
126
+ }
127
+
128
+ :host([layout=tiles]) {
129
+ position: relative;
130
+ overflow: visible !important;
131
+
132
+ & ::slotted(:is(picture, audio, video, img, iframe)) {
133
+ height: 100%;
134
+ width: 100%;
135
+ }
136
+
137
+ & ::slotted(:not(:is(picture, audio, video, img, iframe))) {
138
+ margin: 5px !important;
139
+ }
140
+
141
+ sl-checkbox {
142
+ display: block;
143
+ &::part(base) {
144
+ display: flex;
145
+ flex-direction: row;
146
+ align-items: center;
147
+ cursor: unset;
148
+ position: static;
149
+ }
150
+
151
+ &::part(control) {
152
+ position: absolute;
153
+ bottom: -10px;
154
+ left: -10px;
155
+ cursor: pointer;
156
+ border-radius: var(--webwriter-choice-radius, 2px);
157
+ z-index: 100;
158
+ border-color: var(--sl-color-gray-500);
159
+ }
160
+
161
+ &::part(control--checked):not(:hover) {
162
+ background-color: var(--webwriter-control-color-600, var(--sl-color-primary-600));
163
+ border-color: var(--sl-color-gray-500);
164
+ }
165
+ &::part(control--checked):hover {
166
+ background-color: var(--webwriter-control-color-400, var(--sl-color-primary-400));
167
+ border-color: var(--webwriter-control-color-600, var(--sl-color-primary-600));
168
+ }
169
+
170
+ &::part(label) {
171
+ aspect-ratio: 1;
172
+ min-width: 125px;
173
+ max-width: 350px;
174
+ min-height: 125px;
175
+ max-height: 350px;
176
+ overflow: hidden;
177
+ resize: both;
178
+ margin-inline-start: 0;
179
+ overflow-y: auto;
180
+ scrollbar-width: thin;
181
+ }
182
+ }
183
+ }
184
+ `
185
+
186
+ handleClick = (e: PointerEvent) => {
187
+ const checkboxClicked = e.composedPath().some(v => (v as HTMLElement)?.classList?.contains("checkbox__control"))
188
+ const editable = this.isContentEditable
189
+ if(editable && !checkboxClicked) {
190
+ e.preventDefault()
191
+ }
192
+ else {
193
+ e.stopImmediatePropagation()
194
+ }
195
+ }
196
+
197
+ handleChange = (e: CustomEvent) => {
198
+ if(this.isContentEditable) {
199
+ this.valid = !this.valid
200
+ }
201
+ else {
202
+ this.active = !this.active
203
+ }
204
+ }
205
+
206
+ @query("sl-checkbox")
207
+ accessor checkbox: SlCheckbox
208
+
209
+ observer: MutationObserver
210
+
211
+ protected async updated(_changedProperties: PropertyValues) {
212
+ await this.checkbox.updateComplete
213
+ const labelEl = this.checkbox.shadowRoot.querySelector(".checkbox__label") as HTMLElement
214
+
215
+ if(_changedProperties.has("layout") && this.layout === "list") {
216
+ this.syncSize(true)
217
+ this.observer?.disconnect()
218
+ }
219
+ else if(_changedProperties.has("layout") && this.layout === "tiles") {
220
+ this.syncSize()
221
+ this.observer = new MutationObserver(() => this.syncSize())
222
+ this.observer.observe(labelEl, {attributeFilter: ["style"], attributes: true})
223
+ }
224
+ }
225
+
226
+ syncSize(clear=false) {
227
+ const labelEl = this.checkbox?.shadowRoot.querySelector(".checkbox__label") as HTMLElement
228
+ if(labelEl && !clear) {
229
+ this.style.width = labelEl.style.width
230
+ this.style.height = labelEl.style.height
231
+ }
232
+ else if(labelEl && clear) {
233
+ this.style.width = labelEl.style.width = null
234
+ this.style.height = labelEl.style.height = null
235
+ }
236
+ }
237
+
238
+ disconnectedCallback(): void {
239
+ super.disconnectedCallback()
240
+ this.observer?.disconnect()
241
+ }
242
+
243
+ render() {
244
+ return keyed(this.layout, html`
245
+ ${this.valid !== undefined && (this.active || !this.active && this.valid)? html`<sl-icon class="solution user-only" ?data-valid=${this.valid} src=${this.valid? IconCheck: IconX}></sl-icon>`: null}
246
+ <sl-checkbox class=${classMap({valid: this.valid, active: this.active})} exportparts="base, control, label" @click=${this.handleClick} @sl-change=${this.handleChange} ?checked=${this.isContentEditable? this.valid: this.active}>
247
+ <slot part="slot" style=${styleMap({"--ww-placeholder": `"${this.msg("Option")}"`})}></slot>
248
+ </sl-checkbox>
249
+ `)
250
+ }
251
251
  }