{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "list",
  "title": "List",
  "type": "registry:ui",
  "description": "List and Item row primitives with List, ListItem, ListItemMedia, ListItemContent, ListItemTitle, ListItemDescription, ListItemActions, and ListSubheader for structured rows, settings lists, and feeds.",
  "categories": [
    "data-display"
  ],
  "files": [
    {
      "path": "packages/elements-lit/src/components/list/list.ts",
      "content": "import { LitElement, css, html, nothing } from 'lit'\nimport { cn } from '../../lib/utils'\nimport { tailwind } from '../../lib/styles'\nimport { ThemeController } from '../../lib/theme'\n\n/**\n * <uip-list> — container for list items.\n */\nexport class UipList extends LitElement {\n  static styles = [\n    tailwind,\n    css`\n      :host {\n        display: block;\n        width: 100%;\n      }\n    `,\n  ]\n\n  static properties = {\n    as: { reflect: true },\n  }\n\n  as: 'ul' | 'ol' | 'div' = 'ul'\n\n  constructor() {\n    super()\n    new ThemeController(this)\n  }\n\n  connectedCallback() {\n    super.connectedCallback()\n    this.setAttribute('data-uipkge', '')\n    this.setAttribute('data-slot', 'list')\n  }\n\n  render() {\n    return html`\n      <div part=\"base\" data-slot=\"list\" class=\"list-none space-y-1\">\n        <slot></slot>\n      </div>\n    `\n  }\n}\n\n/**\n * <uip-list-item> — a single item in a list.\n */\nexport class UipListItem extends LitElement {\n  static styles = [\n    tailwind,\n    css`\n      :host {\n        display: block;\n        width: 100%;\n      }\n    `,\n  ]\n\n  static properties = {\n    active: { type: Boolean, reflect: true },\n    disabled: { type: Boolean, reflect: true },\n    href: { reflect: true },\n    as: { reflect: true },\n    hasContent: { state: true },\n  }\n\n  active = false\n  disabled = false\n  href?: string\n  as: 'li' | 'div' | 'a' = 'li'\n  private hasContent = false\n\n  constructor() {\n    super()\n    new ThemeController(this)\n  }\n\n  connectedCallback() {\n    super.connectedCallback()\n    this.setAttribute('data-uipkge', '')\n    this.setAttribute('data-slot', 'list-item')\n  }\n\n  willUpdate() {\n    if (this.active) {\n      this.setAttribute('data-active', '')\n      this.setAttribute('aria-current', 'true')\n    } else {\n      this.removeAttribute('data-active')\n      this.removeAttribute('aria-current')\n    }\n    if (this.disabled) {\n      this.setAttribute('data-disabled', '')\n      this.setAttribute('aria-disabled', 'true')\n    } else {\n      this.removeAttribute('data-disabled')\n      this.removeAttribute('aria-disabled')\n    }\n  }\n\n  private onSlotChange(e: Event) {\n    const slot = e.target as HTMLSlotElement\n    const assigned = slot.assignedElements()\n    this.hasContent = assigned.some(\n      (el) => el.localName === 'uip-list-item-content' || el.getAttribute('data-slot') === 'list-item-content',\n    )\n  }\n\n  private onClick(e: MouseEvent) {\n    if (this.disabled) {\n      e.preventDefault()\n      e.stopPropagation()\n    }\n  }\n\n  render() {\n    const isInteractive = !this.disabled && (this.as === 'a' || this.href != null)\n    const classes = cn(\n      'rounded-md px-2 py-1.5 text-sm transition-colors duration-200 select-none focus-visible:outline-none',\n      this.hasContent && 'flex items-center gap-3',\n      isInteractive && 'hover:bg-accent focus-visible:bg-accent cursor-pointer',\n      this.active && 'bg-accent text-accent-foreground',\n      this.disabled && 'pointer-events-none cursor-not-allowed opacity-50',\n    )\n\n    if (this.href || this.as === 'a') {\n      return html`\n        <a\n          part=\"base\"\n          data-slot=\"list-item\"\n          href=${this.disabled ? nothing : (this.href ?? nothing)}\n          tabindex=${this.disabled ? -1 : nothing}\n          class=${classes}\n          @click=${this.onClick}\n        >\n          <slot @slotchange=${this.onSlotChange}></slot>\n        </a>\n      `\n    }\n\n    return html`\n      <div\n        part=\"base\"\n        data-slot=\"list-item\"\n        tabindex=${this.disabled ? -1 : nothing}\n        class=${classes}\n        @click=${this.onClick}\n      >\n        <slot @slotchange=${this.onSlotChange}></slot>\n      </div>\n    `\n  }\n}\n\n/**\n * <uip-list-item-media> — icon/avatar slot in a list item.\n */\nexport class UipListItemMedia extends LitElement {\n  static styles = [tailwind, css`:host { display: inline-flex; align-self: center; }`]\n\n  constructor() {\n    super()\n    new ThemeController(this)\n  }\n\n  connectedCallback() {\n    super.connectedCallback()\n    this.setAttribute('data-uipkge', '')\n    this.setAttribute('data-slot', 'list-item-media')\n  }\n\n  render() {\n    return html`\n      <div part=\"base\" data-slot=\"list-item-media\" class=\"flex shrink-0 items-center justify-center self-center\">\n        <slot></slot>\n      </div>\n    `\n  }\n}\n\n/**\n * <uip-list-item-content> — primary title + description container.\n */\nexport class UipListItemContent extends LitElement {\n  static styles = [tailwind, css`:host { display: flex; flex: 1 1 0%; min-width: 0; align-self: center; }`]\n\n  constructor() {\n    super()\n    new ThemeController(this)\n  }\n\n  connectedCallback() {\n    super.connectedCallback()\n    this.setAttribute('data-uipkge', '')\n    this.setAttribute('data-slot', 'list-item-content')\n  }\n\n  render() {\n    return html`\n      <div part=\"base\" data-slot=\"list-item-content\" class=\"flex min-w-0 flex-1 flex-col gap-0.5 self-center\">\n        <slot></slot>\n      </div>\n    `\n  }\n}\n\n/**\n * <uip-list-item-title> — title inside list item content.\n */\nexport class UipListItemTitle extends LitElement {\n  static styles = [tailwind, css`:host { display: block; }`]\n\n  constructor() {\n    super()\n    new ThemeController(this)\n  }\n\n  connectedCallback() {\n    super.connectedCallback()\n    this.setAttribute('data-uipkge', '')\n    this.setAttribute('data-slot', 'list-item-title')\n  }\n\n  render() {\n    return html`\n      <div part=\"base\" data-slot=\"list-item-title\" class=\"text-foreground truncate text-sm leading-none font-medium\">\n        <slot></slot>\n      </div>\n    `\n  }\n}\n\n/**\n * <uip-list-item-description> — description under title.\n */\nexport class UipListItemDescription extends LitElement {\n  static styles = [tailwind, css`:host { display: block; }`]\n\n  constructor() {\n    super()\n    new ThemeController(this)\n  }\n\n  connectedCallback() {\n    super.connectedCallback()\n    this.setAttribute('data-uipkge', '')\n    this.setAttribute('data-slot', 'list-item-description')\n  }\n\n  render() {\n    return html`\n      <div part=\"base\" data-slot=\"list-item-description\" class=\"text-muted-foreground line-clamp-1 text-xs\">\n        <slot></slot>\n      </div>\n    `\n  }\n}\n\n/**\n * <uip-list-item-actions> — trailing actions/controls in a list item.\n */\nexport class UipListItemActions extends LitElement {\n  static styles = [tailwind, css`:host { display: inline-flex; align-self: center; }`]\n\n  constructor() {\n    super()\n    new ThemeController(this)\n  }\n\n  connectedCallback() {\n    super.connectedCallback()\n    this.setAttribute('data-uipkge', '')\n    this.setAttribute('data-slot', 'list-item-actions')\n  }\n\n  render() {\n    return html`\n      <div part=\"base\" data-slot=\"list-item-actions\" class=\"text-muted-foreground flex shrink-0 items-center gap-1.5 self-center\">\n        <slot></slot>\n      </div>\n    `\n  }\n}\n\n/**\n * <uip-list-subheader> — group header for list sections.\n */\nexport class UipListSubheader extends LitElement {\n  static styles = [tailwind, css`:host { display: block; }`]\n\n  constructor() {\n    super()\n    new ThemeController(this)\n  }\n\n  connectedCallback() {\n    super.connectedCallback()\n    this.setAttribute('data-uipkge', '')\n    this.setAttribute('data-slot', 'list-subheader')\n  }\n\n  render() {\n    return html`\n      <div part=\"base\" data-slot=\"list-subheader\" class=\"text-muted-foreground px-2 py-1 text-xs font-medium tracking-wider uppercase\">\n        <slot></slot>\n      </div>\n    `\n  }\n}\n\ncustomElements.get('uip-list') || customElements.define('uip-list', UipList)\ncustomElements.get('uip-list-item') || customElements.define('uip-list-item', UipListItem)\ncustomElements.get('uip-list-item-media') || customElements.define('uip-list-item-media', UipListItemMedia)\ncustomElements.get('uip-list-item-content') || customElements.define('uip-list-item-content', UipListItemContent)\ncustomElements.get('uip-list-item-title') || customElements.define('uip-list-item-title', UipListItemTitle)\ncustomElements.get('uip-list-item-description') || customElements.define('uip-list-item-description', UipListItemDescription)\ncustomElements.get('uip-list-item-actions') || customElements.define('uip-list-item-actions', UipListItemActions)\ncustomElements.get('uip-list-subheader') || customElements.define('uip-list-subheader', UipListSubheader)\n\ndeclare global {\n  interface HTMLElementTagNameMap {\n    'uip-list': UipList\n    'uip-list-item': UipListItem\n    'uip-list-item-media': UipListItemMedia\n    'uip-list-item-content': UipListItemContent\n    'uip-list-item-title': UipListItemTitle\n    'uip-list-item-description': UipListItemDescription\n    'uip-list-item-actions': UipListItemActions\n    'uip-list-subheader': UipListSubheader\n  }\n}\n",
      "type": "registry:file",
      "target": "src/uip/components/list/list.ts"
    }
  ],
  "dependencies": [
    "lit"
  ],
  "registryDependencies": [
    "https://uipkge.dev/r/lit/lit-core.json"
  ]
}
