{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "primitive-cards-block",
  "title": "Primitive Run Cards",
  "description": "Each Retab primitive's result framed as a run card — a document thumbnail with a status pill and the primitive's output in the card body. Classification shows the page with its category and reasoning; split a mini page rail of color-keyed subdocuments; partition a keyed-chunk legend with an overlap ribbon; parse the page rendered as markdown; extract the page with each field's source box drawn over it. Composes the primitive-run-cards components over sample results.",
  "registryDependencies": [
    "@retab/primitive-run-cards"
  ],
  "files": [
    {
      "path": "registry/new-york-v4/blocks/primitive-cards-block.tsx",
      "content": "\"use client\";\n\nimport { toSegments } from \"@/lib/segments\";\nimport {\n  ClassificationRunCard,\n  ExtractRunCard,\n  ParseRunCard,\n  PartitionRunCard,\n  SplitRunCard,\n  type ExtractRunCardField,\n} from \"@/components/ui/primitive-run-cards\";\nimport type { ClassifyResult } from \"@/components/viewers/lib/classify-types\";\nimport type { PartitionResult } from \"@/components/viewers/lib/partition-types\";\nimport type { SplitView } from \"@/components/viewers/lib/split-types\";\nimport extractSample from \"@/components/viewers/sample-data/extract.json\";\nimport parseSample from \"@/components/viewers/sample-data/parse.json\";\n\n// ── Per-primitive sample results, each framed as a completed \"run\". ───────────\n\nconst CLASSIFICATION = {\n  file: { name: \"loan-application.pdf\", type: \"application/pdf\" },\n  thumbnail: \"/samples/loan-application-page-1.png\",\n  result: {\n    category: \"Loan Application\",\n    reasoning:\n      \"A Uniform Residential Loan Application (Form 1003): borrower, employment, and property details for a mortgage request.\",\n  } satisfies ClassifyResult,\n};\n\nconst SPLIT = {\n  file: { name: \"an-image-is-worth-16x16-words.pdf\", type: \"application/pdf\" },\n  thumbnail: \"/samples/an-image-is-worth-16x16-words-page-1.png\",\n  result: {\n    output: [\n      { name: \"Title, Abstract & Introduction\", pages: [1] },\n      { name: \"Related Work\", pages: [2] },\n      { name: \"Method\", pages: [3] },\n      { name: \"Experiments\", pages: [4, 5, 6, 7, 8] },\n      { name: \"Conclusion & References\", pages: [9, 10, 11, 12] },\n      { name: \"Appendix\", pages: [13, 14, 15, 16, 17, 18, 19, 20, 21, 22] },\n    ],\n  } satisfies SplitView,\n};\n\nconst PARTITION = {\n  file: { name: \"an-image-is-worth-16x16-words.pdf\", type: \"application/pdf\" },\n  thumbnail: \"/samples/an-image-is-worth-16x16-words-page-1.png\",\n  result: {\n    output: [\n      { key: \"abstract\", pages: [1] },\n      { key: \"introduction\", pages: [1, 2] },\n      { key: \"related_work\", pages: [2] },\n      { key: \"method\", pages: [3, 4] },\n      { key: \"experiments\", pages: [4, 5, 6, 7, 8] },\n      { key: \"conclusion\", pages: [9] },\n      { key: \"references\", pages: [9, 10, 11, 12] },\n      { key: \"appendix\", pages: [13, 14, 15, 16, 17, 18, 19, 20, 21, 22] },\n    ],\n  } satisfies Pick<PartitionResult, \"output\">,\n};\n\nconst PARSE = {\n  file: { name: \"bank-statement.pdf\", type: \"application/pdf\" },\n  markdown: (parseSample.output.pages[0] as string)\n    .split(\"\\n\")\n    .slice(0, 18)\n    .join(\"\\n\"),\n};\n\nconst EXTRACT = {\n  file: { name: \"bank-statement.pdf\", type: \"application/pdf\" },\n  thumbnail: \"/samples/bank-statement-page-1.png\",\n  // The sample carries a `Source` per value (normalized pdf_bbox anchors); the\n  // card tints each field and draws its source box.\n  fields: extractSample as ExtractRunCardField[],\n};\n\n/**\n * Primitive run cards — each Retab primitive's result framed as a run card,\n * composing {@link ClassificationRunCard}, {@link SplitRunCard},\n * {@link PartitionRunCard}, {@link ParseRunCard}, and {@link ExtractRunCard}\n * over sample results. The cards are prop-driven, so the same components render\n * a live workflow run's per-block result.\n */\nexport function PrimitiveCardsBlock() {\n  return (\n    <div className=\"bg-background flex h-full min-h-[680px] flex-col\">\n      <div className=\"min-h-0 flex-1 overflow-auto p-6\">\n        <div className=\"mx-auto grid max-w-5xl grid-cols-1 items-start gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n          <ClassificationRunCard\n            file={CLASSIFICATION.file}\n            previewImageUrl={CLASSIFICATION.thumbnail}\n            category={CLASSIFICATION.result.category}\n            reasoning={CLASSIFICATION.result.reasoning}\n          />\n          <SplitRunCard\n            file={SPLIT.file}\n            previewImageUrl={SPLIT.thumbnail}\n            segments={toSegments(SPLIT.result.output)}\n          />\n          <PartitionRunCard\n            file={PARTITION.file}\n            previewImageUrl={PARTITION.thumbnail}\n            segments={toSegments(PARTITION.result.output)}\n          />\n          <ParseRunCard file={PARSE.file} markdown={PARSE.markdown} />\n          <ExtractRunCard\n            file={EXTRACT.file}\n            previewImageUrl={EXTRACT.thumbnail}\n            fields={EXTRACT.fields}\n          />\n        </div>\n      </div>\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "@components/blocks/primitive-cards-block.tsx"
    },
    {
      "path": "components/viewers/lib/classify-types.ts",
      "content": "// Classification result shape for the classifier viewer.\n\nexport interface ClassifyResult {\n  category: string;\n  reasoning?: string;\n  candidates?: readonly ClassifyCandidate[];\n  consensus?: ClassifyConsensus | null;\n}\n\nexport interface ClassifyCandidate {\n  category: string;\n  description?: string;\n}\n\nexport interface ClassifyConsensus {\n  choices?: readonly ClassifyConsensusChoice[];\n  /** Consensus likelihood score (0.0-1.0) of the winning classification. */\n  likelihoods?: number | null;\n}\n\nexport interface ClassifyConsensusChoice {\n  category: string;\n  reasoning?: string;\n}\n",
      "type": "registry:lib",
      "target": "@components/viewers/lib/classify-types.ts"
    },
    {
      "path": "components/viewers/lib/split-types.ts",
      "content": "// Split result shapes (the structural subset the viewer needs), mirrored from\n// the Retab dashboard's SplitView.\n\nimport type { PartitionChunk } from \"@/components/viewers/lib/partition-types\";\n\nexport interface SplitResult {\n  name: string;\n  /** 1-indexed pages assigned to this subdocument. */\n  pages: number[];\n  /** Frontend-only overlay carried through by the split viewer. */\n  partitions?: PartitionChunk[];\n}\n\nexport interface SplitSubdocumentLikelihood {\n  /** Consensus confidence for the subdocument label. */\n  name?: number | null;\n  /** Consensus confidence per assigned page, aligned with the output pages. */\n  pages?: number[] | null;\n}\n\nexport interface SplitViewConsensus {\n  choices?: SplitResult[][];\n  likelihoods?: SplitSubdocumentLikelihood[] | null;\n}\n\nexport interface SplitView {\n  output: SplitResult[];\n  consensus?: SplitViewConsensus | null;\n  usage?: { credits: number } | null;\n}\n\nexport function asSplitView(\n  payload:\n    | { output?: unknown; consensus?: unknown; usage?: unknown }\n    | null\n    | undefined,\n): SplitView | null {\n  if (!payload || !Array.isArray(payload.output)) return null;\n  return {\n    output: payload.output as SplitResult[],\n    consensus: (payload.consensus ?? null) as SplitViewConsensus | null,\n    usage: (payload.usage ?? null) as SplitView[\"usage\"],\n  };\n}\n\nexport function getSplitVotes(\n  splitView: SplitView | null | undefined,\n  splitIndex: number,\n): SplitResult[] {\n  const choices = splitView?.consensus?.choices;\n  if (!choices?.length) return [];\n  return choices.flatMap((choice) => {\n    const split = choice[splitIndex];\n    return split ? [split] : [];\n  });\n}\n",
      "type": "registry:lib",
      "target": "@components/viewers/lib/split-types.ts"
    },
    {
      "path": "components/viewers/lib/partition-types.ts",
      "content": "// Partition result shapes, mirrored from the Retab API / dashboard.\n\nexport interface PartitionChunk {\n  key: string;\n  /** 1-indexed pages assigned to this chunk. */\n  pages: number[];\n}\n\nexport interface PartitionChunkLikelihood {\n  key: number | null;\n  pages: number[];\n}\n\nexport interface PartitionConsensus {\n  choices: PartitionChunk[][];\n  likelihoods: PartitionChunkLikelihood[] | null;\n}\n\nexport interface PartitionUsage {\n  credits: number;\n}\n\nexport interface PartitionResult {\n  output: PartitionChunk[];\n  consensus: PartitionConsensus;\n  usage: PartitionUsage | null;\n}\n",
      "type": "registry:lib",
      "target": "@components/viewers/lib/partition-types.ts"
    },
    {
      "path": "components/viewers/sample-data/extract.json",
      "content": "[\n  {\n    \"key\": \"accountNumber\",\n    \"label\": \"Account number\",\n    \"value\": \"000009752\",\n    \"source\": {\n      \"content\": \"000009752\",\n      \"anchor\": {\n        \"kind\": \"pdf_bbox\",\n        \"page\": 1,\n        \"left\": 0.8111,\n        \"top\": 0.1772,\n        \"width\": 0.0736,\n        \"height\": 0.0127\n      }\n    }\n  },\n  {\n    \"key\": \"statementDate\",\n    \"label\": \"Statement date\",\n    \"value\": \"July 8, 2003\",\n    \"source\": {\n      \"content\": \"July 8, 2003\",\n      \"anchor\": {\n        \"kind\": \"pdf_bbox\",\n        \"page\": 1,\n        \"left\": 0.8021,\n        \"top\": 0.1933,\n        \"width\": 0.0826,\n        \"height\": 0.0127\n      }\n    }\n  },\n  {\n    \"key\": \"beginningBalance\",\n    \"label\": \"Beginning balance\",\n    \"value\": \"$10,959.87\",\n    \"source\": {\n      \"content\": \"$10,959.87\",\n      \"anchor\": {\n        \"kind\": \"pdf_bbox\",\n        \"page\": 1,\n        \"left\": 0.8136,\n        \"top\": 0.2964,\n        \"width\": 0.0675,\n        \"height\": 0.0116\n      }\n    }\n  },\n  {\n    \"key\": \"endingBalance\",\n    \"label\": \"Ending balance\",\n    \"value\": \"$6,046.95\",\n    \"source\": {\n      \"content\": \"$6,046.95\",\n      \"anchor\": {\n        \"kind\": \"pdf_bbox\",\n        \"page\": 1,\n        \"left\": 0.8211,\n        \"top\": 0.3466,\n        \"width\": 0.06,\n        \"height\": 0.0116\n      }\n    }\n  },\n  {\n    \"key\": \"totalDeposits\",\n    \"label\": \"Total deposits & credits\",\n    \"value\": \"$2,670.93\",\n    \"source\": {\n      \"content\": \"+2,670.93\",\n      \"anchor\": {\n        \"kind\": \"pdf_bbox\",\n        \"page\": 1,\n        \"left\": 0.8207,\n        \"top\": 0.3116,\n        \"width\": 0.0603,\n        \"height\": 0.0116\n      }\n    }\n  },\n  {\n    \"key\": \"atmWithdrawal\",\n    \"label\": \"ATM withdrawal\",\n    \"value\": \"$69.01\",\n    \"source\": {\n      \"content\": \"$69.01\",\n      \"anchor\": {\n        \"kind\": \"pdf_bbox\",\n        \"page\": 1,\n        \"left\": 0.715,\n        \"top\": 0.4839,\n        \"width\": 0.0412,\n        \"height\": 0.0116\n      }\n    }\n  }\n]\n",
      "type": "registry:file",
      "target": "@components/viewers/sample-data/extract.json"
    },
    {
      "path": "components/viewers/sample-data/parse.json",
      "content": "{\n  \"output\": {\n    \"pages\": [\n      \"# Commerce Bank — Bank Statement\\n\\n| Field | Value |\\n| --- | --- |\\n| Account holder | Jane Customer |\\n| Account type | Connections Checking |\\n| Account number | 000009752 |\\n| Statement date | June 5, 2003 |\\n| Statement period | May 3, 2003 through June 5, 2003 |\\n\\n## Account Summary\\n\\n| Description | Amount |\\n| --- | ---: |\\n| Beginning Balance on May 3, 2003 | $7,126.11 |\\n| Deposits & Other Credits | +$3,615.08 |\\n| ATM Withdrawals & Debits | -$20.00 |\\n| VISA Check Card Purchases & Debits | -$0.00 |\\n| Withdrawals & Other Debits | -$0.00 |\\n| Checks Paid | -$200.00 |\\n| Ending Balance on June 5, 2003 | $10,521.19 |\\n\\n## Deposits & Other Credits\\n\\n| Description | Ref Nbr | Date Credited | Amount |\\n| --- | --- | --- | ---: |\\n| Deposit | 130012345 | 05-15 | $3,615.08 |\\n| Total Deposits & Other Credits | | | $3,615.08 |\\n\\n## ATM Withdrawals & Debits\\n\\n| Description | Tran Date | Date Paid | Amount |\\n| --- | --- | --- | ---: |\\n| ATM Withdrawal — 1000 Walnut St M119, Kansas City MO 00005678 | 05-18 | 05-19 | $20.00 |\\n| Total ATM Withdrawals & Debits | | | $20.00 |\\n\\n## Checks Paid\\n\\n| Date Paid | Check Number | Amount | Reference Number |\\n| --- | --- | ---: | --- |\\n| 05-12 | 1001 | $75.00 | 00012576589 |\\n| 05-18 | 1002 | $30.00 | 00036547854 |\\n| 05-24 | 1003 | $200.00 | 00094613547 |\\n| Total Checks Paid | | $305.00 | |\\n\"\n    ],\n    \"text\": \"# Commerce Bank — Bank Statement\\n\\n| Field | Value |\\n| --- | --- |\\n| Account holder | Jane Customer |\\n| Account type | Connections Checking |\\n| Account number | 000009752 |\\n| Statement date | June 5, 2003 |\\n| Statement period | May 3, 2003 through June 5, 2003 |\\n\\n## Account Summary\\n\\n| Description | Amount |\\n| --- | ---: |\\n| Beginning Balance on May 3, 2003 | $7,126.11 |\\n| Deposits & Other Credits | +$3,615.08 |\\n| ATM Withdrawals & Debits | -$20.00 |\\n| VISA Check Card Purchases & Debits | -$0.00 |\\n| Withdrawals & Other Debits | -$0.00 |\\n| Checks Paid | -$200.00 |\\n| Ending Balance on June 5, 2003 | $10,521.19 |\\n\\n## Deposits & Other Credits\\n\\n| Description | Ref Nbr | Date Credited | Amount |\\n| --- | --- | --- | ---: |\\n| Deposit | 130012345 | 05-15 | $3,615.08 |\\n| Total Deposits & Other Credits | | | $3,615.08 |\\n\\n## ATM Withdrawals & Debits\\n\\n| Description | Tran Date | Date Paid | Amount |\\n| --- | --- | --- | ---: |\\n| ATM Withdrawal — 1000 Walnut St M119, Kansas City MO 00005678 | 05-18 | 05-19 | $20.00 |\\n| Total ATM Withdrawals & Debits | | | $20.00 |\\n\\n## Checks Paid\\n\\n| Date Paid | Check Number | Amount | Reference Number |\\n| --- | --- | ---: | --- |\\n| 05-12 | 1001 | $75.00 | 00012576589 |\\n| 05-18 | 1002 | $30.00 | 00036547854 |\\n| 05-24 | 1003 | $200.00 | 00094613547 |\\n| Total Checks Paid | | $305.00 | |\\n\"\n  },\n  \"usage\": {\n    \"credits\": 1\n  }\n}\n",
      "type": "registry:file",
      "target": "@components/viewers/sample-data/parse.json"
    }
  ],
  "categories": [
    "primitives"
  ],
  "type": "registry:block"
}