@llamaindex/ui
Version:
A comprehensive UI component library built with React, TypeScript, and Tailwind CSS for LlamaIndex applications
1,387 lines (1,378 loc) • 65.3 kB
JavaScript
import { Popover, PopoverTrigger, PopoverContent } from './chunk-AT2HHFS3.mjs';
import { Label } from './chunk-HTDT6UBX.mjs';
import { Slider } from './chunk-IPGFBZIN.mjs';
import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from './chunk-WVWSZ6KQ.mjs';
import { Tooltip, TooltipTrigger, TooltipContent } from './chunk-FSJOM7AM.mjs';
import { Textarea } from './chunk-KDZ6LO7J.mjs';
import { isNullable } from './chunk-YHVLD5CA.mjs';
import { useUIConfigStore } from './chunk-QQG6BRXU.mjs';
import { Table, TableHeader, TableBody, TableRow, TableCell, TableHead } from './chunk-Y27WI3E4.mjs';
import { Input } from './chunk-EWMUBFVD.mjs';
import { Button } from './chunk-NLLOGSY3.mjs';
import { cn } from './chunk-MG2ARK3A.mjs';
import { __spreadProps, __spreadValues } from './chunk-FWCSY2DS.mjs';
import React2, { useState, useRef, useLayoutEffect, useMemo, useEffect, useCallback } from 'react';
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
import { Trash2, Plus } from 'lucide-react';
import { toast } from 'sonner';
// src/extracted-data/confidence-utils.ts
function getConfidenceBackgroundClass(threshold, confidence) {
if (!confidence || confidence === 0) return "";
return confidence < threshold ? "bg-orange-50" : "";
}
function getConfidenceBorderClass(threshold, confidence) {
if (!confidence || confidence === 0) return "";
return confidence < threshold ? "border-b-2 border-orange-300" : "border-b border-gray-200";
}
// src/extracted-data/primitive-validation.ts
function toPrimitiveType(schemaType) {
switch (schemaType) {
case "number":
return "number" /* NUMBER */;
case "boolean":
return "boolean" /* BOOLEAN */;
case "string":
default:
return "string" /* STRING */;
}
}
function convertPrimitiveValue(inputValue, expectedType, required = false) {
switch (expectedType) {
case "string" /* STRING */:
return inputValue;
case "number" /* NUMBER */:
if (inputValue === "") {
return required ? "" : null;
}
return Number(inputValue);
case "boolean" /* BOOLEAN */:
return inputValue === "true";
default:
return inputValue;
}
}
function EditableField({
value,
onSave,
isChanged,
showBorder = true,
expectedType = "string" /* STRING */,
required = false,
className,
metadata,
onClick,
editable = true
}) {
var _a;
const confidenceThreshold = useUIConfigStore(
(state) => state.confidenceThreshold
);
const [isOpen, setIsOpen] = useState(false);
const [editValue, setEditValue] = useState(
value === null || value === void 0 ? "" : String(value)
);
const [localConfidence, setLocalConfidence] = useState(
(_a = metadata == null ? void 0 : metadata.confidence) != null ? _a : 1
);
const containerRef = useRef(null);
useLayoutEffect(() => {
if (containerRef.current) {
const parent = containerRef.current.parentElement;
if (parent) {
const contentHeight = parent.clientHeight;
containerRef.current.style.height = `${contentHeight}px`;
}
}
}, [value]);
const handleSave = () => {
if (required && expectedType === "number" /* NUMBER */ && editValue.trim() === "") {
return;
}
const convertedValue = convertPrimitiveValue(
editValue,
expectedType,
required
);
onSave(convertedValue);
setLocalConfidence(1);
setIsOpen(false);
};
const handleCancel = () => {
setEditValue(value === null || value === void 0 ? "" : String(value));
setIsOpen(false);
};
const handleOpenChange = (open) => {
setIsOpen(open);
if (open) {
setEditValue(value === null || value === void 0 ? "" : String(value));
}
};
const handleKeyDown = (e) => {
if (e.key === "Enter" && !e.shiftKey && !e.ctrlKey && !e.metaKey) {
e.preventDefault();
handleSave();
}
if (e.key === "Escape") {
handleCancel();
}
};
const handleInputChange = (e) => {
setEditValue(e.target.value);
};
const handleTextareaChange = (e) => {
setEditValue(e.target.value);
};
const handleSelectChange = (value2) => {
setEditValue(value2);
};
const currentConfidence = localConfidence != null ? localConfidence : metadata == null ? void 0 : metadata.confidence;
const displayValue = value === null || value === void 0 || value === "" ? "" : String(value);
const backgroundClass = isChanged ? "bg-green-50" : getConfidenceBackgroundClass(confidenceThreshold, currentConfidence);
const hoverClass = backgroundClass.includes("bg-orange-50") ? "hover:bg-orange-100" : backgroundClass.includes("bg-green-50") ? "hover:bg-green-100" : "hover:bg-gray-100";
const defaultBorderClass = showBorder ? getConfidenceBorderClass(confidenceThreshold, currentConfidence) : "";
const paddingClass = "p-2";
const renderEditInput = () => {
switch (expectedType) {
case "boolean" /* BOOLEAN */:
return /* @__PURE__ */ jsxs(Select, { onValueChange: handleSelectChange, value: editValue, children: [
/* @__PURE__ */ jsx(SelectTrigger, { className: "w-full", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Select a value" }) }),
/* @__PURE__ */ jsxs(SelectContent, { children: [
/* @__PURE__ */ jsx(SelectItem, { value: "true", children: "true" }),
/* @__PURE__ */ jsx(SelectItem, { value: "false", children: "false" })
] })
] });
case "string" /* STRING */:
return /* @__PURE__ */ jsx(
Textarea,
{
value: editValue,
onChange: handleTextareaChange,
onKeyDown: handleKeyDown,
placeholder: "Enter value",
className: "w-full min-h-[100px] resize-none",
autoFocus: true
}
);
case "number" /* NUMBER */:
return /* @__PURE__ */ jsx(
Input,
{
type: "number",
value: editValue,
onChange: handleInputChange,
onKeyDown: handleKeyDown,
placeholder: "Enter a number",
className: "w-full",
autoFocus: true,
required
}
);
default:
return /* @__PURE__ */ jsx(
Input,
{
value: editValue,
onChange: handleInputChange,
onKeyDown: handleKeyDown,
placeholder: "Enter value",
className: "w-full",
autoFocus: true
}
);
}
};
if (!editable) {
return /* @__PURE__ */ jsxs(Tooltip, { children: [
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
"div",
{
ref: containerRef,
onClick: () => onClick == null ? void 0 : onClick({ value, metadata }),
className: `cursor-pointer ${showBorder ? "min-h-8" : "w-full"} flex items-center ${defaultBorderClass} ${paddingClass} ${backgroundClass} ${hoverClass} ${className}`,
"data-testid": "editable-field-trigger",
children: /* @__PURE__ */ jsx("span", { className: "text-sm accent-foreground truncate leading-tight block w-full", children: displayValue })
}
) }),
/* @__PURE__ */ jsx(TooltipContent, { children: /* @__PURE__ */ jsx("p", { children: displayValue }) })
] });
}
return /* @__PURE__ */ jsxs(Popover, { open: isOpen, onOpenChange: handleOpenChange, children: [
/* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
"div",
{
ref: containerRef,
onClick: () => onClick == null ? void 0 : onClick({ value, metadata }),
className: `cursor-pointer ${showBorder ? "min-h-8" : "w-full"} flex items-center ${defaultBorderClass} ${paddingClass} ${backgroundClass} ${hoverClass} ${className}`,
"data-testid": "editable-field-trigger",
children: /* @__PURE__ */ jsx("span", { className: "text-sm accent-foreground truncate leading-tight block w-full", children: displayValue })
}
) }),
/* @__PURE__ */ jsx(PopoverContent, { className: "w-80", align: "start", children: /* @__PURE__ */ jsxs("div", { className: "space-y-3", "data-testid": "editable-field-popover", children: [
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsx("div", { className: "text-sm font-medium text-gray-700", children: "Edit Value" }) }),
renderEditInput(),
/* @__PURE__ */ jsxs("div", { className: "flex justify-end space-x-2", children: [
/* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", onClick: handleCancel, children: "Cancel" }),
/* @__PURE__ */ jsx(Button, { size: "sm", onClick: handleSave, children: "Save" })
] })
] }) })
] });
}
// src/extracted-data/schema-metadata-lookup.ts
function normalizeMetadataPath(pathString) {
return pathString.replace(/\.\d+(?=\.|$)/g, ".*");
}
function lookupFieldSchemaMetadata(keyPath, fieldSchemaMetadata) {
const pathString = keyPath.join(".");
let metadata = fieldSchemaMetadata[pathString];
if (metadata) {
return metadata;
}
const normalizedPath = normalizeMetadataPath(pathString);
metadata = fieldSchemaMetadata[normalizedPath];
if (metadata) {
return metadata;
}
if (!pathString.includes(".") || !pathString.match(/\.\d+\./)) {
const segments = keyPath;
if (segments.length > 1) {
for (let i = 1; i < segments.length; i++) {
const wildcardPath = [
...segments.slice(0, i),
"*",
...segments.slice(i)
].join(".");
metadata = fieldSchemaMetadata[wildcardPath];
if (metadata) {
return metadata;
}
}
}
}
return metadata;
}
function getDefaultValueForType(schemaType) {
const PrimitiveType2 = {
STRING: "string",
NUMBER: "number",
BOOLEAN: "boolean"
};
switch (schemaType) {
case PrimitiveType2.STRING:
return "";
case PrimitiveType2.NUMBER:
return 0;
case PrimitiveType2.BOOLEAN:
return false;
default:
return "";
}
}
// src/extracted-data/table-renderer/table-renderer-utils.ts
var formatFieldName = (key) => {
return key.replace(/_/g, " ").replace(/([a-z])([A-Z])/g, "$1 $2").replace(/\b\w/g, (l) => l.toUpperCase()).trim();
};
function isTableCellChanged(changedPaths, keyPath, rowIndex, columnKey) {
if (!changedPaths) return false;
const relativeCellPath = `${rowIndex}.${columnKey}`;
const absoluteCellPath = [...keyPath, String(rowIndex), columnKey].join(".");
return changedPaths.has(relativeCellPath) || changedPaths.has(absoluteCellPath);
}
function flattenObject(obj, prefix = []) {
const columns = [];
Object.keys(obj).forEach((key) => {
const value = obj[key];
const currentPath = [...prefix, key];
if (value !== null && value !== void 0 && typeof value === "object" && !Array.isArray(value)) {
const nestedColumns = flattenObject(
value,
currentPath
);
columns.push(...nestedColumns);
} else if (Array.isArray(value)) {
columns.push({
key: currentPath.join("."),
header: formatFieldName(key),
path: currentPath,
isLeaf: true
});
} else if (value !== null && value !== void 0) {
columns.push({
key: currentPath.join("."),
header: formatFieldName(key),
path: currentPath,
isLeaf: true
});
}
});
return columns;
}
var getValue = (item, column) => {
let current = item;
for (const key of column.path) {
if (current && typeof current === "object" && !Array.isArray(current)) {
current = current[key];
} else {
return void 0;
}
}
return current;
};
var handleUpdate = (rowIndex, column, value, data, onUpdate) => {
if (column.path.length === 1) {
const affectedPath = `${rowIndex}.${column.path[0]}`;
onUpdate(rowIndex, column.path[0], value, [affectedPath]);
} else {
const rootKey = column.path[0];
const currentRootObj = data[rowIndex][rootKey] || {};
const updatedObj = JSON.parse(JSON.stringify(currentRootObj));
let current = updatedObj;
for (let i = 1; i < column.path.length - 1; i++) {
const key = column.path[i];
if (!current[key] || typeof current[key] !== "object") {
current[key] = {};
}
current = current[key];
}
const finalKey = column.path[column.path.length - 1];
current[finalKey] = value;
const affectedPath = `${rowIndex}.${column.key}`;
onUpdate(rowIndex, rootKey, updatedObj, [affectedPath]);
}
};
function getTableRowDefaultValue(keyPath, fieldMetadata) {
const newRow = {};
const arrayPath = keyPath.join(".");
Object.entries(fieldMetadata).forEach(([path, metadata]) => {
const pathParts = path.split(".");
if (pathParts.length > keyPath.length + 1) {
const pathArrayPart = pathParts.slice(0, keyPath.length).join(".");
if (pathArrayPart === arrayPath) {
const fieldPath = pathParts.slice(keyPath.length + 1);
const defaultValue = getFieldDefaultValue(metadata);
setNestedValue(newRow, fieldPath, defaultValue);
}
}
});
return newRow;
}
function getFieldDefaultValue(metadata) {
if (!metadata || !metadata.schemaType) {
return "";
}
switch (metadata.schemaType) {
case "array":
return [];
// Empty array for array fields
case "object":
return {};
// Empty object for nested objects
default:
return getDefaultValueForType(metadata.schemaType);
}
}
function setNestedValue(obj, path, value) {
if (path.length === 1) {
obj[path[0]] = value;
} else {
if (!obj[path[0]] || typeof obj[path[0]] !== "object") {
obj[path[0]] = {};
}
setNestedValue(
obj[path[0]],
path.slice(1),
value
);
}
}
// src/extracted-data/metadata-path-utils.ts
function buildTableHeaderMetadataPath(parentKeyPath, columnPath, depth) {
return [...parentKeyPath, "0", ...columnPath.slice(0, depth + 1)];
}
function findFieldSchemaMetadata(keyPath, fieldSchemaMetadata) {
return lookupFieldSchemaMetadata(keyPath, fieldSchemaMetadata);
}
function formatFieldName2(key) {
return key.replace(/_/g, " ").replace(/\b\w/g, (l) => l.toUpperCase());
}
function getFieldDisplayInfo(key, fieldSchemaMetadata, validationErrors = [], keyPath = [key]) {
var _a, _b;
const pathString = keyPath.join(".");
const metadata = findFieldSchemaMetadata(keyPath, fieldSchemaMetadata);
const displayName = (metadata == null ? void 0 : metadata.title) || formatFieldName2(key);
const fieldError = validationErrors.find(
(error) => error.path.join(".") === pathString
);
return {
name: displayName,
isRequired: (_a = metadata == null ? void 0 : metadata.isRequired) != null ? _a : false,
wasMissing: (_b = metadata == null ? void 0 : metadata.wasMissing) != null ? _b : false,
hasError: !!fieldError,
errorMessage: fieldError == null ? void 0 : fieldError.message
};
}
function getFieldLabelClasses(fieldInfo) {
const baseClasses = "text-sm font-medium text-zinc-900 min-w-0 flex-shrink-0 min-h-8 flex items-center";
if (fieldInfo.hasError) {
return `${baseClasses} text-red-600`;
}
if (fieldInfo.isRequired) {
return `${baseClasses} font-semibold`;
}
return baseClasses;
}
function getFieldLabelText(fieldInfo) {
const { name, isRequired } = fieldInfo;
if (isRequired) {
return /* @__PURE__ */ jsxs(Fragment, { children: [
name,
" ",
/* @__PURE__ */ jsx("span", { className: "text-red-500 relative top-0.5", children: "\xA0*" })
] });
}
return name;
}
// src/extracted-data/metadata-lookup.ts
function findExtractedFieldMetadata(path, metadata) {
const pathArray = Array.isArray(path) ? path : path.split(".");
let current = metadata;
for (let i = 0; i < pathArray.length; i++) {
const segment = pathArray[i];
if (!current || typeof current !== "object") {
return void 0;
}
if (!isNaN(Number(segment))) {
if (Array.isArray(current)) {
const index = Number(segment);
current = current[index];
} else {
return void 0;
}
} else {
current = current[segment];
}
if (isExtractedFieldMetadata(current)) {
return current;
}
}
return void 0;
}
function isExtractedFieldMetadata(value) {
if (value === null || typeof value !== "object") {
return false;
}
const obj = value;
if ("confidence" in obj && typeof obj.confidence === "number") {
return true;
}
return false;
}
function TableRenderer({
data,
onUpdate,
onAddRow,
onDeleteRow,
changedPaths,
keyPath = [],
metadata,
validationErrors = [],
onClickField,
editable = true
}) {
var _a, _b;
const effectiveMetadata = {
schema: (_a = metadata == null ? void 0 : metadata.schema) != null ? _a : {},
extracted: (_b = metadata == null ? void 0 : metadata.extracted) != null ? _b : {}
};
const getMetadata = (path) => {
if (effectiveMetadata.extracted) {
return findExtractedFieldMetadata(path, effectiveMetadata.extracted);
}
return void 0;
};
const handleAddRow = () => {
const schemaBasedRow = getTableRowDefaultValue(
keyPath,
effectiveMetadata.schema
);
if (Object.keys(schemaBasedRow).length > 0) {
onAddRow == null ? void 0 : onAddRow(schemaBasedRow);
return;
}
const newRow = {};
if (data.length > 0) {
const firstRow = data[0];
const fillEmptyValues = (obj) => {
const result = {};
Object.keys(obj).forEach((key) => {
const value = obj[key];
if (value !== null && typeof value === "object" && !Array.isArray(value)) {
result[key] = fillEmptyValues(value);
} else {
result[key] = "";
}
});
return result;
};
Object.assign(newRow, fillEmptyValues(firstRow));
} else {
columns.forEach((column) => {
const setNestedValue2 = (obj, path, value) => {
if (path.length === 1) {
obj[path[0]] = value;
} else {
if (!obj[path[0]] || typeof obj[path[0]] !== "object" || Array.isArray(obj[path[0]])) {
obj[path[0]] = {};
}
setNestedValue2(obj[path[0]], path.slice(1), value);
}
};
setNestedValue2(newRow, column.path, "");
});
}
onAddRow == null ? void 0 : onAddRow(newRow);
};
const handleDeleteRow = (index) => {
onDeleteRow == null ? void 0 : onDeleteRow(index);
};
const { columns, maxDepth } = useMemo(() => {
const allColumns = /* @__PURE__ */ new Map();
const columnOrder = [];
if (data && data.length > 0) {
data.forEach((item) => {
const itemColumns = flattenObject(item);
itemColumns.forEach((col) => {
if (!allColumns.has(col.key)) {
allColumns.set(col.key, col);
columnOrder.push(col.key);
}
});
});
} else if (effectiveMetadata.schema && Object.keys(effectiveMetadata.schema).length > 0) {
Object.keys(effectiveMetadata.schema).forEach((path) => {
const pathParts = path.split(".");
if (pathParts.length > keyPath.length + 1) {
const fieldPath = pathParts.slice(keyPath.length + 1);
const fieldKey = fieldPath.join(".");
if (!allColumns.has(fieldKey)) {
const columnDef = {
key: fieldKey,
header: fieldPath[fieldPath.length - 1],
// Use the last part as header
path: fieldPath,
isLeaf: true
// Schema-generated columns are always leaf nodes
};
allColumns.set(fieldKey, columnDef);
columnOrder.push(fieldKey);
}
}
});
}
if (columnOrder.length === 0) {
return { columns: [], maxDepth: 0 };
}
const columns2 = columnOrder.map((key) => allColumns.get(key));
const maxDepth2 = Math.max(...columns2.map((col) => col.path.length));
return { columns: columns2, maxDepth: maxDepth2 };
}, [data, effectiveMetadata.schema, keyPath]);
const generateHeaderRows = () => {
const rows = [];
if (maxDepth === 0 || columns.length === 0) {
return rows;
}
const occupiedCells = Array(maxDepth).fill(null).map(() => Array(columns.length).fill(false));
for (let depth = 0; depth < maxDepth; depth++) {
const rowCells = [];
let colIndex = 0;
while (colIndex < columns.length) {
if (occupiedCells[depth][colIndex]) {
colIndex++;
continue;
}
const column = columns[colIndex];
if (depth < column.path.length) {
const fieldKey = column.path[depth];
const fieldKeyPath = buildTableHeaderMetadataPath(
keyPath,
column.path,
depth
);
const fieldInfo = getFieldDisplayInfo(
fieldKey,
effectiveMetadata.schema,
validationErrors,
fieldKeyPath
);
const headerText = getFieldLabelText(fieldInfo);
const isLeaf = depth === column.path.length - 1;
let colSpan = 1;
let nextColIndex = colIndex + 1;
while (nextColIndex < columns.length) {
const nextColumn = columns[nextColIndex];
if (depth < nextColumn.path.length && nextColumn.path[depth] === column.path[depth]) {
if (depth === 0 || column.path.slice(0, depth).join(".") === nextColumn.path.slice(0, depth).join(".")) {
colSpan++;
nextColIndex++;
} else {
break;
}
} else {
break;
}
}
const rowSpan = isLeaf ? maxDepth - depth : 1;
if (rowSpan > 1) {
for (let r = depth + 1; r < depth + rowSpan; r++) {
for (let c = colIndex; c < colIndex + colSpan; c++) {
occupiedCells[r][c] = true;
}
}
}
rowCells.push(
/* @__PURE__ */ jsx(
TableHead,
{
colSpan,
rowSpan,
className: "px-2 py-2 text-center border-r border-gray-200 border-b min-w-[80px] max-w-[200px] bg-gray-50",
style: rowSpan > 1 ? { height: `${rowSpan * 32}px` } : void 0,
children: /* @__PURE__ */ jsx("div", { className: "break-words text-zinc-900 font-semibold", children: headerText })
},
`${depth}-${colIndex}`
)
);
colIndex = nextColIndex;
} else {
colIndex++;
}
}
rows.push(/* @__PURE__ */ jsx(TableRow, { children: rowCells }, depth));
}
if (onDeleteRow && rows.length > 0) {
const firstRow = rows[0];
const modifiedFirstRow = React2.cloneElement(firstRow, {
children: [
...React2.Children.toArray(firstRow.props.children),
/* @__PURE__ */ jsx(
TableHead,
{
rowSpan: maxDepth,
className: "px-2 py-2 text-center border-r border-gray-200 border-b w-12 bg-gray-50",
style: { height: `${maxDepth * 32}px` }
},
"delete-header"
)
]
});
rows[0] = modifiedFirstRow;
}
return rows;
};
return /* @__PURE__ */ jsx("div", { className: "border border-b-0 rounded-md bg-white", children: /* @__PURE__ */ jsxs(Table, { className: "table-auto", children: [
/* @__PURE__ */ jsx(TableHeader, { children: generateHeaderRows() }),
/* @__PURE__ */ jsxs(TableBody, { children: [
data.map((item, rowIndex) => /* @__PURE__ */ jsxs(TableRow, { className: "hover:bg-gray-50 border-0", children: [
columns.map((column, colIndex) => {
const value = getValue(item, column);
const cellPath = [...keyPath, String(rowIndex), ...column.path];
const isChanged = isTableCellChanged(
changedPaths,
keyPath,
rowIndex,
column.key
);
if (Array.isArray(value)) {
return /* @__PURE__ */ jsx(
TableCell,
{
className: "p-0 border-r border-gray-100 min-w-[160px] max-w-[360px] align-top",
children: /* @__PURE__ */ jsx("div", { className: "px-2 py-2 text-xs text-amber-700 bg-amber-50 border border-amber-200 rounded-sm m-1", children: "Nested list/table is not supported." })
},
colIndex
);
}
const fieldKeyPath = [...keyPath, "*", ...column.path];
const fieldInfo = findFieldSchemaMetadata(
fieldKeyPath,
effectiveMetadata.schema
);
const expectedType = (fieldInfo == null ? void 0 : fieldInfo.schemaType) ? toPrimitiveType(fieldInfo.schemaType) : "string" /* STRING */;
const isRequired = (fieldInfo == null ? void 0 : fieldInfo.isRequired) || false;
return /* @__PURE__ */ jsx(
TableCell,
{
className: "p-0 border-r border-gray-100 min-w-[80px] max-w-[200px]",
children: /* @__PURE__ */ jsx(
EditableField,
{
value,
onSave: (newValue) => handleUpdate(
rowIndex,
column,
newValue,
data,
(idx, key, val, paths) => onUpdate(idx, key, val, paths)
),
metadata: getMetadata(cellPath),
isChanged,
showBorder: true,
expectedType,
required: isRequired,
onClick: (args) => onClickField == null ? void 0 : onClickField({
value: args.value,
metadata: args.metadata,
path: cellPath
}),
editable
}
)
},
colIndex
);
}),
onDeleteRow && /* @__PURE__ */ jsx(TableCell, { className: "p-0 border-r border-gray-100 border-b w-12", children: /* @__PURE__ */ jsx("div", { className: "w-full h-full flex items-center justify-center", children: /* @__PURE__ */ jsx(
Button,
{
variant: "ghost",
size: "icon",
onClick: () => handleDeleteRow(rowIndex),
className: "h-8 w-8 text-red-500 hover:text-red-700 hover:bg-transparent cursor-pointer",
title: "Delete row",
children: /* @__PURE__ */ jsx(Trash2, { className: "h-4 w-4" })
}
) }) })
] }, rowIndex)),
onAddRow && /* @__PURE__ */ jsxs(TableRow, { className: "hover:bg-gray-50", children: [
Array.from({ length: columns.length }).map((_, colIndex) => /* @__PURE__ */ jsx(
TableCell,
{
className: "p-0 border-b min-w-[80px] max-w-[200px]"
},
colIndex
)),
/* @__PURE__ */ jsx(
TableCell,
{
colSpan: columns.length + (onDeleteRow ? 1 : 0),
className: "border-b text-center p-0",
children: /* @__PURE__ */ jsx(
Button,
{
variant: "ghost",
size: "sm",
onClick: handleAddRow,
className: "text-blue-600 border-blue-200 hover:bg-transparent cursor-pointer",
children: /* @__PURE__ */ jsx(Plus, { className: "h-4 w-4" })
}
)
}
)
] })
] })
] }) });
}
// src/extracted-data/list-renderer/list-renderer-utils.ts
function buildArrayItemPath(keyPath, index) {
return [...keyPath, String(index)].join(".");
}
function isArrayItemChanged(changedPaths, keyPath, index) {
if (!changedPaths) return false;
const fullPath = buildArrayItemPath(keyPath, index);
return changedPaths.has(fullPath);
}
function getArrayItemDefaultValue(keyPath, fieldMetadata) {
const itemFieldPath = [...keyPath, "*"];
const itemMetadata = lookupFieldSchemaMetadata(itemFieldPath, fieldMetadata);
if (!(itemMetadata == null ? void 0 : itemMetadata.schemaType)) {
return "";
}
return getDefaultValueForType(itemMetadata.schemaType);
}
function ListRenderer({
data,
onUpdate,
onAdd,
onDelete,
changedPaths,
keyPath = [],
metadata,
onClickField,
editable = true
}) {
var _a, _b;
const effectiveSchema = (_a = metadata == null ? void 0 : metadata.schema) != null ? _a : {};
const effectiveExtracted = (_b = metadata == null ? void 0 : metadata.extracted) != null ? _b : {};
const handleAdd = () => {
const defaultValue = getArrayItemDefaultValue(keyPath, effectiveSchema);
onAdd == null ? void 0 : onAdd(defaultValue);
};
const handleDelete = (index) => {
onDelete == null ? void 0 : onDelete(index);
};
const getExpectedType = () => {
const itemFieldPath = [...keyPath, "*"];
const itemMetadata = findFieldSchemaMetadata(
itemFieldPath,
effectiveSchema
);
if (itemMetadata == null ? void 0 : itemMetadata.schemaType) {
return toPrimitiveType(itemMetadata.schemaType);
}
return "string" /* STRING */;
};
const expectedType = getExpectedType();
const handleFieldClick = (args, index) => {
onClickField == null ? void 0 : onClickField({
value: args.value,
metadata: args.metadata,
path: [...keyPath, String(index)]
});
};
if (!data || data.length === 0) {
return /* @__PURE__ */ jsxs("div", { className: "border rounded-md bg-white p-4", children: [
/* @__PURE__ */ jsx("div", { className: "text-gray-500 text-sm mb-3", children: "Empty array" }),
onAdd && /* @__PURE__ */ jsx(
Button,
{
variant: "outline",
size: "sm",
onClick: handleAdd,
className: "text-blue-600 border-blue-200 hover:bg-blue-50 cursor-pointer",
children: /* @__PURE__ */ jsx(Plus, { className: "h-4 w-4" })
}
)
] });
}
return /* @__PURE__ */ jsx("div", { className: "border rounded-md bg-white overflow-auto", children: /* @__PURE__ */ jsx(Table, { className: "table-auto", children: /* @__PURE__ */ jsxs(TableBody, { children: [
data.map((item, index) => {
const isChanged = isArrayItemChanged(changedPaths, keyPath, index);
const handleItemFieldClick = (args) => {
handleFieldClick(args, index);
};
return /* @__PURE__ */ jsxs(TableRow, { className: "hover:bg-gray-50 border-0", children: [
/* @__PURE__ */ jsx(TableCell, { className: "p-0 border-r border-gray-100 w-12 align-middle h-full", children: /* @__PURE__ */ jsx("div", { className: "w-full h-full border-b flex items-center justify-center text-sm text-gray-600 font-medium bg-gray-25 p-2", children: index + 1 }) }),
/* @__PURE__ */ jsx(TableCell, { className: "p-0 min-w-[120px] align-top h-full", children: /* @__PURE__ */ jsx(
EditableField,
{
value: item,
onSave: (newValue) => onUpdate(index, newValue),
metadata: findExtractedFieldMetadata(
[...keyPath, String(index)],
effectiveExtracted
),
isChanged,
showBorder: true,
expectedType,
required: expectedType === "number" /* NUMBER */ || expectedType === "boolean" /* BOOLEAN */,
onClick: handleItemFieldClick,
editable
}
) }),
onDelete && /* @__PURE__ */ jsx(TableCell, { className: "p-0 w-12 align-middle h-full", children: /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center border-b", children: /* @__PURE__ */ jsx(
Button,
{
variant: "ghost",
size: "icon",
onClick: () => handleDelete(index),
className: "h-9 w-9 text-red-500 hover:text-red-700 hover:bg-transparent cursor-pointer rounded-none",
title: "Delete item",
children: /* @__PURE__ */ jsx(Trash2, { className: "h-4 w-4" })
}
) }) })
] }, index);
}),
onAdd && /* @__PURE__ */ jsxs(TableRow, { className: "hover:bg-gray-50 border-0", children: [
/* @__PURE__ */ jsx(TableCell, { className: "p-0 border-r border-gray-100 w-12 align-middle h-full" }),
/* @__PURE__ */ jsx(TableCell, { className: "p-0 min-w-[120px] align-top h-full" }),
/* @__PURE__ */ jsx(TableCell, { colSpan: onDelete ? 3 : 2, className: "text-center p-0", children: /* @__PURE__ */ jsx(
Button,
{
variant: "ghost",
size: "sm",
onClick: handleAdd,
className: "h-9 w-9 text-blue-600 border-blue-200 hover:bg-transparent cursor-pointer",
children: /* @__PURE__ */ jsx(Plus, { className: "h-4 w-4" })
}
) })
] })
] }) }) });
}
// src/extracted-data/property-renderer/property-renderer-utils.ts
var isPropertyChanged = (changedPaths, keyPath) => {
if (!changedPaths) return false;
const pathString = keyPath.join(".");
return changedPaths.has(pathString);
};
var isArrayOfObjects = (value) => {
return value.length > 0 && typeof value[0] === "object" && value[0] !== null && !Array.isArray(value[0]);
};
var shouldShowKeyOnSeparateLine = (value) => {
return Array.isArray(value) && isArrayOfObjects(value) || typeof value === "object" && value !== null && !Array.isArray(value);
};
function PropertyRenderer({
keyPath,
value,
onUpdate,
changedPaths,
metadata,
validationErrors = [],
onClickField,
editable = true
}) {
var _a, _b;
const pathString = keyPath.join(".");
const isChanged = isPropertyChanged(changedPaths, keyPath);
const effectiveMetadata = {
schema: (_a = metadata == null ? void 0 : metadata.schema) != null ? _a : {},
extracted: (_b = metadata == null ? void 0 : metadata.extracted) != null ? _b : {}
};
const getMetadata = (path) => {
if (effectiveMetadata.extracted) {
return findExtractedFieldMetadata(path, effectiveMetadata.extracted);
}
return void 0;
};
const handleFieldClick = (args) => {
onClickField == null ? void 0 : onClickField({
value: args.value,
metadata: args.metadata,
path: keyPath
});
};
const renderFieldLabel = (key, currentKeyPath, additionalClasses) => {
const fieldInfo2 = getFieldDisplayInfo(
key,
effectiveMetadata.schema,
validationErrors,
currentKeyPath
);
const baseClasses = getFieldLabelClasses(fieldInfo2);
const finalClasses = additionalClasses ? `${baseClasses} ${additionalClasses}` : baseClasses;
return /* @__PURE__ */ jsx("div", { className: finalClasses, children: getFieldLabelText(fieldInfo2) });
};
if (value === null || value === void 0) {
const fieldInfo2 = findFieldSchemaMetadata(
keyPath,
effectiveMetadata.schema
);
const expectedType2 = (fieldInfo2 == null ? void 0 : fieldInfo2.schemaType) ? toPrimitiveType(fieldInfo2.schemaType) : "string" /* STRING */;
const isRequired2 = (fieldInfo2 == null ? void 0 : fieldInfo2.isRequired) || false;
return /* @__PURE__ */ jsx(
EditableField,
{
value: "N/A",
onSave: (newValue) => onUpdate(keyPath, newValue),
metadata: getMetadata(pathString),
isChanged,
expectedType: expectedType2,
required: isRequired2,
onClick: handleFieldClick,
editable
}
);
}
if (Array.isArray(value)) {
if (value.length === 0) {
return /* @__PURE__ */ jsx(
ListRenderer,
{
data: value,
onUpdate: () => {
},
onAdd: (newValue) => {
const newArray = [newValue];
const newItemPath = [...keyPath, "0"];
onUpdate(keyPath, newArray, [newItemPath]);
},
changedPaths,
keyPath,
metadata: { schema: effectiveMetadata.schema, extracted: {} },
editable
}
);
}
if (isArrayOfObjects(value)) {
return /* @__PURE__ */ jsx(
TableRenderer,
{
data: value,
onUpdate: (index, key, newValue, affectedPaths) => {
const newArray = [...value];
newArray[index] = __spreadProps(__spreadValues({}, newArray[index]), { [key]: newValue });
if (affectedPaths && affectedPaths.length > 0) {
const absolutePaths = affectedPaths.map((path) => {
const pathParts = path.split(".");
return [...keyPath, ...pathParts];
});
onUpdate(keyPath, newArray, absolutePaths);
} else {
const cellPath = [...keyPath, String(index), key];
onUpdate(keyPath, newArray, [cellPath]);
}
},
onAddRow: (newRow) => {
const newArray = [
...value,
newRow
];
const newRowPath = [...keyPath, String(value.length)];
onUpdate(keyPath, newArray, [newRowPath]);
},
onDeleteRow: (index) => {
const newArray = value.filter((_, i) => i !== index);
onUpdate(keyPath, newArray, [keyPath]);
},
changedPaths,
keyPath,
metadata: {
schema: effectiveMetadata.schema,
extracted: effectiveMetadata.extracted
},
validationErrors,
onClickField,
editable
}
);
} else {
return /* @__PURE__ */ jsx(
ListRenderer,
{
data: value,
onUpdate: (index, newValue) => {
const newArray = [...value];
newArray[index] = newValue;
const itemPath = [...keyPath, String(index)];
onUpdate(keyPath, newArray, [itemPath]);
},
onAdd: (newValue) => {
const newArray = [...value, newValue];
const newItemPath = [...keyPath, String(value.length)];
onUpdate(keyPath, newArray, [newItemPath]);
},
onDelete: (index) => {
const newArray = value.filter((_, i) => i !== index);
onUpdate(keyPath, newArray, [keyPath]);
},
changedPaths,
keyPath,
metadata: {
schema: effectiveMetadata.schema,
extracted: effectiveMetadata.extracted
},
onClickField,
editable
}
);
}
}
if (typeof value === "object") {
return /* @__PURE__ */ jsx("div", { className: "relative", children: /* @__PURE__ */ jsx("div", { className: "pl-4 border-l-2 border-gray-200", children: Object.entries(value).map(([key, val]) => {
if (shouldShowKeyOnSeparateLine(val)) {
return /* @__PURE__ */ jsxs("div", { children: [
renderFieldLabel(key, [...keyPath, key]),
/* @__PURE__ */ jsx("div", { className: "mt-2", children: /* @__PURE__ */ jsx(
PropertyRenderer,
{
keyPath: [...keyPath, key],
value: val,
onUpdate,
changedPaths,
metadata: effectiveMetadata,
validationErrors,
onClickField,
editable
}
) })
] }, key);
} else {
return /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-6", children: [
renderFieldLabel(
key,
[...keyPath, key],
"min-w-0 flex-shrink-0"
),
/* @__PURE__ */ jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsx(
PropertyRenderer,
{
keyPath: [...keyPath, key],
value: val,
onUpdate,
changedPaths,
metadata: effectiveMetadata,
validationErrors,
onClickField,
editable
}
) })
] }) }, key);
}
}) }) });
}
const fieldInfo = findFieldSchemaMetadata(keyPath, effectiveMetadata.schema);
const expectedType = (fieldInfo == null ? void 0 : fieldInfo.schemaType) ? toPrimitiveType(fieldInfo.schemaType) : "string" /* STRING */;
const isRequired = (fieldInfo == null ? void 0 : fieldInfo.isRequired) || false;
return /* @__PURE__ */ jsx(
EditableField,
{
value,
onSave: (newValue) => onUpdate(keyPath, newValue),
metadata: getMetadata(pathString),
isChanged,
expectedType,
required: isRequired,
onClick: handleFieldClick,
editable
}
);
}
// src/extracted-data/schema-reconciliation.ts
function reconcileDataWithJsonSchema(originalData, jsonSchema) {
const metadata = {};
const requiredFields = /* @__PURE__ */ new Set();
const addedOptionalFields = /* @__PURE__ */ new Set();
const validationErrors = [];
const data = structuredClone(originalData);
fillMissingFieldsFromJsonSchema(data, jsonSchema, [], {
metadata,
requiredFields,
addedOptionalFields});
return {
data,
schemaMetadata: metadata,
requiredFields,
addedOptionalFields,
validationErrors,
isValid: validationErrors.length === 0
};
}
function fillMissingFieldsFromJsonSchema(data, jsonSchema, currentPath, context) {
var _a, _b;
const properties = jsonSchema.properties || {};
if (data === null || data === void 0 || typeof data !== "object" || Array.isArray(data)) {
return;
}
const dataObj = data;
for (const [fieldName, fieldSchema] of Object.entries(properties)) {
const fieldPath = [...currentPath, fieldName];
const pathString = fieldPath.join(".");
const existsInData = fieldName in dataObj;
const isRequired = (_b = ((_a = jsonSchema.required) == null ? void 0 : _a.includes(fieldName)) && !isNullable(fieldSchema)) != null ? _b : false;
let wasMissing = false;
if (!existsInData && !isRequired) {
dataObj[fieldName] = void 0;
wasMissing = true;
context.addedOptionalFields.add(pathString);
}
const baseSchema = fieldSchema;
const metadata = {
isRequired,
isOptional: !isRequired,
schemaType: baseSchema.type || "unknown",
title: baseSchema.title,
description: baseSchema.description,
wasMissing
};
context.metadata[pathString] = metadata;
if (baseSchema.type === "array") {
const arraySchema = baseSchema;
if (arraySchema.items && typeof arraySchema.items === "object" && !Array.isArray(arraySchema.items)) {
const itemSchema = arraySchema.items;
if (itemSchema.type === "object") {
const objectItemSchema = itemSchema;
generateArrayItemMetadata(
objectItemSchema,
[...fieldPath, "*"],
// Add "*" wildcard for array items
context
);
} else {
const itemPathString = [...fieldPath, "*"].join(".");
const itemMetadata = {
isRequired: false,
// Array items themselves are not required
isOptional: true,
schemaType: itemSchema.type || "unknown",
title: itemSchema.title,
description: itemSchema.description,
wasMissing: false
};
context.metadata[itemPathString] = itemMetadata;
}
}
}
if (isRequired) {
context.requiredFields.add(pathString);
}
if (baseSchema.type === "object" && dataObj[fieldName] !== null && dataObj[fieldName] !== void 0) {
const objectSchema = baseSchema;
fillMissingFieldsFromJsonSchema(
dataObj[fieldName],
objectSchema,
fieldPath,
context
);
} else if (baseSchema.type === "array" && Array.isArray(dataObj[fieldName])) {
const arraySchema = baseSchema;
if (arraySchema.items && typeof arraySchema.items === "object" && !Array.isArray(arraySchema.items)) {
const itemSchema = arraySchema.items;
if (itemSchema.type === "object") {
dataObj[fieldName].forEach((item, index) => {
fillMissingFieldsFromJsonSchema(
item,
itemSchema,
[...fieldPath, String(index)],
context
);
});
}
}
}
}
}
function generateArrayItemMetadata(objectSchema, currentPath, context) {
var _a, _b;
const { properties } = objectSchema;
if (!properties || typeof properties !== "object") {
return;
}
for (const [fieldName, fieldSchema] of Object.entries(properties)) {
const fieldPath = [...currentPath, fieldName];
const pathString = fieldPath.join(".");
const baseSchema = fieldSchema;
const isRequired = (_b = (_a = objectSchema.required) == null ? void 0 : _a.includes(fieldName)) != null ? _b : false;
const metadata = {
isRequired,
isOptional: !isRequired,
schemaType: baseSchema.type || "unknown",
title: baseSchema.title,
description: baseSchema.description,
wasMissing: false
// Array item fields are schema-defined, not missing
};
context.metadata[pathString] = metadata;
if (baseSchema.type === "object") {
const nestedObjectSchema = baseSchema;
generateArrayItemMetadata(nestedObjectSchema, fieldPath, context);
}
if (baseSchema.type === "array") {
const arraySchema = baseSchema;
if (arraySchema.items && typeof arraySchema.items === "object" && !Array.isArray(arraySchema.items)) {
const itemSchema = arraySchema.items;
if (itemSchema.type === "object") {
const objectItemSchema = itemSchema;
generateArrayItemMetadata(
objectItemSchema,
[...fieldPath, "*"],
context
);
} else {
const itemPathString = [...fieldPath, "*"].join(".");
const itemMetadata = {
isRequired: false,
isOptional: true,
schemaType: itemSchema.type || "unknown",
title: itemSchema.title,
description: itemSchema.description,
wasMissing: false
};
context.metadata[itemPathString] = itemMetadata;
}
}
}
}
}
function ExtractedDataDisplay({
extractedData,
emptyMessage = "No extracted data available",
onChange,
editable = true,
jsonSchema,
onClickField
}) {
const [changedPaths, setChangedPaths] = useState(/* @__PURE__ */ new Set());
const { data, field_metadata } = extractedData;
const reconciliationResult = useMemo(() => {
if (!jsonSchema) {
return null;
}
return reconcileDataWithJsonSchema(data, jsonSchema);
}, [data, jsonSchema]);
const displayData = (reconciliationResult == null ? void 0 : reconciliationResult.data) || data;
const schemaMetadata = (reconciliationResult == null ? void 0 : reconciliationResult.schemaMetadata) || {};
const validationErrors = (reconciliationResult == null ? void 0 : reconciliationResult.validationErrors) || [];
const renderFieldLabel = (key, additionalClasses) => {
const fieldInfo = getFieldDisplayInfo(
key,
schemaMetadata,
validationErrors,
[key]
);
const baseClasses = getFieldLabelClasses(fieldInfo);
const finalClasses = additionalClasses ? `${baseClasses} ${additionalClasses}` : baseClasses;
return /* @__PURE__ */ jsx("div", { className: finalClasses, children: getFieldLabelText(fieldInfo) });
};
if (!displayData || Object.keys(displayData).length === 0) {
return /* @__PURE__ */ jsx("div", { className: "text-sm text-gray-500 text-center py-4", children: emptyMessage });
}
const handleUpdate2 = (path, newValue, additionalPaths) => {
if (!editable || !onChange) return;
const newData = __spreadValues({}, data);
let current = newData;
for (let i = 0; i < path.length - 1; i++) {
current = current[path[i]];
}
current[path[path.length - 1]] = newValue;
const pathsToTrack = [path, ...additionalPaths || []];
setChangedPaths((prev) => {
const newSet = new Set(prev);
pathsToTrack.forEach((p) => {
newSet.add(p.join("."));
});
return newSet;
});
onChange(newData);
};
return /* @__PURE__ */ jsx("div", { children: Object.keys((jsonSchema == null ? void 0 : jsonSchema.properties) || {}).map((key) => {
const value = displayData[key];
if (Array.isArray(value) && value.length > 0 && typeof value[0] === "object" && value[0] !== null) {
return /* @__PURE__ */ jsxs("div", { children: [
renderFieldLabel(key),
/* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(
PropertyRenderer,
{
keyPath: [key],
value,
onUpdate: handleUpdate2,
changedPaths,
metadata: {
schema: schemaMetadata,
extracted: field_metadata
},
validationErrors,
onClickField,
editable
}
) })
] }, key);
} else if (typeof value === "object" && value !== null) {
return /* @__PURE__ */ jsxs("div", { children: [
renderFieldLabel(key),
/* @__PURE__ */ jsx(
PropertyRenderer,
{
keyPath: [key],
value,
onUpdate: handleUpdate2,
changedPaths,
metadata: {
schema: schemaMetadata,
extracted: field_metadata
},
validationErrors,
onClickField,
editable
}
)
] }, key);
} else {
return /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-6"