{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "conversation-list",
  "title": "ConversationList",
  "description": "Scrollable conversation-list region with dedicated empty and persistent action placement.",
  "type": "registry:ui",
  "meta": {
    "library": "@ds-mo/ui",
    "distribution": "npm",
    "storybook": "https://zainadeel.github.io/compomo/?path=/story/conversation-list",
    "source": "src/wc/components/ConversationList/ConversationList.tsx",
    "intentStatus": "complete",
    "intent": {
      "audience": "general",
      "status": "experimental",
      "summary": "Scrollable conversation-list region with dedicated empty and persistent action placement.",
      "useWhen": [
        "A messaging-like surface needs a reusable history list with empty and action regions."
      ],
      "avoidWhen": [
        "The content is not a collection of conversations or threads."
      ],
      "commonlyComposedWith": [
        "component:ds-conversation-list-section",
        "component:ds-conversation-list-item",
        "component:ds-empty-state",
        "component:ds-scroll-overlay"
      ],
      "patterns": [
        "pattern:conversation"
      ],
      "accessibility": [
        "Provide an accessible list label through the surrounding heading or region.",
        "Keep the empty message descriptive and every persistent action explicitly named."
      ],
      "states": [
        "The default floating action stays at the lower end corner.",
        "actionLayout footer stretches a long action between 8px side and bottom insets.",
        "Both action layouts share the always-active scroll-overlay fade controller, reserve measured end clearance, and begin fading 8px before the visible action.",
        "ConversationList paints its measured fade on a separate surface-aware layer so contextual row actions retain a real backdrop for blur; hovered, focused, and menu-open rows rise above that decorative fade.",
        "The persistent action wrapper splits its md outer shadow from a top inset-highlight overlay so opaque filled actions keep the complete TokoMo elevation; slotted buttons disable optional resting borders and the press-scale modifier moves the button and elevated surface as one unit."
      ],
      "responsiveBehavior": [
        "The list fills its owner, scrolls independently, and keeps its persistent action above scrolling rows."
      ],
      "references": [
        {
          "label": "Storybook examples",
          "path": "src/wc/components/ConversationList/ConversationList.stories.ts"
        }
      ]
    },
    "api": {
      "props": {
        "actionLayout": {
          "type": "ConversationListActionLayout",
          "resolvedType": "\"floating\" | \"footer\"",
          "attribute": "action-layout",
          "default": "'floating'",
          "required": false,
          "mutable": false,
          "description": "Corner icon action or full-width persistent footer action."
        }
      },
      "events": [],
      "methods": [],
      "slots": []
    },
    "props": {
      "actionLayout": {
        "type": "ConversationListActionLayout",
        "resolvedType": "\"floating\" | \"footer\"",
        "attribute": "action-layout",
        "default": "'floating'",
        "required": false,
        "mutable": false,
        "description": "Corner icon action or full-width persistent footer action."
      }
    },
    "events": [],
    "methods": [],
    "slots": [],
    "exports": {
      "customElement": "ds-conversation-list",
      "react": "DsConversationList",
      "vue": "DsConversationList",
      "angular": "DsConversationList"
    },
    "consumption": {
      "install": "npm install @ds-mo/ui @ds-mo/tokens @ds-mo/icons",
      "cssSetup": "import '@ds-mo/tokens';\nimport '@ds-mo/tokens/reset';\nimport '@ds-mo/tokens/globals';",
      "customElements": {
        "import": "import '@ds-mo/ui/dist/components/ds-conversation-list.js';",
        "example": "<ds-conversation-list></ds-conversation-list>"
      },
      "react": {
        "import": "import { DsConversationList } from '@ds-mo/ui/react';",
        "example": "<DsConversationList />"
      },
      "vue": {
        "import": "import { DsConversationList } from '@ds-mo/ui/vue';",
        "example": "<DsConversationList />"
      },
      "angular": {
        "import": "import { DsConversationList } from '@ds-mo/ui/angular/ds-conversation-list';",
        "example": "<ds-conversation-list></ds-conversation-list>"
      },
      "peerDependencies": {
        "required": [
          "@ds-mo/tokens ^6.5.0",
          "@ds-mo/icons ^7.0.0"
        ],
        "frameworks": "Custom Elements; React 18/19 wrappers; Vue 3 wrappers; Angular 19-22 standalone adapters."
      }
    }
  },
  "dependencies": [
    "@ds-mo/ui",
    "@ds-mo/tokens"
  ],
  "registryDependencies": [],
  "files": [
    {
      "path": "src/wc/components/ConversationList/ConversationList.css",
      "content": "@import '../../styles/control-elevation.css';\n\n:host {\n  display: block;\n  position: relative;\n  width: 100%;\n  height: 100%;\n  min-height: 0;\n  box-sizing: border-box;\n  -webkit-user-select: none;\n  user-select: none;\n}\n\n.conversation-list {\n  position: relative;\n  display: flex;\n  flex-direction: column;\n  width: 100%;\n  height: 100%;\n  min-height: 0;\n  box-sizing: border-box;\n}\n\n.conversation-list__viewport {\n  position: relative;\n  flex: 1 1 auto;\n  min-height: 0;\n  overflow: auto;\n  box-sizing: border-box;\n}\n\n.conversation-list__content {\n  position: relative;\n  min-height: 100%;\n  padding: var(--dimension-space-100);\n  padding-bottom: calc(\n    var(--dimension-space-100) + var(--ds-scroll-overlay-block-size, 0px)\n  );\n  box-sizing: border-box;\n}\n\n.conversation-list__fade {\n  position: absolute;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: 1;\n  height: var(--ds-scroll-overlay-fade-block-size, 0);\n  pointer-events: none;\n  background-color: var(\n    --ds-scroll-overlay-surface-color,\n    var(--_shell-chrome-bg, var(--color-background-primary))\n  );\n  --ds-scroll-edge-fade-size: 100%;\n}\n\n.conversation-list__fade::before {\n  content: '';\n  position: absolute;\n  inset: 0;\n  background-image: var(\n    --ds-scroll-overlay-surface-image,\n    var(--ds-shell-gradient-image, none)\n  );\n  background-position: var(--ds-scroll-overlay-surface-position, 0 0);\n  background-attachment: fixed;\n  background-size: var(\n    --ds-scroll-overlay-surface-size,\n    var(--ds-shell-gradient-size, auto)\n  );\n  background-repeat: no-repeat;\n  opacity: var(\n    --ds-scroll-overlay-surface-image-opacity,\n    var(--ds-shell-gradient-opacity, 1)\n  );\n}\n\n.conversation-list__empty {\n  display: contents;\n}\n\n.conversation-list__actions {\n  position: absolute;\n  right: 0;\n  bottom: 0;\n  z-index: var(--dimension-z-index-floating);\n  padding: 0 var(--dimension-space-200) var(--dimension-space-200) 0;\n}\n\n.conversation-list__actions--footer {\n  left: 0;\n  padding: 0 var(--dimension-space-100) var(--dimension-space-100);\n}\n\n.conversation-list__actions-surface {\n  display: flex;\n  border-radius: var(--dimension-radius-half);\n}\n\n.conversation-list__actions--footer .conversation-list__actions-surface {\n  width: 100%;\n}\n\n.conversation-list__actions-surface:empty {\n  display: none;\n}\n",
      "type": "registry:ui"
    },
    {
      "path": "src/wc/components/ConversationList/ConversationList.tsx",
      "content": "import { Component, Element, h, Host, Prop } from '@stencil/core';\nimport { ScrollOverlayController } from '../../utils/scroll-overlay-controller';\n\nexport type ConversationListActionLayout = 'floating' | 'footer';\n\n@Component({\n  tag: 'ds-conversation-list',\n  styleUrl: 'ConversationList.css',\n  styleUrls: ['../../utils/scroll-edge-fade.css'],\n  scoped: true,\n})\nexport class ConversationList {\n  @Element() el!: HTMLElement;\n\n  /** Corner icon action or full-width persistent footer action. */\n  @Prop() actionLayout: ConversationListActionLayout = 'floating';\n\n  private viewport?: HTMLElement;\n  private content?: HTMLElement;\n  private overlay?: HTMLElement;\n  private scrollOverlayController?: ScrollOverlayController;\n  private emptySlotObserver?: MutationObserver;\n\n  componentDidLoad(): void {\n    if (!this.viewport || !this.content || !this.overlay) return;\n    this.scrollOverlayController = new ScrollOverlayController({\n      host: this.el,\n      viewport: this.viewport,\n      content: this.content,\n      overlay: this.overlay,\n      overlayContentSelector: '[slot=\"actions\"]',\n    });\n    this.scrollOverlayController.connect();\n    this.syncEmptyStateLayout();\n    this.emptySlotObserver = new MutationObserver(this.syncEmptyStateLayout);\n    this.emptySlotObserver.observe(this.el, { childList: true, subtree: true });\n  }\n\n  disconnectedCallback(): void {\n    this.scrollOverlayController?.disconnect();\n    this.emptySlotObserver?.disconnect();\n  }\n\n  private syncEmptyStateLayout = (): void => {\n    const emptyState = this.el.querySelector<HTMLElement>('[slot=\"empty\"]');\n    if (emptyState) {\n      emptyState.style.setProperty('position', 'absolute');\n      emptyState.style.setProperty('inset-block-start', '0');\n      emptyState.style.setProperty('inset-inline', '0');\n      emptyState.style.setProperty(\n        'inset-block-end',\n        'var(--ds-scroll-overlay-block-size, 0)',\n      );\n      emptyState.style.setProperty('height', 'auto');\n      emptyState.style.setProperty('box-sizing', 'border-box');\n    }\n    this.scrollOverlayController?.sync();\n  };\n\n  render() {\n    return (\n      <Host>\n        <div class=\"conversation-list\">\n          <div\n            class=\"conversation-list__viewport\"\n            ref={element => {\n              this.viewport = element;\n            }}\n            onScroll={() => this.scrollOverlayController?.sync()}\n          >\n            <div\n              class=\"conversation-list__content\"\n              ref={element => {\n                this.content = element;\n              }}\n            >\n              <slot />\n              <div class=\"conversation-list__empty\">\n                <slot name=\"empty\" />\n              </div>\n            </div>\n          </div>\n          <div\n            class=\"conversation-list__fade scroll-edge-fade scroll-edge-fade--top\"\n            aria-hidden=\"true\"\n          />\n          <div\n            class={{\n              'conversation-list__actions': true,\n              'conversation-list__actions--footer': this.actionLayout === 'footer',\n            }}\n            ref={element => {\n              this.overlay = element;\n            }}\n          >\n            <div class=\"conversation-list__actions-surface ds-control-elevation ds-control-elevation--md ds-control-elevation--press-scale\">\n              <slot name=\"actions\" />\n            </div>\n          </div>\n        </div>\n      </Host>\n    );\n  }\n}\n",
      "type": "registry:ui"
    }
  ]
}
