{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "contact-us",
  "title": "Contact Us",
  "type": "registry:block",
  "description": "Two-column contact section. Left: eyebrow, headline, lede, icon contact rows (email / phone / office) and a live Mapbox map pinned to your office (pass access-token + location; falls back to a placeholder without a token). Right: a Card-wrapped form (name / email / company / subject Select / message Textarea) that swaps to a success state. Emits \"submit\" with the payload.",
  "categories": [
    "marketing"
  ],
  "files": [
    {
      "path": "packages/elements-lit/src/blocks/contact-us/contact-us.ts",
      "content": "import { LitElement, css, html } from 'lit'\nimport { CheckCircle2, Mail, MapPin, Phone, Send } from 'lucide'\nimport { tailwind } from '../../lib/styles'\nimport { ThemeController } from '../../lib/theme'\nimport { icon } from '../../lib/icon'\n// Side-effect imports: register the composed elements for standalone use\n// (consumers who install only this block still get working primitives).\nimport '../../components/button/button'\nimport '../../components/input/input'\nimport type { UipInput } from '../../components/input/input'\nimport '../../components/label/label'\nimport '../../components/select/select'\nimport type { UipSelect } from '../../components/select/select'\nimport '../../components/textarea/textarea'\nimport type { UipTextarea } from '../../components/textarea/textarea'\nimport '../../components/map/map'\n\nexport interface ContactUsSubmitPayload {\n  name: string\n  email: string\n  company: string\n  subject: string\n  message: string\n}\n\n/**\n * <uip-contact-us> — the registry ContactUs block as a web component.\n *\n * Class strings are React's ContactUs verbatim. React state (useState)\n * becomes @state fields; `onSubmit` (payload) becomes a `submit` CustomEvent\n * with the payload in `detail` (bubbles, composed). `accessToken` +\n * `location` drive a <uip-map> (mapbox-gl loads lazily inside it); without a\n * token the map area shows React's styled placeholder. Card chrome stays\n * plain divs carrying the registry Card part classes (see the login-01\n * block).\n */\nexport class UipContactUs extends LitElement {\n  static shadowRootOptions = { ...LitElement.shadowRootOptions, delegatesFocus: true }\n  // :host display can't be a utility class (the host has no template of its own).\n  static styles = [tailwind, css`:host { display: block; }`]\n\n  static properties = {\n    accessToken: { attribute: 'access-token' },\n    location: { type: Array },\n    locationLabel: { attribute: 'location-label' },\n    name: { state: true },\n    email: { state: true },\n    company: { state: true },\n    subject: { state: true },\n    message: { state: true },\n    sent: { state: true },\n  }\n\n  /** Mapbox token. Without it the map area shows a styled placeholder. */\n  accessToken = ''\n  /** Office [lng, lat]. */\n  location: [number, number] = [-122.4194, 37.7749]\n  locationLabel = 'San Francisco, CA'\n  private name = ''\n  private email = ''\n  private company = ''\n  private subject = 'sales'\n  private message = ''\n  private sent = 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', 'contact-us')\n  }\n\n  private get canSubmit() {\n    return !!this.name && !!this.email && !!this.message\n  }\n\n  private submit() {\n    if (!this.canSubmit) return\n    this.dispatchEvent(\n      new CustomEvent<ContactUsSubmitPayload>('submit', {\n        detail: { name: this.name, email: this.email, company: this.company, subject: this.subject, message: this.message },\n        bubbles: true,\n        composed: true,\n      }),\n    )\n    this.sent = true\n  }\n\n  render() {\n    return html`\n      <section data-slot=\"contact-us\" class=\"bg-background\">\n        <div class=\"mx-auto max-w-6xl px-6 py-20\">\n          <div class=\"grid gap-10 lg:grid-cols-2 lg:items-start\">\n            <div class=\"space-y-6\">\n              <p class=\"text-primary text-sm font-medium tracking-widest uppercase\">Contact</p>\n              <h2 class=\"text-3xl font-semibold tracking-tight sm:text-4xl\">Talk to our team</h2>\n              <p class=\"text-muted-foreground max-w-md\">\n                Questions about pricing, onboarding, or a custom plan? Send a note and we'll get back within one business\n                day.\n              </p>\n\n              <ul class=\"space-y-3\">\n                <li class=\"flex items-center gap-3\">\n                  <span class=\"bg-muted text-foreground flex size-9 items-center justify-center rounded-lg\">\n                    ${icon(Mail, 'mail', 'size-4')}\n                  </span>\n                  <span class=\"text-sm\">hello@example.com</span>\n                </li>\n                <li class=\"flex items-center gap-3\">\n                  <span class=\"bg-muted text-foreground flex size-9 items-center justify-center rounded-lg\">\n                    ${icon(Phone, 'phone', 'size-4')}\n                  </span>\n                  <span class=\"text-sm\">+1 (555) 010-2030</span>\n                </li>\n                <li class=\"flex items-center gap-3\">\n                  <span class=\"bg-muted text-foreground flex size-9 items-center justify-center rounded-lg\">\n                    ${icon(MapPin, 'map-pin', 'size-4')}\n                  </span>\n                  <span class=\"text-sm\">${this.locationLabel}</span>\n                </li>\n              </ul>\n\n              <div class=\"h-56 overflow-hidden rounded-xl border\">\n                ${this.accessToken\n                  ? html`<uip-map\n                      access-token=${this.accessToken}\n                      .center=${this.location}\n                      zoom=\"11\"\n                      muted\n                      class=\"size-full\"\n                    >\n                      <uip-map-marker longitude=${this.location[0]} latitude=${this.location[1]} anchor=\"bottom\">\n                        <svg viewBox=\"0 0 24 24\" width=\"26\" height=\"34\" class=\"text-primary drop-shadow\">\n                          <path\n                            d=\"M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7z\"\n                            fill=\"currentColor\"\n                            stroke=\"#fff\"\n                            stroke-width=\"1.5\"\n                          />\n                          <circle cx=\"12\" cy=\"9\" r=\"2.6\" fill=\"#fff\" />\n                        </svg>\n                      </uip-map-marker>\n                    </uip-map>`\n                  : html`<div class=\"bg-muted text-muted-foreground flex size-full items-center justify-center gap-2 text-sm\">\n                      ${icon(MapPin, 'map-pin', 'size-4')} ${this.locationLabel}\n                    </div>`}\n              </div>\n            </div>\n\n            <div\n              data-uipkge=\"\"\n              data-slot=\"card\"\n              class=\"bg-card text-card-foreground rounded-xl border border-border shadow-sm transition-colors duration-150 overflow-hidden\"\n            >\n              ${!this.sent\n                ? html`<div\n                      data-uipkge=\"\"\n                      data-slot=\"card-header\"\n                      class=\"grid auto-rows-min grid-cols-[minmax(0,1fr)] grid-rows-[auto_auto] items-start gap-1.5 p-6 has-data-[slot=card-action]:grid-cols-[minmax(0,1fr)_auto]\"\n                    >\n                      <h3 data-uipkge=\"\" data-slot=\"card-title\" class=\"leading-none font-semibold tracking-tight\">\n                        Send a message\n                      </h3>\n                      <p data-uipkge=\"\" data-slot=\"card-description\" class=\"text-muted-foreground text-sm\">\n                        We'll route it to the right person.\n                      </p>\n                    </div>\n                    <div data-uipkge=\"\" data-slot=\"card-content\" class=\"space-y-4 p-6 pt-0\">\n                      <div class=\"grid gap-4 sm:grid-cols-2\">\n                        <div class=\"space-y-1.5\">\n                          <uip-label for=\"cu-name\">Name</uip-label>\n                          <uip-input\n                            id=\"cu-name\"\n                            .value=${this.name}\n                            @input=${(e: Event) => {\n                              this.name = (e.target as UipInput).value\n                            }}\n                            placeholder=\"Jane Cooper\"\n                          ></uip-input>\n                        </div>\n                        <div class=\"space-y-1.5\">\n                          <uip-label for=\"cu-email\">Email</uip-label>\n                          <uip-input\n                            id=\"cu-email\"\n                            .value=${this.email}\n                            @input=${(e: Event) => {\n                              this.email = (e.target as UipInput).value\n                            }}\n                            type=\"email\"\n                            placeholder=\"jane@company.com\"\n                          ></uip-input>\n                        </div>\n                      </div>\n                      <div class=\"space-y-1.5\">\n                        <uip-label for=\"cu-company\">Company</uip-label>\n                        <uip-input\n                          id=\"cu-company\"\n                          .value=${this.company}\n                          @input=${(e: Event) => {\n                            this.company = (e.target as UipInput).value\n                          }}\n                          placeholder=\"Acme Inc.\"\n                        ></uip-input>\n                      </div>\n                      <div class=\"space-y-1.5\">\n                        <uip-label>Subject</uip-label>\n                        <uip-select\n                          placeholder=\"Choose a topic\"\n                          .value=${this.subject}\n                          @change=${(e: Event) => {\n                            this.subject = (e.target as UipSelect).value\n                          }}\n                        >\n                          <option value=\"sales\">Sales</option>\n                          <option value=\"support\">Support</option>\n                          <option value=\"partnership\">Partnership</option>\n                        </uip-select>\n                      </div>\n                      <div class=\"space-y-1.5\">\n                        <uip-label for=\"cu-message\">Message</uip-label>\n                        <uip-textarea\n                          id=\"cu-message\"\n                          .value=${this.message}\n                          @input=${(e: Event) => {\n                            this.message = (e.target as UipTextarea).value ?? ''\n                          }}\n                          rows=\"4\"\n                          placeholder=\"How can we help?\"\n                        ></uip-textarea>\n                      </div>\n                      <uip-button class=\"w-full\" ?disabled=${!this.canSubmit} @click=${this.submit}>\n                        ${icon(Send, 'send', 'size-4')} Send message\n                      </uip-button>\n                    </div>`\n                : html`<div\n                      data-uipkge=\"\"\n                      data-slot=\"card-content\"\n                      class=\"flex flex-col items-center gap-3 p-6 py-16 pt-0 text-center\"\n                    >\n                      <span class=\"bg-success/10 text-success flex size-12 items-center justify-center rounded-full\">\n                        ${icon(CheckCircle2, 'circle-check-big', 'size-6')}\n                      </span>\n                      <p class=\"text-lg font-semibold\">Message sent</p>\n                      <p class=\"text-muted-foreground max-w-xs text-sm\">\n                        Thanks, ${this.name} — we'll reply to ${this.email} within one business day.\n                      </p>\n                      <uip-button\n                        variant=\"outline\"\n                        @click=${() => {\n                          this.sent = false\n                        }}\n                      >\n                        Send another\n                      </uip-button>\n                    </div>`}\n            </div>\n          </div>\n        </div>\n      </section>\n    `\n  }\n}\n\ncustomElements.get('uip-contact-us') || customElements.define('uip-contact-us', UipContactUs)\n\ndeclare global {\n  interface HTMLElementTagNameMap {\n    'uip-contact-us': UipContactUs\n  }\n}\n",
      "type": "registry:file",
      "target": "src/uip/blocks/contact-us/contact-us.ts"
    }
  ],
  "dependencies": [
    "lit",
    "lucide"
  ],
  "registryDependencies": [
    "https://uipkge.dev/r/lit/button.json",
    "https://uipkge.dev/r/lit/input.json",
    "https://uipkge.dev/r/lit/label.json",
    "https://uipkge.dev/r/lit/lit-core.json",
    "https://uipkge.dev/r/lit/map.json",
    "https://uipkge.dev/r/lit/select.json",
    "https://uipkge.dev/r/lit/textarea.json"
  ]
}
