{
  "$schema": "https://shadcn-vue.com/schema/registry-item.json",
  "name": "feature-matrix-table-dense",
  "title": "Feature Matrix Table Dense",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-vue/blocks/feature-matrix-table-dense/FeatureMatrixTableDense.vue",
      "content": "<script setup lang=\"ts\">\nimport { computed, ref } from 'vue'\nimport { ArrowRight, Check, CheckCircle2, ChevronDown, ChevronRight, Filter, Minus, Search } from 'lucide-vue-next'\nimport { cn } from '@/lib/utils'\n\nexport interface MatrixFeature {\n  name: string\n  description: string\n  uipkge: boolean | string\n  npmMonolith: boolean | string\n  inHouse: boolean | string\n}\n\nexport interface MatrixCategory {\n  id: string\n  title: string\n  features: MatrixFeature[]\n}\n\nexport interface FeatureMatrixTableDenseProps {\n  title?: string\n  description?: string\n  categories?: MatrixCategory[]\n  class?: string\n}\n\nconst DEFAULT_CATEGORIES: MatrixCategory[] = [\n  {\n    id: 'architecture',\n    title: 'Architecture & Runtime Ownership',\n    features: [\n      {\n        name: 'Zero NPM Runtime Dependency',\n        description: 'Source code copied directly into your repository with 100% ownership.',\n        uipkge: true,\n        npmMonolith: false,\n        inHouse: true,\n      },\n      {\n        name: 'Dual Framework 1:1 Parity',\n        description: 'Synchronized Vue 3.5 and React 19 primitives with identical token bindings.',\n        uipkge: true,\n        npmMonolith: false,\n        inHouse: 'High Cost',\n      },\n      {\n        name: 'Deterministic Tree-Shaking',\n        description: 'Zero dead code in final production bundles; only imported components compile.',\n        uipkge: true,\n        npmMonolith: 'Partial',\n        inHouse: true,\n      },\n      {\n        name: 'Tailwind CSS v4 Native Tokens',\n        description: 'Direct @theme inline OKLCH bindings without legacy tailwind.config.js overhead.',\n        uipkge: true,\n        npmMonolith: false,\n        inHouse: 'Manual',\n      },\n    ],\n  },\n  {\n    id: 'developer-experience',\n    title: 'Developer Experience & Tooling',\n    features: [\n      {\n        name: 'Headless Primitive Foundation',\n        description: 'Powered by battle-tested Reka UI and Radix UI accessible state machines.',\n        uipkge: true,\n        npmMonolith: 'Proprietary',\n        inHouse: 'Custom',\n      },\n      {\n        name: 'CLI Direct Add Workflow',\n        description: 'Install via npx shadcn-vue add @uipkge/<name> with automated dependency resolution.',\n        uipkge: true,\n        npmMonolith: false,\n        inHouse: false,\n      },\n      {\n        name: 'Automated Parity Check Suite',\n        description: 'Built-in AST parity verification scripts guarding against framework drift.',\n        uipkge: true,\n        npmMonolith: false,\n        inHouse: false,\n      },\n    ],\n  },\n  {\n    id: 'enterprise',\n    title: 'Enterprise & Security Compliance',\n    features: [\n      {\n        name: 'Zero Supply-Chain Vulnerabilities',\n        description: 'No third-party registry packages or compromised transitive semver updates.',\n        uipkge: true,\n        npmMonolith: false,\n        inHouse: true,\n      },\n      {\n        name: 'Full Customization Freedom',\n        description: 'Modify any CSS class, DOM attribute, or internal logic without breaking upstream.',\n        uipkge: true,\n        npmMonolith: 'Limited',\n        inHouse: true,\n      },\n      {\n        name: 'WCAG 2.1 AA Accessibility',\n        description: 'Keyboard ergonomics, focus rings, ARIA roles, and screen-reader audited.',\n        uipkge: true,\n        npmMonolith: 'Partial',\n        inHouse: 'Manual',\n      },\n    ],\n  },\n]\n\nconst props = withDefaults(defineProps<FeatureMatrixTableDenseProps>(), {\n  title: 'Engineered for teams who demand complete source code control.',\n  description:\n    'Compare how unbundled registry components stack up against traditional monolithic npm packages and bespoke in-house design systems.',\n})\n\nconst activeCategories = computed(() => props.categories ?? DEFAULT_CATEGORIES)\nconst searchQuery = ref('')\nconst onlyDifferences = ref(false)\nconst collapsedCategories = ref<Record<string, boolean>>({})\n\nfunction toggleCategory(catId: string) {\n  collapsedCategories.value[catId] = !collapsedCategories.value[catId]\n}\n\nconst filteredCategories = computed(() => {\n  const query = searchQuery.value.toLowerCase().trim()\n\n  return activeCategories.value\n    .map((cat) => {\n      const filteredFeatures = cat.features.filter((f) => {\n        const matchesQuery =\n          !query || f.name.toLowerCase().includes(query) || f.description.toLowerCase().includes(query)\n\n        if (!matchesQuery) return false\n\n        if (onlyDifferences.value) {\n          const isSame = f.uipkge === f.npmMonolith && f.npmMonolith === f.inHouse\n          if (isSame) return false\n        }\n\n        return true\n      })\n\n      return {\n        ...cat,\n        features: filteredFeatures,\n      }\n    })\n    .filter((cat) => cat.features.length > 0)\n})\n</script>\n\n<template>\n  <section\n    data-slot=\"feature-matrix-table-dense\"\n    :class=\"cn('bg-background relative overflow-hidden py-16 sm:py-24', props.class)\"\n  >\n    <div class=\"mx-auto max-w-7xl px-4 sm:px-6 lg:px-8\">\n      <!-- Section Header -->\n      <div class=\"mx-auto max-w-3xl space-y-4 text-center\">\n        <a\n          href=\"#technical-matrix\"\n          class=\"group border-border/80 bg-secondary/60 hover:bg-secondary text-foreground inline-flex items-center gap-2 rounded-full border px-3.5 py-1 text-xs font-medium shadow-2xs transition-colors\"\n        >\n          <CheckCircle2 class=\"text-primary size-3.5\" />\n          <span>Technical Architecture Comparison</span>\n          <ArrowRight class=\"text-muted-foreground size-3 transition-transform group-hover:translate-x-0.5\" />\n        </a>\n\n        <h2 class=\"text-foreground text-3xl font-bold tracking-tight sm:text-4xl\">\n          {{ title }}\n        </h2>\n\n        <p class=\"text-muted-foreground text-base sm:text-lg\">\n          {{ description }}\n        </p>\n      </div>\n\n      <!-- Controls Strip: Search & Filter Toggles -->\n      <div class=\"border-border mt-10 flex flex-col gap-3 border-b pb-4 sm:flex-row sm:items-center sm:justify-between\">\n        <div class=\"relative w-full sm:w-72\">\n          <Search class=\"text-muted-foreground absolute top-1/2 left-2.5 size-3.5 -translate-y-1/2\" />\n          <input\n            v-model=\"searchQuery\"\n            type=\"text\"\n            placeholder=\"Filter capabilities...\"\n            class=\"border-border bg-muted/40 text-foreground placeholder:text-muted-foreground focus-visible:ring-primary h-8 w-full rounded-md border pr-3 pl-8 text-xs focus-visible:ring-1 focus-visible:outline-none\"\n          />\n        </div>\n\n        <div class=\"flex items-center gap-2\">\n          <button\n            type=\"button\"\n            :class=\"\n              cn(\n                'flex items-center gap-1.5 rounded-md border px-2.5 py-1.5 text-xs font-medium transition-colors',\n                onlyDifferences\n                  ? 'border-primary bg-primary/10 text-primary'\n                  : 'border-border bg-card text-muted-foreground hover:text-foreground',\n              )\n            \"\n            @click=\"onlyDifferences = !onlyDifferences\"\n          >\n            <Filter class=\"size-3\" />\n            <span>Show Differences Only</span>\n          </button>\n        </div>\n      </div>\n\n      <!-- Dense Comparison Matrix Table -->\n      <div class=\"border-border bg-card mt-6 overflow-x-auto rounded-lg border shadow-xs\">\n        <table class=\"w-full text-left text-xs\">\n          <!-- Table Sticky Header -->\n          <thead class=\"border-border bg-muted/50 text-foreground border-b font-medium\">\n            <tr>\n              <th scope=\"col\" class=\"w-1/2 py-3.5 pr-3 pl-4 text-sm font-semibold sm:w-5/12 sm:pl-6\">\n                Capability & Specification\n              </th>\n              <th\n                scope=\"col\"\n                class=\"text-primary bg-primary/5 border-border border-x px-3 py-3.5 text-center font-bold sm:w-3/12\"\n              >\n                <div class=\"flex flex-col items-center\">\n                  <span>UIPKGE Registry</span>\n                  <span class=\"text-muted-foreground text-xs font-normal\">Unbundled Code Ownership</span>\n                </div>\n              </th>\n              <th scope=\"col\" class=\"text-muted-foreground px-3 py-3.5 text-center sm:w-2/12\">\n                <div class=\"flex flex-col items-center\">\n                  <span>NPM Monolith</span>\n                  <span class=\"text-muted-foreground text-xs font-normal\">e.g. MUI / AntD</span>\n                </div>\n              </th>\n              <th scope=\"col\" class=\"text-muted-foreground px-3 py-3.5 text-center sm:w-2/12\">\n                <div class=\"flex flex-col items-center\">\n                  <span>In-House Bespoke</span>\n                  <span class=\"text-muted-foreground text-xs font-normal\">Built from scratch</span>\n                </div>\n              </th>\n            </tr>\n          </thead>\n\n          <!-- Table Body with Collapsible Category Rows -->\n          <tbody class=\"divide-border/60 divide-y\">\n            <template v-for=\"category in filteredCategories\" :key=\"category.id\">\n              <!-- Category Header Row -->\n              <tr\n                class=\"bg-muted/30 hover:bg-muted/50 cursor-pointer transition-colors select-none\"\n                @click=\"toggleCategory(category.id)\"\n              >\n                <td colspan=\"4\" class=\"py-2.5 pr-3 pl-4 sm:pl-6\">\n                  <div class=\"text-foreground flex items-center gap-1.5 text-xs font-bold tracking-wider uppercase\">\n                    <ChevronDown v-if=\"!collapsedCategories[category.id]\" class=\"text-muted-foreground size-3.5\" />\n                    <ChevronRight v-else class=\"text-muted-foreground size-3.5\" />\n                    <span>{{ category.title }}</span>\n                    <span class=\"text-muted-foreground ml-1 text-xs font-normal\">({{ category.features.length }})</span>\n                  </div>\n                </td>\n              </tr>\n\n              <!-- Feature Items Rows -->\n              <template v-if=\"!collapsedCategories[category.id]\">\n                <tr\n                  v-for=\"(feature, fIdx) in category.features\"\n                  :key=\"fIdx\"\n                  class=\"hover:bg-muted/10 transition-colors\"\n                >\n                  <!-- Feature Info (Col 1) -->\n                  <td class=\"space-y-0.5 py-3 pr-3 pl-4 sm:pl-6\">\n                    <div class=\"text-foreground font-semibold\">{{ feature.name }}</div>\n                    <div class=\"text-muted-foreground text-xs\">{{ feature.description }}</div>\n                  </td>\n\n                  <!-- UIPKGE (Col 2 - Highlighted) -->\n                  <td class=\"bg-primary/5 border-border border-x px-3 py-3 text-center\">\n                    <div class=\"flex items-center justify-center\">\n                      <span\n                        v-if=\"feature.uipkge === true\"\n                        class=\"bg-success/10 text-success inline-flex size-5 items-center justify-center rounded-full font-bold\"\n                      >\n                        <Check class=\"size-3.5 stroke-[2.5]\" />\n                      </span>\n                      <span\n                        v-else-if=\"typeof feature.uipkge === 'string'\"\n                        class=\"bg-muted text-foreground rounded px-1.5 py-0.5 font-mono text-xs font-medium\"\n                      >\n                        {{ feature.uipkge }}\n                      </span>\n                      <span v-else class=\"text-muted-foreground\">\n                        <Minus class=\"size-3.5\" />\n                      </span>\n                    </div>\n                  </td>\n\n                  <!-- NPM Monolith (Col 3) -->\n                  <td class=\"px-3 py-3 text-center\">\n                    <div class=\"flex items-center justify-center\">\n                      <span\n                        v-if=\"feature.npmMonolith === true\"\n                        class=\"bg-success/10 text-success inline-flex size-5 items-center justify-center rounded-full\"\n                      >\n                        <Check class=\"size-3.5\" />\n                      </span>\n                      <span\n                        v-else-if=\"typeof feature.npmMonolith === 'string'\"\n                        class=\"bg-muted/60 text-muted-foreground rounded px-1.5 py-0.5 font-mono text-xs font-medium\"\n                      >\n                        {{ feature.npmMonolith }}\n                      </span>\n                      <span v-else class=\"text-muted-foreground/60\">\n                        <Minus class=\"size-3.5\" />\n                      </span>\n                    </div>\n                  </td>\n\n                  <!-- In-House Bespoke (Col 4) -->\n                  <td class=\"px-3 py-3 text-center\">\n                    <div class=\"flex items-center justify-center\">\n                      <span\n                        v-if=\"feature.inHouse === true\"\n                        class=\"bg-success/10 text-success inline-flex size-5 items-center justify-center rounded-full\"\n                      >\n                        <Check class=\"size-3.5\" />\n                      </span>\n                      <span\n                        v-else-if=\"typeof feature.inHouse === 'string'\"\n                        class=\"bg-muted/60 text-muted-foreground rounded px-1.5 py-0.5 font-mono text-xs font-medium\"\n                      >\n                        {{ feature.inHouse }}\n                      </span>\n                      <span v-else class=\"text-muted-foreground/60\">\n                        <Minus class=\"size-3.5\" />\n                      </span>\n                    </div>\n                  </td>\n                </tr>\n              </template>\n            </template>\n          </tbody>\n        </table>\n      </div>\n    </div>\n  </section>\n</template>\n",
      "type": "registry:block",
      "target": "~/app/components/blocks/feature-matrix-table-dense/FeatureMatrixTableDense.vue"
    },
    {
      "path": "packages/registry-vue/blocks/feature-matrix-table-dense/index.ts",
      "content": "export { default as FeatureMatrixTableDense } from './FeatureMatrixTableDense.vue'\nexport type { FeatureMatrixTableDenseProps, MatrixCategory, MatrixFeature } from './FeatureMatrixTableDense.vue'\n",
      "type": "registry:block",
      "target": "~/app/components/blocks/feature-matrix-table-dense/index.ts"
    }
  ],
  "dependencies": [
    "lucide-vue-next"
  ],
  "devDependencies": [],
  "registryDependencies": [],
  "description": "Dense Linear-style technical specification matrix table with collapsible sections and search filtering.",
  "categories": [
    "feature",
    "marketing"
  ]
}