{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "xlsx-sources-block",
  "title": "Excel Sources",
  "description": "Extracted values linked to spreadsheet cells across sheets — hover to switch sheet, highlight the cell, and scroll to it.",
  "registryDependencies": [
    "@retab/xlsx-viewer",
    "@retab/xlsx-source",
    "@retab/document-source",
    "@retab/segmented-document",
    "@retab/source-segmented-document",
    "@retab/source-field-list",
    "@retab/source-field-link",
    "@retab/source-indicator"
  ],
  "files": [
    {
      "path": "registry/new-york-v4/blocks/xlsx-sources-block.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\n\nimport type { Source } from \"@/lib/document-source\";\nimport {\n  FileViewer,\n  FileViewerContent,\n  FileViewerHeader,\n  FileViewerTitle,\n  FileViewerProvider,\n  FileViewerSidebar,\n  FileViewerSidebarContent,\n  FileViewerInset,\n  FileViewerControls,\n  FileViewerViewport,\n} from \"@/components/ui/file-viewer\";\nimport { SegmentedDocumentProvider } from \"@/components/ui/segmented-document-provider\";\nimport { useSegmentedSourceFieldLink } from \"@/components/ui/source-field-link\";\nimport {\n  SourceFieldList,\n  type SourceField,\n} from \"@/components/ui/source-field-list\";\nimport { createSourcesSegmentedDocumentModel } from \"@/components/ui/source-segmented-document-model\";\nimport {\n  sourceToXlsxCell,\n  useXlsxSourceTarget,\n} from \"@/components/ui/xlsx-source\";\nimport { XlsxViewer, type XlsxViewerHandle } from \"@/components/ui/xlsx-viewer\";\nimport xlsxSample from \"@/components/viewers/sample-data/xlsx-sources.json\";\n\nconst XLSX_URL = \"/samples/nvidia-financials-fy2024.xlsx\";\nconst XLSX_SOURCE = {\n  kind: \"url\" as const,\n  url: XLSX_URL,\n  fileName: \"nvidia-financials-fy2024.xlsx\",\n};\n\ntype XlsxField = SourceField & { source: Source };\n\nconst FIELDS = (xlsxSample as XlsxField[]).map((field) => ({\n  ...field,\n  hint:\n    field.source.anchor.kind === \"spreadsheet_cell\"\n      ? `${field.source.anchor.sheet_name ?? `Sheet ${field.source.anchor.sheet_index + 1}`} · ${field.source.anchor.coordinate ?? \"\"}`\n      : undefined,\n}));\nconst FIELD_BY_KEY = new Map(FIELDS.map((field) => [field.key, field]));\nconst SEGMENTED_DOCUMENT = createSourcesSegmentedDocumentModel(\n  FIELDS.map((field) => ({\n    id: field.key,\n    label: field.label,\n    source: field.source,\n  })),\n);\n\n/**\n * Excel sources block — extracted values linked to the spreadsheet cells they\n * came from, across sheets. Hovering a field switches to its sheet, highlights\n * the cell, and scrolls to it. Segmented source interaction owns\n * preview/selection while the XLSX source adapter owns sheet-aware navigation.\n */\nexport function XlsxSourcesBlock() {\n  const viewerRef = React.useRef<XlsxViewerHandle>(null);\n\n  return (\n    <SegmentedDocumentProvider model={SEGMENTED_DOCUMENT}>\n      <XlsxSourcesContent viewerRef={viewerRef} />\n    </SegmentedDocumentProvider>\n  );\n}\n\nfunction XlsxSourcesContent({\n  viewerRef,\n}: {\n  viewerRef: React.RefObject<XlsxViewerHandle | null>;\n}) {\n  const target = useXlsxSourceTarget(viewerRef);\n  const segmentedLink = useSegmentedSourceFieldLink({\n    initialSourcePath: FIELDS[0]?.key,\n  });\n  const link = useTargetedSourceFieldLink({\n    fieldByKey: FIELD_BY_KEY,\n    link: segmentedLink,\n    target,\n  });\n  const activeSource = link.activeSourcePath\n    ? FIELD_BY_KEY.get(link.activeSourcePath)?.source\n    : undefined;\n  const activeCell = sourceToXlsxCell(activeSource);\n\n  return (\n    <FileViewerProvider source={XLSX_SOURCE} defaultSidebarOpen>\n      <FileViewer\n        className=\"bg-background h-full min-h-[680px]\"\n       \n      >\n        <FileViewerHeader>\n            <FileViewerTitle />\n            <FileViewerControls />\n        </FileViewerHeader>\n        <FileViewerContent>\n          <FileViewerInset>\n            <FileViewerViewport>\n              <XlsxViewer\n                ref={viewerRef}\n                source={XLSX_SOURCE}\n                bare\n                className=\"h-full\"\n                controls={false}\n                activeCell={activeCell}\n              />\n            </FileViewerViewport>\n          </FileViewerInset>\n          <FileViewerSidebar\n            aria-label=\"Source fields\"\n            side=\"right\"\n            collapsible=\"none\"\n            width=\"360px\"\n            className=\"border-l\"\n          >\n            <FileViewerSidebarContent>\n              <SourceFieldList fields={FIELDS} link={link} />\n            </FileViewerSidebarContent>\n          </FileViewerSidebar>\n        </FileViewerContent>\n      </FileViewer>\n    </FileViewerProvider>\n  );\n}\n\nfunction useTargetedSourceFieldLink({\n  fieldByKey,\n  link,\n  target,\n}: {\n  fieldByKey: ReadonlyMap<string, XlsxField>;\n  link: ReturnType<typeof useSegmentedSourceFieldLink>;\n  target: ReturnType<typeof useXlsxSourceTarget>;\n}) {\n  const scrollToField = React.useCallback(\n    (path: string, behavior: ScrollBehavior) => {\n      const source = fieldByKey.get(path)?.source;\n      if (source) target.scrollTo?.(source, { behavior });\n    },\n    [fieldByKey, target],\n  );\n  const onSourceHover = React.useCallback(\n    (path: string | null) => {\n      link.onSourceHover(path);\n      if (path) scrollToField(path, \"auto\");\n    },\n    [link, scrollToField],\n  );\n  const selectSourcePath = React.useCallback(\n    (path: string) => {\n      link.selectSourcePath?.(path);\n      scrollToField(path, \"smooth\");\n    },\n    [link, scrollToField],\n  );\n\n  return React.useMemo(\n    () => ({\n      ...link,\n      onSourceHover,\n      selectSourcePath,\n    }),\n    [link, onSourceHover, selectSourcePath],\n  );\n}\n",
      "type": "registry:component",
      "target": "@components/blocks/xlsx-sources-block.tsx"
    },
    {
      "path": "components/viewers/sample-data/xlsx-sources.json",
      "content": "[\n  {\n    \"key\": \"registrantName\",\n    \"label\": \"Registrant name\",\n    \"value\": \"NVIDIA CORP\",\n    \"source\": {\n      \"content\": \"NVIDIA CORP\",\n      \"anchor\": { \"kind\": \"spreadsheet_cell\", \"row\": 10, \"column\": \"B\", \"sheet_index\": 0, \"sheet_name\": \"Cover Page\", \"coordinate\": \"B10\" }\n    }\n  },\n  {\n    \"key\": \"documentType\",\n    \"label\": \"Document type\",\n    \"value\": \"10-K\",\n    \"source\": {\n      \"content\": \"10-K\",\n      \"anchor\": { \"kind\": \"spreadsheet_cell\", \"row\": 4, \"column\": \"B\", \"sheet_index\": 0, \"sheet_name\": \"Cover Page\", \"coordinate\": \"B4\" }\n    }\n  },\n  {\n    \"key\": \"periodEnd\",\n    \"label\": \"Period end date\",\n    \"value\": \"Jan. 28, 2024\",\n    \"source\": {\n      \"content\": \"Jan. 28,  2024\",\n      \"anchor\": { \"kind\": \"spreadsheet_cell\", \"row\": 6, \"column\": \"B\", \"sheet_index\": 0, \"sheet_name\": \"Cover Page\", \"coordinate\": \"B6\" }\n    }\n  },\n  {\n    \"key\": \"fiscalYearEnd\",\n    \"label\": \"Fiscal year end\",\n    \"value\": \"--01-28\",\n    \"source\": {\n      \"content\": \"--01-28\",\n      \"anchor\": { \"kind\": \"spreadsheet_cell\", \"row\": 7, \"column\": \"B\", \"sheet_index\": 0, \"sheet_name\": \"Cover Page\", \"coordinate\": \"B7\" }\n    }\n  },\n  {\n    \"key\": \"fileNumber\",\n    \"label\": \"Entity file number\",\n    \"value\": \"0-23985\",\n    \"source\": {\n      \"content\": \"0-23985\",\n      \"anchor\": { \"kind\": \"spreadsheet_cell\", \"row\": 9, \"column\": \"B\", \"sheet_index\": 0, \"sheet_name\": \"Cover Page\", \"coordinate\": \"B9\" }\n    }\n  },\n  {\n    \"key\": \"incorporationState\",\n    \"label\": \"Incorporation state\",\n    \"value\": \"DE\",\n    \"source\": {\n      \"content\": \"DE\",\n      \"anchor\": { \"kind\": \"spreadsheet_cell\", \"row\": 11, \"column\": \"B\", \"sheet_index\": 0, \"sheet_name\": \"Cover Page\", \"coordinate\": \"B11\" }\n    }\n  },\n  {\n    \"key\": \"taxId\",\n    \"label\": \"Tax ID\",\n    \"value\": \"94-3177549\",\n    \"source\": {\n      \"content\": \"94-3177549\",\n      \"anchor\": { \"kind\": \"spreadsheet_cell\", \"row\": 12, \"column\": \"B\", \"sheet_index\": 0, \"sheet_name\": \"Cover Page\", \"coordinate\": \"B12\" }\n    }\n  },\n  {\n    \"key\": \"address\",\n    \"label\": \"Address\",\n    \"value\": \"2788 San Tomas Expressway\",\n    \"source\": {\n      \"content\": \"2788 San Tomas Expressway\",\n      \"anchor\": { \"kind\": \"spreadsheet_cell\", \"row\": 13, \"column\": \"B\", \"sheet_index\": 0, \"sheet_name\": \"Cover Page\", \"coordinate\": \"B13\" }\n    }\n  },\n  {\n    \"key\": \"city\",\n    \"label\": \"City\",\n    \"value\": \"Santa Clara\",\n    \"source\": {\n      \"content\": \"Santa Clara\",\n      \"anchor\": { \"kind\": \"spreadsheet_cell\", \"row\": 14, \"column\": \"B\", \"sheet_index\": 0, \"sheet_name\": \"Cover Page\", \"coordinate\": \"B14\" }\n    }\n  },\n  {\n    \"key\": \"state\",\n    \"label\": \"State\",\n    \"value\": \"CA\",\n    \"source\": {\n      \"content\": \"CA\",\n      \"anchor\": { \"kind\": \"spreadsheet_cell\", \"row\": 15, \"column\": \"B\", \"sheet_index\": 0, \"sheet_name\": \"Cover Page\", \"coordinate\": \"B15\" }\n    }\n  },\n  {\n    \"key\": \"zip\",\n    \"label\": \"ZIP code\",\n    \"value\": \"95051\",\n    \"source\": {\n      \"content\": \"95051\",\n      \"anchor\": { \"kind\": \"spreadsheet_cell\", \"row\": 16, \"column\": \"B\", \"sheet_index\": 0, \"sheet_name\": \"Cover Page\", \"coordinate\": \"B16\" }\n    }\n  },\n  {\n    \"key\": \"phone\",\n    \"label\": \"Phone\",\n    \"value\": \"(408) 486-2000\",\n    \"source\": {\n      \"content\": \"486-2000\",\n      \"anchor\": { \"kind\": \"spreadsheet_cell\", \"row\": 18, \"column\": \"B\", \"sheet_index\": 0, \"sheet_name\": \"Cover Page\", \"coordinate\": \"B18\" }\n    }\n  },\n  {\n    \"key\": \"securityTitle\",\n    \"label\": \"Security title\",\n    \"value\": \"Common Stock, $0.001 par value\",\n    \"source\": {\n      \"content\": \"Common Stock, $0.001 par value per share\",\n      \"anchor\": { \"kind\": \"spreadsheet_cell\", \"row\": 19, \"column\": \"B\", \"sheet_index\": 0, \"sheet_name\": \"Cover Page\", \"coordinate\": \"B19\" }\n    }\n  },\n  {\n    \"key\": \"tradingSymbol\",\n    \"label\": \"Trading symbol\",\n    \"value\": \"NVDA\",\n    \"source\": {\n      \"content\": \"NVDA\",\n      \"anchor\": { \"kind\": \"spreadsheet_cell\", \"row\": 20, \"column\": \"B\", \"sheet_index\": 0, \"sheet_name\": \"Cover Page\", \"coordinate\": \"B20\" }\n    }\n  },\n  {\n    \"key\": \"auditorName\",\n    \"label\": \"Auditor\",\n    \"value\": \"PricewaterhouseCoopers LLP\",\n    \"source\": {\n      \"content\": \"PricewaterhouseCoopers LLP\",\n      \"anchor\": { \"kind\": \"spreadsheet_cell\", \"row\": 5, \"column\": \"B\", \"sheet_index\": 1, \"sheet_name\": \"Audit Information\", \"coordinate\": \"B5\" }\n    }\n  },\n  {\n    \"key\": \"auditorLocation\",\n    \"label\": \"Auditor location\",\n    \"value\": \"San Jose, California\",\n    \"source\": {\n      \"content\": \"San Jose, California\",\n      \"anchor\": { \"kind\": \"spreadsheet_cell\", \"row\": 6, \"column\": \"B\", \"sheet_index\": 1, \"sheet_name\": \"Audit Information\", \"coordinate\": \"B6\" }\n    }\n  },\n  {\n    \"key\": \"auditorFirmId\",\n    \"label\": \"Auditor firm ID\",\n    \"value\": \"238\",\n    \"source\": {\n      \"content\": \"238\",\n      \"anchor\": { \"kind\": \"spreadsheet_cell\", \"row\": 4, \"column\": \"B\", \"sheet_index\": 1, \"sheet_name\": \"Audit Information\", \"coordinate\": \"B4\" }\n    }\n  }\n]\n",
      "type": "registry:file",
      "target": "@components/viewers/sample-data/xlsx-sources.json"
    }
  ],
  "categories": [
    "primitives"
  ],
  "type": "registry:block"
}