egroupware_official/api/js/etemplate/Et2Switch/Et2SwitchIcon.ts
2024-10-21 11:46:35 -06:00

177 lines
4.4 KiB
TypeScript

import {css, html, LitElement, nothing} from "lit";
import {customElement} from "lit/decorators/custom-element.js";
import {property} from "lit/decorators/property.js";
import {classMap} from "lit/directives/class-map.js";
import {live} from "lit/directives/live.js";
import {Et2InputWidget} from "../Et2InputWidget/Et2InputWidget";
import {SlSwitch} from "@shoelace-style/shoelace";
/**
* @summary Switch to allow choosing between two options, displayed with two images
*
* @slot on - Content shown when the switch is on
* @slot off - Content shown when the switch is off
* @slot help-text - Text that describes how to use the switch. Alternatively, you can use the `help-text` attribute.
*
* @cssproperty --height - The height of the switch.
* @cssproperty --width - The width of the switch.
* @cssproperty --indicator-color - The color of the selected image
*
* @csspart form-control-label The label's wrapper
* @csspart control The control's wrapper
* @csspart switch-label The internal control's wrapper (sometimes needed for positioning)
*/
@customElement("et2-switch-icon")
export class Et2SwitchIcon extends Et2InputWidget(LitElement)
{
static get styles()
{
return [
...super.styles,
css`
:host {
--indicator-color: var(--sl-color-primary-600);
display: flex;
}
sl-switch {
font-size: 1em;
--height: 1em;
}
::part(control) {
display: none;
}
::part(label) {
width: 100%;
height: 100%;
}
.label {
display: inline-flex;
flex: 1 1 auto;
font-size: var(--height);
user-select: none;
}
et2-image, ::slotted(:scope > *) {
flex: 1 1 50%;
font-size: var(--width);
}
slot {
color: var(--sl-color-neutral-400);
}
sl-switch {
display: flex;
align-items: center;
}
sl-switch[checked] slot[name="on"], sl-switch:not([checked]) slot[name="off"] {
color: var(--indicator-color, inherit);
}
sl-switch::part(label), sl-switch::part(form-control) {
display: flex;
align-items: center;
margin-inline-start: 0px;
}
.label:hover {
background-color: var(--sl-color-primary-50);
border-color: var(--sl-color-primary-300);
}
`
]
}
/**
* Name of the icon displayed when the switch is on
* @type {string}
*/
@property() onIcon = "check";
/**
* Name of the icon displayed when the switch is off
* @type {string}
*/
@property() offIcon = "x"
private get switch() : SlSwitch { return <SlSwitch>this.shadowRoot?.querySelector("sl-switch")};
private get input() { return this.switch.shadowRoot.querySelector("input");}
async getUpdateComplete()
{
const result = await super.getUpdateComplete();
await this.switch?.updateComplete;
return result;
}
set value(new_value : string | boolean)
{
if(this.switch)
{
this.switch.checked = !!new_value;
}
else
{
this.updateComplete.then(() => this.value = new_value);
}
}
get value()
{
return this.switch?.checked;
}
labelTemplate()
{
return html`
${this.label ? html`<span
part="form-control-label"
class="form-control__label">${this.label}
</span>` : nothing}
<span
part="control"
class=${classMap({
"label": true,
"on": this.checked,
})}
aria-label="${this.label}"
>
<slot name="on">
<et2-image class="image on" src=${this.onIcon} title="${this.toggleOn}"></et2-image>
</slot>
<slot name="off">
<et2-image class="image off" src=${this.offIcon} title="${this.toggleOff}"></et2-image>
</slot>
</span>
`;
}
render()
{
return html`
<sl-switch
part="switch"
exportparts="base:switch-label"
.label=${this.label}
.value=${live(this.value)}
.checked=${live(this.checked)}
.disabled=${live(this.disabled)}
.required=${this.required}
.helpText=${this.helpText}
@sl-change=${async(e) =>
{
await this.updateComplete;
this.dispatchEvent(new Event("change", {bubbles: true}));
}}
>
${this.labelTemplate()}
</sl-switch>
`;
}
}