import {css, html, PropertyValues} from "lit"
import {styleMap} from "lit/directives/style-map.js"
import {classMap} from "lit/directives/class-map.js"
import {unsafeStatic} from "lit/static-html.js"
import {LitElementWw} from "@webwriter/lit"
import {customElement, property, query} from "lit/decorators.js"
import SlRadio from "@shoelace-style/shoelace/dist/components/radio/radio.component.js"
import SlCheckbox from "@shoelace-style/shoelace/dist/components/checkbox/checkbox.component.js"
import SlIcon from "@shoelace-style/shoelace/dist/components/icon/icon.component.js"
import "@shoelace-style/shoelace/dist/themes/light.css"
import { keyed } from "lit/directives/keyed.js"
import IconX from "bootstrap-icons/icons/x.svg"
import IconCheck from "bootstrap-icons/icons/check.svg"
import LOCALIZE from "../../localization/generated"
import {msg} from "@lit/localize"
declare global {interface HTMLElementTagNameMap {
"webwriter-choice-item": WebwriterChoiceItem;
}}
@customElement("webwriter-choice-item")
export class WebwriterChoiceItem extends LitElementWw {
localize = LOCALIZE
@property({type: Boolean, attribute: false})
accessor showSolution = true
@property({type: Boolean, attribute: false})
accessor active = false
@property({type: Boolean, attribute: false})
accessor valid: true | false | undefined
// inactive + invalid/no validity -> nothing
// active + no validity -> blue circle
// inactive/active + valid -> green upper checkmark
// active + invalid -> red upper cross
@property({type: String, attribute: true, reflect: true})
accessor layout: "list" | "tiles" = "list"
static scopedElements = {
"sl-radio": SlRadio,
"sl-checkbox": SlCheckbox,
"sl-icon": SlIcon
}
static styles = css`
:host {
width: 100%;
position: relative;
}
:host(:not([contenteditable=true]):not([contenteditable=""])) .author-only {
display: none;
}
:host(:is([contenteditable=true], [contenteditable=""])) .user-only {
display: none;
}
:host(:is([contenteditable=true], [contenteditable=""])) sl-checkbox.valid {
--webwriter-control-color-600: var(--sl-color-success-600);
--webwriter-control-color-400: var(--sl-color-success-400);
}
sl-checkbox {
display: block;
width: 100%;
&::part(base) {
width: 100%;
display: flex;
flex-direction: row;
align-items: center;
cursor: unset;
}
&::part(control) {
cursor: pointer;
border-radius: var(--webwriter-choice-radius, 2px);
border-width: 2px;
}
&::part(control):not(:hover){
border-color: var(--sl-color-gray-500);
}
&::part(control):hover {
border-color: var(--sl-color-gray-700);
}
&::part(control--checked):not(:hover) {
background-color: var(--webwriter-control-color-600, var(--sl-color-primary-600));
border-color: var(--sl-color-gray-500);
}
&::part(control--checked):hover {
background-color: var(--webwriter-control-color-400, var(--sl-color-primary-400));
border-color: var(--webwriter-control-color-600, var(--sl-color-primary-600));
}
&::part(label) {
width: 100%;
}
}
.solution {
position: absolute;
top: -6px;
left: -6px;
border: 2px solid var(--sl-color-gray-500);
border-radius: var(--webwriter-choice-radius, 2px);
width: 12px;
height: 12px;
z-index: 1;
color: white;
&[data-valid] {
background: var(--sl-color-success-600);
}
&:not([data-valid]) {
background: var(--sl-color-danger-600);
}
}
:host([layout=tiles]) {
position: relative;
overflow: visible !important;
& ::slotted(:is(picture, audio, video, img, iframe)) {
height: 100%;
width: 100%;
}
& ::slotted(:not(:is(picture, audio, video, img, iframe))) {
margin: 5px !important;
}
sl-checkbox {
display: block;
&::part(base) {
display: flex;
flex-direction: row;
align-items: center;
cursor: unset;
position: static;
}
&::part(control) {
position: absolute;
bottom: -10px;
left: -10px;
cursor: pointer;
border-radius: var(--webwriter-choice-radius, 2px);
z-index: 100;
border-color: var(--sl-color-gray-500);
}
&::part(control--checked):not(:hover) {
background-color: var(--webwriter-control-color-600, var(--sl-color-primary-600));
border-color: var(--sl-color-gray-500);
}
&::part(control--checked):hover {
background-color: var(--webwriter-control-color-400, var(--sl-color-primary-400));
border-color: var(--webwriter-control-color-600, var(--sl-color-primary-600));
}
&::part(label) {
aspect-ratio: 1;
min-width: 125px;
max-width: 350px;
min-height: 125px;
max-height: 350px;
overflow: hidden;
margin-inline-start: 0;
overflow-y: auto;
scrollbar-width: thin;
}
:host(:is([contenteditable=true], [contenteditable=""])) &::part(label) {
resize: both;
}
}
}
`
handleClick = (e: PointerEvent) => {
const checkboxClicked = e.composedPath().some(v => (v as HTMLElement)?.classList?.contains("checkbox__control"))
const editable = this.isContentEditable
if(editable && !checkboxClicked) {
e.preventDefault()
}
else {
e.stopImmediatePropagation()
}
}
handleChange = (e: CustomEvent) => {
if(this.isContentEditable) {
this.valid = !this.valid
}
else {
this.active = !this.active
}
}
@query("sl-checkbox")
accessor checkbox: SlCheckbox
observer: MutationObserver
protected async updated(_changedProperties: PropertyValues) {
await this.checkbox.updateComplete
const labelEl = this.checkbox.shadowRoot.querySelector(".checkbox__label") as HTMLElement
if(_changedProperties.has("layout") && this.layout === "list") {
this.syncSize(true)
this.observer?.disconnect()
}
else if(_changedProperties.has("layout") && this.layout === "tiles") {
this.syncSize()
this.observer = new MutationObserver(() => this.syncSize())
this.observer.observe(labelEl, {attributeFilter: ["style"], attributes: true})
}
}
syncSize(clear=false) {
const labelEl = this.checkbox?.shadowRoot.querySelector(".checkbox__label") as HTMLElement
if(labelEl && !clear) {
this.style.width = labelEl.style.width
this.style.height = labelEl.style.height
}
else if(labelEl && clear) {
this.style.width = labelEl.style.width = null
this.style.height = labelEl.style.height = null
}
}
disconnectedCallback(): void {
super.disconnectedCallback()
this.observer?.disconnect()
}
render() {
return keyed(this.layout, html`
${this.showSolution && this.valid !== undefined && (this.active || !this.active && this.valid)? html``: null}
`)
}
}