@elabs-ai/components-viewer 4.0.0 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -7
- package/dist/{chunk-NMA57QZ7.js → chunk-XBOR2YXS.js} +2 -2
- package/dist/{chunk-NMA57QZ7.js.map → chunk-XBOR2YXS.js.map} +1 -1
- package/dist/{csv-adapter-6VU3FFVU.js → csv-adapter-7HOFZ5Z6.js} +2 -2
- package/dist/index.js +10 -7
- package/dist/index.js.map +1 -1
- package/dist/{pptx-adapter-6GEQLS2Z.js → pptx-adapter-BONWFHYT.js} +2 -2
- package/dist/pptx-adapter-BONWFHYT.js.map +1 -0
- package/dist/{xlsx-adapter-CM2Y6AKQ.js → xlsx-adapter-O3XIVLFC.js} +2 -2
- package/package.json +5 -5
- package/src/__contract__/file-viewer.contract.test.tsx +49 -0
- package/src/adapters/pptx/pptx-adapter.tsx +1 -1
- package/src/components/sheet-table.tsx +1 -1
- package/src/file-viewer/file-viewer.stories.tsx +14 -0
- package/src/file-viewer/file-viewer.test.tsx +35 -1
- package/src/file-viewer/file-viewer.tsx +17 -7
- package/dist/pptx-adapter-6GEQLS2Z.js.map +0 -1
- /package/dist/{csv-adapter-6VU3FFVU.js.map → csv-adapter-7HOFZ5Z6.js.map} +0 -0
- /package/dist/{xlsx-adapter-CM2Y6AKQ.js.map → xlsx-adapter-O3XIVLFC.js.map} +0 -0
package/README.md
CHANGED
|
@@ -6,15 +6,14 @@
|
|
|
6
6
|
> FileViewer — any file (image, text, JSON, CSV) via a pluggable adapter registry.
|
|
7
7
|
|
|
8
8
|
Part of **brand-ui**, a source-owned, token-driven React component system.
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
Published to the **public npm registry** under the `@elabs-ai` scope — it
|
|
10
|
+
installs like any other npm dependency, with no registry configuration and
|
|
11
|
+
no token required. See `docs/CONSUMING.md`.
|
|
11
12
|
|
|
12
13
|
## Install
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
```json
|
|
17
|
-
"@elabs-ai/components-viewer": "workspace:*"
|
|
15
|
+
```bash
|
|
16
|
+
pnpm add @elabs-ai/components-tokens @elabs-ai/components-viewer
|
|
18
17
|
```
|
|
19
18
|
|
|
20
19
|
## Set up styling (do not skip)
|
|
@@ -69,7 +68,7 @@ prompt for migrating an existing project: `docs/CONSUMING.md`.
|
|
|
69
68
|
|
|
70
69
|
## License
|
|
71
70
|
|
|
72
|
-
|
|
71
|
+
MIT
|
|
73
72
|
|
|
74
73
|
<!-- brand-ui:gen:readme:end -->
|
|
75
74
|
|
|
@@ -70,7 +70,7 @@ function SheetTable({
|
|
|
70
70
|
tabIndex: 0,
|
|
71
71
|
role: "group",
|
|
72
72
|
"aria-label": t("viewer.content"),
|
|
73
|
-
className: "focus-
|
|
73
|
+
className: "focus-ring min-h-0 flex-1 overflow-auto",
|
|
74
74
|
children: /* @__PURE__ */ jsxs(Table, { children: [
|
|
75
75
|
/* @__PURE__ */ jsx(TableCaption, { className: "sr-only", children: t("viewer.table.caption", {
|
|
76
76
|
rows: formatNumber(totalRows ?? rows.length),
|
|
@@ -114,4 +114,4 @@ export {
|
|
|
114
114
|
gridToText,
|
|
115
115
|
SheetTable
|
|
116
116
|
};
|
|
117
|
-
//# sourceMappingURL=chunk-
|
|
117
|
+
//# sourceMappingURL=chunk-XBOR2YXS.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/grid-text.ts","../src/components/sheet-table.tsx"],"sourcesContent":["/**\n * The one text projection every tabular format is addressed against.\n *\n * CSV and XLSX arrive through different parsers and render into the same\n * `SheetTable`; they should also be *addressable* the same way, or a citation\n * that resolves in a workbook would miss in the CSV export of the same data.\n * So the projection is written once here and both adapters call it.\n *\n * Shape — a sheet's name (when it has one), then its header row, then its body\n * rows; cells joined by a tab, rows by a newline, sheets by a blank line:\n *\n * ```\n * Q3\n * Region\\tRevenue\n * EMEA\\t4.2M\n *\n * Q4\n * …\n * ```\n *\n * **Rows, not cells, are the finest ref** — the same trade the Word adapter\n * makes. A cell-granular index would need a span per cell and a separator per\n * level; a row-granular one needs neither, because a cell's offset is the sum of\n * the cells before it ({@link chunkOffset}). The granularity of the REF is the\n * row; the granularity of the MARK is still the character.\n */\n\nimport { createTextIndexBuilder, type TextIndex } from \"../core/text-index\";\n\n/** Between two cells of the same row. */\nexport const GRID_CELL_SEPARATOR = \"\\t\";\n/** Between two rows of the same sheet. */\nexport const GRID_ROW_SEPARATOR = \"\\n\";\n/** Between two sheets of the same workbook. */\nexport const GRID_SHEET_SEPARATOR = \"\\n\\n\";\n\n/** The `row` of a sheet's own name line. */\nexport const GRID_NAME_ROW = -2;\n/** The `row` of a sheet's header row. */\nexport const GRID_HEAD_ROW = -1;\n\n/** Where a stretch of the projection came from in the grid. */\nexport interface GridRef {\n /** Index into the sheets. `0` for a single-sheet format like CSV. */\n sheet: number;\n /** Body row index, or {@link GRID_HEAD_ROW} / {@link GRID_NAME_ROW}. */\n row: number;\n}\n\n/** What {@link gridToText} needs from a sheet — the shape both adapters already hold. */\nexport interface GridSheetInput {\n /** The tab's name. Absent for a single-sheet format, which has no tab. */\n name?: string;\n columns: readonly string[];\n rows: readonly (readonly string[])[];\n}\n\n/** Project a workbook (or a one-sheet CSV) to text, with the map back to it. */\nexport function gridToText(sheets: readonly GridSheetInput[]): TextIndex<GridRef> {\n const builder = createTextIndexBuilder<GridRef>({ separator: GRID_ROW_SEPARATOR });\n sheets.forEach((sheet, index) => {\n // The blank line goes before whatever this sheet's FIRST line turns out to\n // be — its name, or its header when it has no name.\n let separator = index === 0 ? undefined : GRID_SHEET_SEPARATOR;\n const push = (chunk: string, row: number) => {\n builder.push(chunk, { sheet: index, row }, separator);\n if (chunk.length > 0) separator = undefined;\n };\n\n if (sheet.name) push(sheet.name, GRID_NAME_ROW);\n push(sheet.columns.join(GRID_CELL_SEPARATOR), GRID_HEAD_ROW);\n sheet.rows.forEach((row, rowIndex) => {\n push(row.join(GRID_CELL_SEPARATOR), rowIndex);\n });\n });\n return builder.build();\n}\n","\"use client\";\n\n/**\n * The one grid every tabular format renders into.\n *\n * CSV and XLSX arrive through completely different parsers and end up wanting\n * exactly the same thing: a header row, body rows, a truncation notice and an\n * `sr-only` caption. That is a PATTERN, not a coincidence, so it is named once\n * here rather than copied a second time (`.claude/rules/design-first.md` —\n * patterns over instances).\n *\n * It stays deliberately dumb: no sorting, no filtering, no virtualization. A\n * preview pane is for looking; past a few thousand rows the right component is\n * `DataTable` in `@elabs-ai/components-data`, which virtualizes.\n */\n\nimport {\n cn,\n Table,\n TableBody,\n TableCaption,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n useLocale,\n} from \"@elabs-ai/components-ui\";\nimport { useRef } from \"react\";\n\nimport { type MarkRanges } from \"../core/highlight-marks\";\nimport { chunkOffset } from \"../core/text-index\";\nimport { useScrollActiveHighlightIntoView } from \"../core/use-highlight-scroll\";\nimport { GRID_CELL_SEPARATOR, GRID_HEAD_ROW } from \"./grid-text\";\nimport { MarkedText } from \"./marked-text\";\n\nexport interface SheetTableProps {\n /** Header cells. May be empty — the grid still renders its body. */\n columns: string[];\n /** Body rows, already capped by the caller. */\n rows: string[][];\n /** Total body rows in the file, when more exist than `rows` holds. */\n totalRows?: number;\n className?: string;\n /** Marks to paint, in projection offsets. */\n marks?: MarkRanges;\n /**\n * Where a row's first cell begins in the projection — {@link GRID_HEAD_ROW}\n * for the header. A function rather than an array so a workbook can answer\n * for the sheet being drawn without slicing an index per tab.\n */\n rowStart?: (row: number) => number | undefined;\n /** Scrolls the current mark into this grid's own viewport when it changes. */\n activeHighlightId?: string | null;\n}\n\nexport function SheetTable({\n columns,\n rows,\n totalRows,\n className,\n marks,\n rowStart,\n activeHighlightId,\n}: SheetTableProps) {\n const { t, formatNumber } = useLocale();\n const viewport = useRef<HTMLDivElement>(null);\n\n useScrollActiveHighlightIntoView(viewport, activeHighlightId);\n\n return (\n <div className={cn(\"flex h-full min-h-0 flex-col gap-2\", className)}>\n {totalRows !== undefined && (\n // A status, not an error: the file is fine, we are simply showing part\n // of it (loading-states.md — a capability bound is news, not an alarm).\n <p role=\"status\" className=\"text-meta text-muted-foreground shrink-0\">\n {t(\"viewer.table.truncated\", { count: formatNumber(rows.length) })}\n </p>\n )}\n {/* The grid keeps its OWN viewport, unlike the flowing formats: a workbook\n puts a sheet-tab bar above it that must not scroll away with the rows.\n A table cell is not focusable, so a scrollable region wrapping one is\n unreachable from a keyboard (WCAG 2.1.1) — `tabIndex={0}` makes it a\n real stop that arrow keys and Page Up/Down drive. `group`, not\n `region`, so a sheet does not mint a second landmark inside the\n viewer's content region. */}\n <div\n ref={viewport}\n tabIndex={0}\n role=\"group\"\n aria-label={t(\"viewer.content\")}\n className=\"focus-visible:ring-ring min-h-0 flex-1 overflow-auto focus-visible:outline-none focus-visible:ring-2\"\n >\n <Table>\n <TableCaption className=\"sr-only\">\n {t(\"viewer.table.caption\", {\n rows: formatNumber(totalRows ?? rows.length),\n columns: formatNumber(columns.length),\n })}\n </TableCaption>\n <TableHeader>\n <TableRow>\n {columns.map((column, index) => (\n // The file's own header text is the only identity a column has;\n // an empty one still needs a cell so the grid stays aligned.\n <TableHead key={`${column}-${String(index)}`} scope=\"col\">\n <MarkedText\n text={column}\n marks={marks}\n start={chunkOffset(\n columns,\n index,\n rowStart?.(GRID_HEAD_ROW),\n GRID_CELL_SEPARATOR,\n )}\n />\n </TableHead>\n ))}\n </TableRow>\n </TableHeader>\n <TableBody>\n {rows.map((row, rowIndex) => {\n const start = rowStart?.(rowIndex);\n return (\n <TableRow key={rowIndex}>\n {columns.map((_, columnIndex) => (\n <TableCell key={columnIndex} className=\"whitespace-pre-wrap\">\n <MarkedText\n text={row[columnIndex] ?? \"\"}\n marks={marks}\n start={chunkOffset(row, columnIndex, start, GRID_CELL_SEPARATOR)}\n />\n </TableCell>\n ))}\n </TableRow>\n );\n })}\n </TableBody>\n </Table>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;AA8BO,IAAM,sBAAsB;AAE5B,IAAM,qBAAqB;AAE3B,IAAM,uBAAuB;AAG7B,IAAM,gBAAgB;AAEtB,IAAM,gBAAgB;AAmBtB,SAAS,WAAW,QAAuD;AAChF,QAAM,UAAU,uBAAgC,EAAE,WAAW,mBAAmB,CAAC;AACjF,SAAO,QAAQ,CAAC,OAAO,UAAU;AAG/B,QAAI,YAAY,UAAU,IAAI,SAAY;AAC1C,UAAM,OAAO,CAAC,OAAe,QAAgB;AAC3C,cAAQ,KAAK,OAAO,EAAE,OAAO,OAAO,IAAI,GAAG,SAAS;AACpD,UAAI,MAAM,SAAS,EAAG,aAAY;AAAA,IACpC;AAEA,QAAI,MAAM,KAAM,MAAK,MAAM,MAAM,aAAa;AAC9C,SAAK,MAAM,QAAQ,KAAK,mBAAmB,GAAG,aAAa;AAC3D,UAAM,KAAK,QAAQ,CAAC,KAAK,aAAa;AACpC,WAAK,IAAI,KAAK,mBAAmB,GAAG,QAAQ;AAAA,IAC9C,CAAC;AAAA,EACH,CAAC;AACD,SAAO,QAAQ,MAAM;AACvB;;;AC5DA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,cAAc;AA+Cf,cAkBA,YAlBA;AAnBD,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAoB;AAClB,QAAM,EAAE,GAAG,aAAa,IAAI,UAAU;AACtC,QAAM,WAAW,OAAuB,IAAI;AAE5C,mCAAiC,UAAU,iBAAiB;AAE5D,SACE,qBAAC,SAAI,WAAW,GAAG,sCAAsC,SAAS,GAC/D;AAAA,kBAAc;AAAA;AAAA,IAGb,oBAAC,OAAE,MAAK,UAAS,WAAU,4CACxB,YAAE,0BAA0B,EAAE,OAAO,aAAa,KAAK,MAAM,EAAE,CAAC,GACnE;AAAA,IASF;AAAA,MAAC;AAAA;AAAA,QACC,KAAK;AAAA,QACL,UAAU;AAAA,QACV,MAAK;AAAA,QACL,cAAY,EAAE,gBAAgB;AAAA,QAC9B,WAAU;AAAA,QAEV,+BAAC,SACC;AAAA,8BAAC,gBAAa,WAAU,WACrB,YAAE,wBAAwB;AAAA,YACzB,MAAM,aAAa,aAAa,KAAK,MAAM;AAAA,YAC3C,SAAS,aAAa,QAAQ,MAAM;AAAA,UACtC,CAAC,GACH;AAAA,UACA,oBAAC,eACC,8BAAC,YACE,kBAAQ,IAAI,CAAC,QAAQ;AAAA;AAAA;AAAA,YAGpB,oBAAC,aAA6C,OAAM,OAClD;AAAA,cAAC;AAAA;AAAA,gBACC,MAAM;AAAA,gBACN;AAAA,gBACA,OAAO;AAAA,kBACL;AAAA,kBACA;AAAA,kBACA,WAAW,aAAa;AAAA,kBACxB;AAAA,gBACF;AAAA;AAAA,YACF,KAVc,GAAG,MAAM,IAAI,OAAO,KAAK,CAAC,EAW1C;AAAA,WACD,GACH,GACF;AAAA,UACA,oBAAC,aACE,eAAK,IAAI,CAAC,KAAK,aAAa;AAC3B,kBAAM,QAAQ,WAAW,QAAQ;AACjC,mBACE,oBAAC,YACE,kBAAQ,IAAI,CAAC,GAAG,gBACf,oBAAC,aAA4B,WAAU,uBACrC;AAAA,cAAC;AAAA;AAAA,gBACC,MAAM,IAAI,WAAW,KAAK;AAAA,gBAC1B;AAAA,gBACA,OAAO,YAAY,KAAK,aAAa,OAAO,mBAAmB;AAAA;AAAA,YACjE,KALc,WAMhB,CACD,KATY,QAUf;AAAA,UAEJ,CAAC,GACH;AAAA,WACF;AAAA;AAAA,IACF;AAAA,KACF;AAEJ;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/components/grid-text.ts","../src/components/sheet-table.tsx"],"sourcesContent":["/**\n * The one text projection every tabular format is addressed against.\n *\n * CSV and XLSX arrive through different parsers and render into the same\n * `SheetTable`; they should also be *addressable* the same way, or a citation\n * that resolves in a workbook would miss in the CSV export of the same data.\n * So the projection is written once here and both adapters call it.\n *\n * Shape — a sheet's name (when it has one), then its header row, then its body\n * rows; cells joined by a tab, rows by a newline, sheets by a blank line:\n *\n * ```\n * Q3\n * Region\\tRevenue\n * EMEA\\t4.2M\n *\n * Q4\n * …\n * ```\n *\n * **Rows, not cells, are the finest ref** — the same trade the Word adapter\n * makes. A cell-granular index would need a span per cell and a separator per\n * level; a row-granular one needs neither, because a cell's offset is the sum of\n * the cells before it ({@link chunkOffset}). The granularity of the REF is the\n * row; the granularity of the MARK is still the character.\n */\n\nimport { createTextIndexBuilder, type TextIndex } from \"../core/text-index\";\n\n/** Between two cells of the same row. */\nexport const GRID_CELL_SEPARATOR = \"\\t\";\n/** Between two rows of the same sheet. */\nexport const GRID_ROW_SEPARATOR = \"\\n\";\n/** Between two sheets of the same workbook. */\nexport const GRID_SHEET_SEPARATOR = \"\\n\\n\";\n\n/** The `row` of a sheet's own name line. */\nexport const GRID_NAME_ROW = -2;\n/** The `row` of a sheet's header row. */\nexport const GRID_HEAD_ROW = -1;\n\n/** Where a stretch of the projection came from in the grid. */\nexport interface GridRef {\n /** Index into the sheets. `0` for a single-sheet format like CSV. */\n sheet: number;\n /** Body row index, or {@link GRID_HEAD_ROW} / {@link GRID_NAME_ROW}. */\n row: number;\n}\n\n/** What {@link gridToText} needs from a sheet — the shape both adapters already hold. */\nexport interface GridSheetInput {\n /** The tab's name. Absent for a single-sheet format, which has no tab. */\n name?: string;\n columns: readonly string[];\n rows: readonly (readonly string[])[];\n}\n\n/** Project a workbook (or a one-sheet CSV) to text, with the map back to it. */\nexport function gridToText(sheets: readonly GridSheetInput[]): TextIndex<GridRef> {\n const builder = createTextIndexBuilder<GridRef>({ separator: GRID_ROW_SEPARATOR });\n sheets.forEach((sheet, index) => {\n // The blank line goes before whatever this sheet's FIRST line turns out to\n // be — its name, or its header when it has no name.\n let separator = index === 0 ? undefined : GRID_SHEET_SEPARATOR;\n const push = (chunk: string, row: number) => {\n builder.push(chunk, { sheet: index, row }, separator);\n if (chunk.length > 0) separator = undefined;\n };\n\n if (sheet.name) push(sheet.name, GRID_NAME_ROW);\n push(sheet.columns.join(GRID_CELL_SEPARATOR), GRID_HEAD_ROW);\n sheet.rows.forEach((row, rowIndex) => {\n push(row.join(GRID_CELL_SEPARATOR), rowIndex);\n });\n });\n return builder.build();\n}\n","\"use client\";\n\n/**\n * The one grid every tabular format renders into.\n *\n * CSV and XLSX arrive through completely different parsers and end up wanting\n * exactly the same thing: a header row, body rows, a truncation notice and an\n * `sr-only` caption. That is a PATTERN, not a coincidence, so it is named once\n * here rather than copied a second time (`.claude/rules/design-first.md` —\n * patterns over instances).\n *\n * It stays deliberately dumb: no sorting, no filtering, no virtualization. A\n * preview pane is for looking; past a few thousand rows the right component is\n * `DataTable` in `@elabs-ai/components-data`, which virtualizes.\n */\n\nimport {\n cn,\n Table,\n TableBody,\n TableCaption,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n useLocale,\n} from \"@elabs-ai/components-ui\";\nimport { useRef } from \"react\";\n\nimport { type MarkRanges } from \"../core/highlight-marks\";\nimport { chunkOffset } from \"../core/text-index\";\nimport { useScrollActiveHighlightIntoView } from \"../core/use-highlight-scroll\";\nimport { GRID_CELL_SEPARATOR, GRID_HEAD_ROW } from \"./grid-text\";\nimport { MarkedText } from \"./marked-text\";\n\nexport interface SheetTableProps {\n /** Header cells. May be empty — the grid still renders its body. */\n columns: string[];\n /** Body rows, already capped by the caller. */\n rows: string[][];\n /** Total body rows in the file, when more exist than `rows` holds. */\n totalRows?: number;\n className?: string;\n /** Marks to paint, in projection offsets. */\n marks?: MarkRanges;\n /**\n * Where a row's first cell begins in the projection — {@link GRID_HEAD_ROW}\n * for the header. A function rather than an array so a workbook can answer\n * for the sheet being drawn without slicing an index per tab.\n */\n rowStart?: (row: number) => number | undefined;\n /** Scrolls the current mark into this grid's own viewport when it changes. */\n activeHighlightId?: string | null;\n}\n\nexport function SheetTable({\n columns,\n rows,\n totalRows,\n className,\n marks,\n rowStart,\n activeHighlightId,\n}: SheetTableProps) {\n const { t, formatNumber } = useLocale();\n const viewport = useRef<HTMLDivElement>(null);\n\n useScrollActiveHighlightIntoView(viewport, activeHighlightId);\n\n return (\n <div className={cn(\"flex h-full min-h-0 flex-col gap-2\", className)}>\n {totalRows !== undefined && (\n // A status, not an error: the file is fine, we are simply showing part\n // of it (loading-states.md — a capability bound is news, not an alarm).\n <p role=\"status\" className=\"text-meta text-muted-foreground shrink-0\">\n {t(\"viewer.table.truncated\", { count: formatNumber(rows.length) })}\n </p>\n )}\n {/* The grid keeps its OWN viewport, unlike the flowing formats: a workbook\n puts a sheet-tab bar above it that must not scroll away with the rows.\n A table cell is not focusable, so a scrollable region wrapping one is\n unreachable from a keyboard (WCAG 2.1.1) — `tabIndex={0}` makes it a\n real stop that arrow keys and Page Up/Down drive. `group`, not\n `region`, so a sheet does not mint a second landmark inside the\n viewer's content region. */}\n <div\n ref={viewport}\n tabIndex={0}\n role=\"group\"\n aria-label={t(\"viewer.content\")}\n className=\"focus-ring min-h-0 flex-1 overflow-auto\"\n >\n <Table>\n <TableCaption className=\"sr-only\">\n {t(\"viewer.table.caption\", {\n rows: formatNumber(totalRows ?? rows.length),\n columns: formatNumber(columns.length),\n })}\n </TableCaption>\n <TableHeader>\n <TableRow>\n {columns.map((column, index) => (\n // The file's own header text is the only identity a column has;\n // an empty one still needs a cell so the grid stays aligned.\n <TableHead key={`${column}-${String(index)}`} scope=\"col\">\n <MarkedText\n text={column}\n marks={marks}\n start={chunkOffset(\n columns,\n index,\n rowStart?.(GRID_HEAD_ROW),\n GRID_CELL_SEPARATOR,\n )}\n />\n </TableHead>\n ))}\n </TableRow>\n </TableHeader>\n <TableBody>\n {rows.map((row, rowIndex) => {\n const start = rowStart?.(rowIndex);\n return (\n <TableRow key={rowIndex}>\n {columns.map((_, columnIndex) => (\n <TableCell key={columnIndex} className=\"whitespace-pre-wrap\">\n <MarkedText\n text={row[columnIndex] ?? \"\"}\n marks={marks}\n start={chunkOffset(row, columnIndex, start, GRID_CELL_SEPARATOR)}\n />\n </TableCell>\n ))}\n </TableRow>\n );\n })}\n </TableBody>\n </Table>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;AA8BO,IAAM,sBAAsB;AAE5B,IAAM,qBAAqB;AAE3B,IAAM,uBAAuB;AAG7B,IAAM,gBAAgB;AAEtB,IAAM,gBAAgB;AAmBtB,SAAS,WAAW,QAAuD;AAChF,QAAM,UAAU,uBAAgC,EAAE,WAAW,mBAAmB,CAAC;AACjF,SAAO,QAAQ,CAAC,OAAO,UAAU;AAG/B,QAAI,YAAY,UAAU,IAAI,SAAY;AAC1C,UAAM,OAAO,CAAC,OAAe,QAAgB;AAC3C,cAAQ,KAAK,OAAO,EAAE,OAAO,OAAO,IAAI,GAAG,SAAS;AACpD,UAAI,MAAM,SAAS,EAAG,aAAY;AAAA,IACpC;AAEA,QAAI,MAAM,KAAM,MAAK,MAAM,MAAM,aAAa;AAC9C,SAAK,MAAM,QAAQ,KAAK,mBAAmB,GAAG,aAAa;AAC3D,UAAM,KAAK,QAAQ,CAAC,KAAK,aAAa;AACpC,WAAK,IAAI,KAAK,mBAAmB,GAAG,QAAQ;AAAA,IAC9C,CAAC;AAAA,EACH,CAAC;AACD,SAAO,QAAQ,MAAM;AACvB;;;AC5DA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,cAAc;AA+Cf,cAkBA,YAlBA;AAnBD,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAoB;AAClB,QAAM,EAAE,GAAG,aAAa,IAAI,UAAU;AACtC,QAAM,WAAW,OAAuB,IAAI;AAE5C,mCAAiC,UAAU,iBAAiB;AAE5D,SACE,qBAAC,SAAI,WAAW,GAAG,sCAAsC,SAAS,GAC/D;AAAA,kBAAc;AAAA;AAAA,IAGb,oBAAC,OAAE,MAAK,UAAS,WAAU,4CACxB,YAAE,0BAA0B,EAAE,OAAO,aAAa,KAAK,MAAM,EAAE,CAAC,GACnE;AAAA,IASF;AAAA,MAAC;AAAA;AAAA,QACC,KAAK;AAAA,QACL,UAAU;AAAA,QACV,MAAK;AAAA,QACL,cAAY,EAAE,gBAAgB;AAAA,QAC9B,WAAU;AAAA,QAEV,+BAAC,SACC;AAAA,8BAAC,gBAAa,WAAU,WACrB,YAAE,wBAAwB;AAAA,YACzB,MAAM,aAAa,aAAa,KAAK,MAAM;AAAA,YAC3C,SAAS,aAAa,QAAQ,MAAM;AAAA,UACtC,CAAC,GACH;AAAA,UACA,oBAAC,eACC,8BAAC,YACE,kBAAQ,IAAI,CAAC,QAAQ;AAAA;AAAA;AAAA,YAGpB,oBAAC,aAA6C,OAAM,OAClD;AAAA,cAAC;AAAA;AAAA,gBACC,MAAM;AAAA,gBACN;AAAA,gBACA,OAAO;AAAA,kBACL;AAAA,kBACA;AAAA,kBACA,WAAW,aAAa;AAAA,kBACxB;AAAA,gBACF;AAAA;AAAA,YACF,KAVc,GAAG,MAAM,IAAI,OAAO,KAAK,CAAC,EAW1C;AAAA,WACD,GACH,GACF;AAAA,UACA,oBAAC,aACE,eAAK,IAAI,CAAC,KAAK,aAAa;AAC3B,kBAAM,QAAQ,WAAW,QAAQ;AACjC,mBACE,oBAAC,YACE,kBAAQ,IAAI,CAAC,GAAG,gBACf,oBAAC,aAA4B,WAAU,uBACrC;AAAA,cAAC;AAAA;AAAA,gBACC,MAAM,IAAI,WAAW,KAAK;AAAA,gBAC1B;AAAA,gBACA,OAAO,YAAY,KAAK,aAAa,OAAO,mBAAmB;AAAA;AAAA,YACjE,KALc,WAMhB,CACD,KATY,QAUf;AAAA,UAEJ,CAAC,GACH;AAAA,WACF;AAAA;AAAA,IACF;AAAA,KACF;AAEJ;","names":[]}
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
import {
|
|
7
7
|
SheetTable,
|
|
8
8
|
gridToText
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-XBOR2YXS.js";
|
|
10
10
|
import "./chunk-2NQ4RSJ3.js";
|
|
11
11
|
import "./chunk-UL43NGUG.js";
|
|
12
12
|
import {
|
|
@@ -97,4 +97,4 @@ export {
|
|
|
97
97
|
CSV_ROW_LIMIT,
|
|
98
98
|
csv_adapter_default as default
|
|
99
99
|
};
|
|
100
|
-
//# sourceMappingURL=csv-adapter-
|
|
100
|
+
//# sourceMappingURL=csv-adapter-7HOFZ5Z6.js.map
|
package/dist/index.js
CHANGED
|
@@ -185,12 +185,12 @@ function createDefaultRegistry() {
|
|
|
185
185
|
const registry = createRegistry();
|
|
186
186
|
registry.register(imageManifest, () => import("./image-adapter-WOHZR24J.js"));
|
|
187
187
|
registry.register(jsonManifest, () => import("./json-adapter-ZUW5GQHE.js"));
|
|
188
|
-
registry.register(csvManifest, () => import("./csv-adapter-
|
|
188
|
+
registry.register(csvManifest, () => import("./csv-adapter-7HOFZ5Z6.js"));
|
|
189
189
|
registry.register(pdfManifest, () => import("./pdf-adapter-5PMKEXUD.js"));
|
|
190
190
|
registry.register(mediaManifest, () => import("./media-adapter-MCTB4GBH.js"));
|
|
191
191
|
registry.register(docxManifest, () => import("./docx-adapter-5CQDHWTD.js"));
|
|
192
|
-
registry.register(xlsxManifest, () => import("./xlsx-adapter-
|
|
193
|
-
registry.register(pptxManifest, () => import("./pptx-adapter-
|
|
192
|
+
registry.register(xlsxManifest, () => import("./xlsx-adapter-O3XIVLFC.js"));
|
|
193
|
+
registry.register(pptxManifest, () => import("./pptx-adapter-BONWFHYT.js"));
|
|
194
194
|
registry.register(markdownManifest, () => import("./markdown-adapter-YC6WTBS4.js"));
|
|
195
195
|
registry.register(codeManifest, () => import("./code-adapter-ADZ4UOGN.js"));
|
|
196
196
|
registry.register(textManifest, () => import("./text-adapter-NFNWB5W3.js"));
|
|
@@ -1028,10 +1028,15 @@ var FileViewerToolbar = forwardRef4(
|
|
|
1028
1028
|
const { t } = useLocale4();
|
|
1029
1029
|
const source = state.source;
|
|
1030
1030
|
const Glyph = fileIconFor(source?.name ?? "", source?.mediaType);
|
|
1031
|
+
const [downloadFailed, setDownloadFailed] = useState2(false);
|
|
1031
1032
|
if (!source) return null;
|
|
1032
1033
|
const download = () => {
|
|
1034
|
+
setDownloadFailed(false);
|
|
1033
1035
|
void source.bytes().then((bytes) => {
|
|
1034
1036
|
downloadBlob(new Blob([bytes], { type: source.mediaType }), source.name);
|
|
1037
|
+
}).catch((error) => {
|
|
1038
|
+
console.error("FileViewer: download failed", error);
|
|
1039
|
+
setDownloadFailed(true);
|
|
1035
1040
|
});
|
|
1036
1041
|
};
|
|
1037
1042
|
return /* @__PURE__ */ jsxs4(
|
|
@@ -1051,6 +1056,7 @@ var FileViewerToolbar = forwardRef4(
|
|
|
1051
1056
|
/* @__PURE__ */ jsx4(Text, { className: "min-w-0 flex-1 truncate", title: source.name, children: source.name }),
|
|
1052
1057
|
children,
|
|
1053
1058
|
actions,
|
|
1059
|
+
downloadFailed ? /* @__PURE__ */ jsx4(Text, { role: "alert", className: "text-destructive-text shrink-0 truncate", children: t("viewer.error.readFailedBody", { name: source.name, format: source.mediaType }) }) : null,
|
|
1054
1060
|
/* @__PURE__ */ jsx4(Separator2, { orientation: "vertical", className: "h-4" }),
|
|
1055
1061
|
/* @__PURE__ */ jsx4(
|
|
1056
1062
|
IconButton4,
|
|
@@ -1211,10 +1217,7 @@ var FileViewerContent = forwardRef4(
|
|
|
1211
1217
|
role: "region",
|
|
1212
1218
|
"aria-label": t("viewer.content"),
|
|
1213
1219
|
tabIndex: 0,
|
|
1214
|
-
className: cn4(
|
|
1215
|
-
"focus-visible:ring-ring min-h-0 flex-1 overflow-auto p-4 focus-visible:outline-none focus-visible:ring-2",
|
|
1216
|
-
className
|
|
1217
|
-
),
|
|
1220
|
+
className: cn4("focus-ring min-h-0 flex-1 overflow-auto p-4", className),
|
|
1218
1221
|
...props,
|
|
1219
1222
|
children: [
|
|
1220
1223
|
state.status === "empty" && /* @__PURE__ */ jsx4(FileViewerEmpty, {}),
|