// Copyright (C) 2025 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import { LitElement, html, css } from "https://cdn.jsdelivr.net/gh/lit/dist@3/all/lit-all.min.js"; // Generated by Gemini export class RadioButtonGroup extends LitElement { static styles = css` :host { display: block; font-family: sans-serif; } .radio-group-container { display: flex; flex-direction: row; } label { display: flex; align-items: center; margin-bottom: 8px; cursor: pointer; padding: 8px; border-radius: 4px; transition: background-color 0.2s ease-in-out; } label:hover { background-color: #f0f0f0; } input[type="radio"] { margin-right: 8px; cursor: pointer; /* Custom radio button appearance */ appearance: none; -webkit-appearance: none; width: 18px; height: 18px; border: 2px solid #ccc; border-radius: 50%; outline: none; transition: border-color 0.2s ease-in-out, box-shadow 0.2s ease-in-out; } input[type="radio"]:checked { border-color: #656565; background-color: #656565; /* Optional: fill color when checked */ } input[type="radio"]:checked::before { content: ''; display: block; width: 8px; height: 8px; margin: 3px; /* Adjust to center the dot */ background-color: white; border-radius: 50%; } input[type="radio"]:focus { box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25); } .label-text { font-size: 1rem; } `; static properties = { /** * An array of strings representing the choices for the radio buttons. * @type {Array} */ choices: { type: Array }, /** * The name for the radio button group. This is important for accessibility * and ensuring only one radio button in the group can be selected. * @type {string} */ name: { type: String }, /** * The currently selected value. * @type {string} */ value: { type: String, reflect: true }, /** * The label or title for the radio group. * @type {string} */ groupLabel: { type: String } }; constructor() { super(); this.choices = []; this.name = 'radio-group'; // Default name this.value = ''; this.groupLabel = ''; } _handleChange(event) { const selectedValue = event.target.value; if (this.value !== selectedValue) { this.value = selectedValue; // Dispatch a custom event with the new value this.dispatchEvent(new CustomEvent('radio-change', { detail: { value: this.value, radioId: this.id }, bubbles: true, // Allows the event to bubble up through the DOM composed: true // Allows the event to cross shadow DOM boundaries })); } } render() { return html`
${this.groupLabel ? html`${this.groupLabel}` : ''} ${this.choices.map(choice => html` `)}
`; } } customElements.define('radio-button-group', RadioButtonGroup); // Generated by Gemini with some modifications class ModalDialog extends LitElement { static styles = css` :host { display: none; /* Hidden by default */ } :host([open]) { display: block; /* Show when open attribute is present */ } .backdrop { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background-color: rgba(0, 0, 0, 0.5); /* Semi-transparent black */ display: flex; justify-content: center; align-items: center; z-index: 1000; /* Ensure it's on top */ } .dialog { background-color: white; padding: 20px; border-radius: 8px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); min-width: 300px; /* Or your desired width */ z-index: 1001; /* Above the backdrop */ display: flex; flex-direction: column; align-items: center; margin: 0 15px; } `; static get properties() { return { open: { type: Boolean, reflect: true }, }; } constructor() { super(); this.open = false; } _handleBackdropClick(event) { // Close only if the click is directly on the backdrop, not on the dialog itself if (event.target === this.shadowRoot.querySelector('.backdrop')) { this.open = false; this.dispatchEvent(new CustomEvent('dialog-closed', { bubbles: true, composed: true })); } } _handleDialogClick(event) { // Prevent clicks inside the dialog from bubbling up to the backdrop event.stopPropagation(); } render() { if (!this.open) { return html``; } return html`

Default Header

This is the default content of the modal.

`; } } customElements.define('modal-dialog', ModalDialog);