Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | 90x 90x 90x 90x 29x 29x | import { LitElement, html, unsafeCSS } from "lit" import { customElement, property } from "lit/decorators.js" import { classMap } from "lit/directives/class-map.js" import { ifDefined } from "lit/directives/if-defined.js" import style from "./style.scss?inline" /** * Available visual styles for {@link VgCard}. */ export type CardVariant = "elevated" | "outlined" | "subtle" /** * Payload emitted by the {@link VgCard | card}'s `action` event when the card is interactive. */ export interface CardActionDetail { /** * Original keyboard or pointer event initiating the action. */ readonly originalEvent: MouseEvent | KeyboardEvent } /** * Theme-aware content container with optional header/footer slots. * * @tag vg-card * @tagname vg-card * @summary The Card component, used for displaying content in a structured container. * * @slot header - Optional content rendered before the body, often containing a title or metadata * @slot - Main card body content * @slot footer - Optional actions or supporting content rendered after the body * * @csspart card - Allows you to style the card container element * * @fires {CardActionDetail} vg-action - Fired when an interactive card is triggered * */ @customElement("vg-card") export class VgCard extends LitElement { static styles = unsafeCSS(style) /** * Display heading rendered above the default slot when provided. */ @property({ type: String }) public heading: string | null = null /** * Visual variant for the card container. */ @property({ type: String }) public variant: CardVariant = "elevated" /** * Enables hover/press affordances and makes the card keyboard activatable. */ @property({ type: Boolean, reflect: true }) public interactive = false /** * @inheritdoc */ protected render() { const classes = { card: true, [this.variant]: true, interactive: this.interactive, } return html` <article class=${classMap(classes)} role=${ifDefined(this.interactive ? "button" : "group")} tabindex=${ifDefined(this.interactive ? "0" : undefined)} @click=${this.handleClick} @keydown=${this.handleKeydown} > ${this.heading ? html`<header class="card__header">${this.heading}</header>` : null} <slot name="header"></slot> <div class="card__body"> <slot></slot> </div> <slot name="footer"></slot> </article> ` } private handleClick(event: MouseEvent) { Iif (I!this.interactive) { return } this.dispatchAction(event) } private handleKeydown(event: KeyboardEvent) { Iif (I!this.interactive) { return } Iif (event.key === "Enter" || event.key === " ") { event.preventDefault() this.dispatchAction(event) } } private dispatchAction(event: MouseEvent | KeyboardEvent) { this.dispatchEvent(new CustomEvent<CardActionDetail>("vg-action", { detail: { originalEvent: event }, // bubbles: true, composed: true, })) } } declare global { interface HTMLElementTagNameMap { "vg-card": VgCard } } |