@tetrascience-npm/tetrascience-react-ui 1.0.0-beta.157.1 → 1.0.0-beta.158.1

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.
Files changed (68) hide show
  1. package/README.md +113 -0
  2. package/dist/components/composed/PlateMapEditor/ManifestFilterPopover.cjs +1 -1
  3. package/dist/components/composed/PlateMapEditor/ManifestFilterPopover.cjs.map +1 -1
  4. package/dist/components/composed/PlateMapEditor/ManifestFilterPopover.d.ts +5 -1
  5. package/dist/components/composed/PlateMapEditor/ManifestFilterPopover.js +32 -30
  6. package/dist/components/composed/PlateMapEditor/ManifestFilterPopover.js.map +1 -1
  7. package/dist/components/composed/PlateMapEditor/PlateMapEditor.cjs +1 -1
  8. package/dist/components/composed/PlateMapEditor/PlateMapEditor.cjs.map +1 -1
  9. package/dist/components/composed/PlateMapEditor/PlateMapEditor.d.ts +269 -13
  10. package/dist/components/composed/PlateMapEditor/PlateMapEditor.js +392 -310
  11. package/dist/components/composed/PlateMapEditor/PlateMapEditor.js.map +1 -1
  12. package/dist/components/composed/PlateMapEditor/PlateMapForm.cjs +1 -1
  13. package/dist/components/composed/PlateMapEditor/PlateMapForm.cjs.map +1 -1
  14. package/dist/components/composed/PlateMapEditor/PlateMapForm.d.ts +5 -1
  15. package/dist/components/composed/PlateMapEditor/PlateMapForm.js +19 -15
  16. package/dist/components/composed/PlateMapEditor/PlateMapForm.js.map +1 -1
  17. package/dist/components/composed/PlateMapEditor/PlateMapGrid.cjs +1 -1
  18. package/dist/components/composed/PlateMapEditor/PlateMapGrid.cjs.map +1 -1
  19. package/dist/components/composed/PlateMapEditor/PlateMapGrid.d.ts +12 -1
  20. package/dist/components/composed/PlateMapEditor/PlateMapGrid.js +69 -63
  21. package/dist/components/composed/PlateMapEditor/PlateMapGrid.js.map +1 -1
  22. package/dist/components/composed/PlateMapEditor/PlateMapManifest.cjs +1 -1
  23. package/dist/components/composed/PlateMapEditor/PlateMapManifest.cjs.map +1 -1
  24. package/dist/components/composed/PlateMapEditor/PlateMapManifest.d.ts +13 -4
  25. package/dist/components/composed/PlateMapEditor/PlateMapManifest.js +38 -29
  26. package/dist/components/composed/PlateMapEditor/PlateMapManifest.js.map +1 -1
  27. package/dist/components/composed/PlateMapEditor/PlatePaintGrid.cjs +1 -1
  28. package/dist/components/composed/PlateMapEditor/PlatePaintGrid.cjs.map +1 -1
  29. package/dist/components/composed/PlateMapEditor/PlatePaintGrid.d.ts +6 -1
  30. package/dist/components/composed/PlateMapEditor/PlatePaintGrid.js +490 -275
  31. package/dist/components/composed/PlateMapEditor/PlatePaintGrid.js.map +1 -1
  32. package/dist/components/composed/PlateMapEditor/WellLegend.cjs +1 -1
  33. package/dist/components/composed/PlateMapEditor/WellLegend.cjs.map +1 -1
  34. package/dist/components/composed/PlateMapEditor/WellLegend.d.ts +8 -2
  35. package/dist/components/composed/PlateMapEditor/WellLegend.js +8 -7
  36. package/dist/components/composed/PlateMapEditor/WellLegend.js.map +1 -1
  37. package/dist/components/composed/PlateMapEditor/WellManifestTable.cjs +1 -1
  38. package/dist/components/composed/PlateMapEditor/WellManifestTable.cjs.map +1 -1
  39. package/dist/components/composed/PlateMapEditor/WellManifestTable.d.ts +6 -2
  40. package/dist/components/composed/PlateMapEditor/WellManifestTable.js +288 -256
  41. package/dist/components/composed/PlateMapEditor/WellManifestTable.js.map +1 -1
  42. package/dist/components/composed/PlateMapEditor/WellMetadataForm.cjs +1 -1
  43. package/dist/components/composed/PlateMapEditor/WellMetadataForm.cjs.map +1 -1
  44. package/dist/components/composed/PlateMapEditor/WellMetadataForm.d.ts +5 -1
  45. package/dist/components/composed/PlateMapEditor/WellMetadataForm.js +61 -66
  46. package/dist/components/composed/PlateMapEditor/WellMetadataForm.js.map +1 -1
  47. package/dist/components/composed/PlateMapEditor/WellQuickPaint.cjs +2 -0
  48. package/dist/components/composed/PlateMapEditor/WellQuickPaint.cjs.map +1 -0
  49. package/dist/components/composed/PlateMapEditor/WellQuickPaint.d.ts +23 -0
  50. package/dist/components/composed/PlateMapEditor/WellQuickPaint.js +75 -0
  51. package/dist/components/composed/PlateMapEditor/WellQuickPaint.js.map +1 -0
  52. package/dist/components/composed/PlateMapEditor/index.d.ts +6 -2
  53. package/dist/components/composed/PlateMapEditor/types.d.ts +65 -0
  54. package/dist/components/composed/PlateMapEditor/usePlateMapEditorState.cjs +2 -0
  55. package/dist/components/composed/PlateMapEditor/usePlateMapEditorState.cjs.map +1 -0
  56. package/dist/components/composed/PlateMapEditor/usePlateMapEditorState.d.ts +109 -0
  57. package/dist/components/composed/PlateMapEditor/usePlateMapEditorState.js +246 -0
  58. package/dist/components/composed/PlateMapEditor/usePlateMapEditorState.js.map +1 -0
  59. package/dist/composed/PlateMapEditor.cjs +1 -1
  60. package/dist/composed/PlateMapEditor.js +48 -42
  61. package/dist/composed/PlateMapEditor.js.map +1 -1
  62. package/dist/index.cjs +1 -1
  63. package/dist/index.css +1 -1
  64. package/dist/index.js +701 -695
  65. package/dist/index.js.map +1 -1
  66. package/dist/index.scoped.css +1 -1
  67. package/dist/index.tailwind.css +1 -1
  68. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"WellManifestTable.js","sources":["../../../../src/components/composed/PlateMapEditor/WellManifestTable.tsx"],"sourcesContent":["import { ArrowDownToLine, Check, ChevronDown, ChevronRight, Layers } from \"lucide-react\";\nimport * as React from \"react\";\n\nimport { ManifestFilterPopover } from \"./ManifestFilterPopover\";\n\nimport type { WellColumn, WellField, WellId, WellRecord, WellSelectOption } from \"./types\";\nimport type { FilterColumnConfig, FilterCondition } from \"@/components/ui/data-table/data-table\";\n\nimport { Badge } from \"@/components/ui/badge\";\nimport { Button } from \"@/components/ui/button\";\nimport { Checkbox } from \"@/components/ui/checkbox\";\nimport {\n Combobox,\n ComboboxChip,\n ComboboxChips,\n ComboboxChipsInput,\n ComboboxContent,\n ComboboxEmpty,\n ComboboxItem,\n ComboboxList,\n ComboboxValue,\n useComboboxAnchor,\n} from \"@/components/ui/combobox\";\nimport { applyFilterCondition } from \"@/components/ui/data-table/data-table\";\nimport { Input } from \"@/components/ui/input\";\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from \"@/components/ui/select\";\nimport { Switch } from \"@/components/ui/switch\";\nimport { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from \"@/components/ui/table\";\nimport { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from \"@/components/ui/tooltip\";\nimport { cn } from \"@/lib/utils\";\n\nfunction MultiSelectCell({\n ariaLabel,\n value,\n options,\n placeholder,\n onChange,\n}: {\n ariaLabel: string;\n value: string[];\n options: WellSelectOption[];\n placeholder?: string;\n onChange: (next: string[]) => void;\n}) {\n const anchorRef = useComboboxAnchor();\n const labelByValue = React.useMemo(() => {\n const m = new Map<string, string>();\n options.forEach((o) => m.set(o.value, o.label));\n return m;\n }, [options]);\n\n return (\n <Combobox multiple items={options.map((o) => o.value)} value={value} onValueChange={onChange}>\n <ComboboxChips ref={anchorRef} className={cn(\"min-h-7 w-full py-0.5\", CELL_EDITOR_CLASS)}>\n <ComboboxValue>\n {(items: string[]) =>\n items.map((item) => <ComboboxChip key={item}>{labelByValue.get(item) ?? item}</ComboboxChip>)\n }\n </ComboboxValue>\n <ComboboxChipsInput aria-label={ariaLabel} placeholder={placeholder ?? \"Select…\"} />\n </ComboboxChips>\n <ComboboxContent anchor={anchorRef}>\n <ComboboxEmpty>No options.</ComboboxEmpty>\n <ComboboxList aria-label={ariaLabel}>\n {(item: string) => (\n <ComboboxItem key={item} value={item}>\n {labelByValue.get(item) ?? item}\n </ComboboxItem>\n )}\n </ComboboxList>\n </ComboboxContent>\n </Combobox>\n );\n}\n\n/**\n * Cell editors render borderless by default so the table reads flat. The\n * underlying primitives keep their `focus-visible` / `focus-within` rings, so\n * an outline only appears while the user is actively editing the cell.\n */\nconst CELL_EDITOR_CLASS = \"border-transparent shadow-none hover:border-input/40\";\n\nconst PAGE_SIZE_SMALL = 25;\nconst PAGE_SIZE_MEDIUM = 50;\nconst PAGE_SIZE_LARGE = 100;\nconst DEFAULT_PAGE_SIZE = PAGE_SIZE_SMALL;\nconst DEFAULT_PAGE_SIZE_OPTIONS: number[] = [PAGE_SIZE_SMALL, PAGE_SIZE_MEDIUM, PAGE_SIZE_LARGE];\n\nfunction hasFillValue(value: unknown): boolean {\n return value !== undefined && value !== null && value !== \"\";\n}\n\nconst INPUT_TYPE_BY_KIND: Record<string, string> = {\n number: \"number\",\n integer: \"number\",\n date: \"date\",\n datetime: \"datetime-local\",\n time: \"time\",\n};\n\nfunction resolveInputType(kind: string): string {\n return INPUT_TYPE_BY_KIND[kind] ?? \"text\";\n}\n\nfunction parseInputValue(kind: string, raw: string): unknown {\n if (raw === \"\") return undefined;\n if (kind === \"number\") {\n const num = parseFloat(raw);\n return Number.isFinite(num) ? num : raw;\n }\n if (kind === \"integer\") {\n const num = parseInt(raw, 10);\n return Number.isFinite(num) ? num : raw;\n }\n return raw;\n}\n\nexport interface WellManifestTableRowContext<T extends WellRecord = WellRecord> {\n wellId: WellId;\n row: T;\n isSelected: boolean;\n}\n\nexport interface WellManifestTableProps<T extends WellRecord = WellRecord> {\n values: Map<WellId, T>;\n columns: WellColumn<T>[];\n /**\n * Field schema. If a column has `field` matching a `select`-kind field, a\n * Select cell renders automatically with that field's options.\n */\n fields?: WellField<T>[];\n selection?: Set<WellId>;\n onSelectionChange?: (next: Set<WellId>) => void;\n onChange: (next: Map<WellId, T>) => void;\n /** Builds an empty record for a freshly-created row. */\n emptyEntry: (id: WellId) => T;\n /** Filter that controls which empty rows surface. Defaults to `false`. */\n isPopulated?: (row: T) => boolean;\n pageSize?: number;\n pageSizeOptions?: number[];\n /** Adds a column header action that copies the first non-empty value downward. */\n enableFillDown?: boolean;\n /**\n * Extra props spread onto each `<tr>` — typically used to attach a DnD\n * library's `setNodeRef`, listeners, and data attributes so rows can act as\n * drag sources. The kit stays DnD-library-agnostic.\n */\n rowProps?: (ctx: WellManifestTableRowContext<T>) => React.ComponentProps<\"tr\"> | undefined;\n /** Enables an inline filter popover above the table. Defaults to false. */\n filterable?: boolean;\n /**\n * Optional override of filterable column configs. When omitted, every column\n * with a `field` becomes filterable using the default operator set from the\n * shared data-table filter system.\n */\n filterColumns?: FilterColumnConfig[];\n /** Enables an inline group-by selector. Defaults to false. */\n groupable?: boolean;\n className?: string;\n}\n\ninterface GroupedRow<T> {\n key: string;\n rows: Array<{ id: WellId; row: T }>;\n}\n\nfunction groupRowsBy<T extends WellRecord>(rows: Array<{ id: WellId; row: T }>, field: string): GroupedRow<T>[] {\n const map = new Map<string, GroupedRow<T>>();\n for (const entry of rows) {\n const raw = (entry.row as Record<string, unknown>)[field];\n const key = raw === undefined || raw === null || raw === \"\" ? \"(blank)\" : String(raw);\n const existing = map.get(key);\n if (existing) existing.rows.push(entry);\n else map.set(key, { key, rows: [entry] });\n }\n return [...map.values()];\n}\n\nfunction inferFilterColumns<T extends WellRecord>(columns: WellColumn<T>[]): FilterColumnConfig[] {\n return columns.filter((col) => !!col.field).map((col) => ({ columnId: col.field as string, label: col.header }));\n}\n\nexport function WellManifestTable<T extends WellRecord = WellRecord>({\n values,\n columns,\n fields,\n selection,\n onSelectionChange,\n onChange,\n emptyEntry,\n isPopulated,\n pageSize: initialPageSize = DEFAULT_PAGE_SIZE,\n pageSizeOptions = DEFAULT_PAGE_SIZE_OPTIONS,\n enableFillDown = true,\n rowProps,\n filterable = false,\n filterColumns,\n groupable = false,\n className,\n}: WellManifestTableProps<T>) {\n const [showAll, setShowAll] = React.useState(false);\n const [page, setPage] = React.useState(0);\n const [pageSize, setPageSize] = React.useState(initialPageSize);\n const [filters, setFilters] = React.useState<FilterCondition[]>([]);\n const [groupByField, setGroupByField] = React.useState<string>(\"\");\n const [collapsedGroups, setCollapsedGroups] = React.useState<Set<string>>(new Set());\n\n React.useEffect(() => {\n setPage(0);\n }, [showAll]);\n\n const fieldByKey = React.useMemo(() => {\n const m = new Map<string, WellField<T>>();\n (fields ?? []).forEach((f) => m.set(f.key, f));\n return m;\n }, [fields]);\n\n const resolvedFilterColumns = React.useMemo<FilterColumnConfig[]>(\n () => filterColumns ?? inferFilterColumns(columns),\n [columns, filterColumns],\n );\n\n const rows = React.useMemo(() => {\n const arr = [...values.entries()].map(([id, row]) => ({\n id,\n row,\n }));\n let filtered = arr;\n if (!showAll && isPopulated) {\n filtered = arr.filter((r) => isPopulated(r.row));\n }\n if (filterable && filters.length > 0) {\n filtered = filtered.filter((entry) => {\n const record = entry.row as Record<string, unknown>;\n return filters.every((condition) => {\n const cellRaw = record[condition.columnId];\n const cellValue = cellRaw === undefined || cellRaw === null ? \"\" : String(cellRaw);\n return applyFilterCondition(cellValue, condition.operator, condition.value);\n });\n });\n }\n if (selection && selection.size > 0) {\n const have = new Set(filtered.map((r) => r.id));\n selection.forEach((p) => {\n if (!have.has(p) && !values.has(p)) {\n filtered = [...filtered, { id: p, row: emptyEntry(p) }];\n }\n });\n }\n return filtered.sort((a, b) => a.id.localeCompare(b.id));\n }, [values, showAll, isPopulated, selection, emptyEntry, filterable, filters]);\n\n React.useEffect(() => {\n setPage(0);\n }, [filters]);\n\n const pagedRows = React.useMemo(\n () => rows.slice(page * pageSize, page * pageSize + pageSize),\n [rows, page, pageSize],\n );\n\n const updateRow = (wellId: WellId, patch: Partial<T>) => {\n const next = new Map(values);\n const cur = next.get(wellId) ?? emptyEntry(wellId);\n next.set(wellId, { ...cur, ...patch });\n onChange(next);\n };\n\n const toggleSelect = (wellId: WellId) => {\n if (!onSelectionChange) return;\n const s = new Set(selection ?? []);\n if (s.has(wellId)) {\n s.delete(wellId);\n } else {\n s.add(wellId);\n }\n onSelectionChange(s);\n };\n\n const getFillDownPlan = (col: WellColumn<T>) => {\n if (!col.field) return null;\n\n const selectionActive = !!selection && selection.size > 0;\n const groupingActive = groupable && !!groupByField;\n const sourceRows = selectionActive\n ? rows.filter(({ id }) => selection.has(id))\n : groupingActive\n ? rows\n : pagedRows;\n const sourceIndex = sourceRows.findIndex(({ row }) => hasFillValue(row[col.field!]));\n if (sourceIndex < 0) return null;\n\n const source = sourceRows[sourceIndex];\n const targets = selectionActive\n ? sourceRows.filter(({ id }) => id !== source.id)\n : sourceRows.slice(sourceIndex + 1);\n\n return {\n field: col.field,\n source,\n targets,\n value: source.row[col.field],\n };\n };\n\n const fillColumnDown = (col: WellColumn<T>) => {\n const plan = getFillDownPlan(col);\n if (!plan || plan.targets.length === 0) return;\n\n const next = new Map(values);\n plan.targets.forEach(({ id }) => {\n const cur = next.get(id) ?? emptyEntry(id);\n next.set(id, { ...cur, [plan.field]: plan.value } as T);\n });\n onChange(next);\n };\n\n const renderSelectCellEditable = (\n field: WellField<T>,\n fieldKey: keyof T & string,\n value: unknown,\n wellId: WellId,\n ariaLabel: string,\n ) => (\n <Select\n value={(value as string | undefined) ?? \"\"}\n onValueChange={(v) => updateRow(wellId, { [fieldKey]: v } as Partial<T>)}\n >\n <SelectTrigger size=\"sm\" className={cn(\"h-7 w-full\", CELL_EDITOR_CLASS)} aria-label={ariaLabel}>\n <SelectValue placeholder={field.placeholder ?? \"Select…\"} />\n </SelectTrigger>\n <SelectContent>\n {(field.options ?? []).map((opt) => (\n <SelectItem key={opt.value} value={opt.value}>\n <span className=\"inline-flex items-center gap-2\">\n {opt.swatch ? (\n <span\n className=\"inline-block h-2.5 w-2.5 rounded-sm border border-foreground/20\"\n style={{ backgroundColor: opt.swatch }}\n aria-hidden\n />\n ) : null}\n {opt.label}\n </span>\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n );\n\n const renderBooleanCellEditable = (\n field: WellField<T>,\n fieldKey: keyof T & string,\n value: unknown,\n wellId: WellId,\n ariaLabel: string,\n ) => {\n const checked = !!value;\n if (field.boolStyle === \"switch\") {\n return (\n <Switch\n aria-label={ariaLabel}\n checked={checked}\n onCheckedChange={(c) => updateRow(wellId, { [fieldKey]: c } as Partial<T>)}\n />\n );\n }\n return (\n <Checkbox\n aria-label={ariaLabel}\n checked={checked}\n onCheckedChange={(c) => updateRow(wellId, { [fieldKey]: c === true } as Partial<T>)}\n />\n );\n };\n\n const renderInputCellEditable = (\n field: WellField<T>,\n fieldKey: keyof T & string,\n value: unknown,\n wellId: WellId,\n ariaLabel: string,\n ) => (\n <Input\n type={resolveInputType(field.kind)}\n step={field.kind === \"integer\" ? 1 : undefined}\n placeholder={field.placeholder}\n aria-label={ariaLabel}\n className={cn(\"h-7\", CELL_EDITOR_CLASS)}\n value={(value as string | number | undefined) ?? \"\"}\n onChange={(e) => updateRow(wellId, { [fieldKey]: parseInputValue(field.kind, e.target.value) } as Partial<T>)}\n />\n );\n\n const renderEditableCell = (field: WellField<T>, col: WellColumn<T>, wellId: WellId, row: T) => {\n const fieldKey = col.field!;\n const value = row[fieldKey];\n const ariaLabel = `${field.label} for ${wellId}`;\n\n if (field.kind === \"select\") return renderSelectCellEditable(field, fieldKey, value, wellId, ariaLabel);\n if (field.kind === \"multiselect\") {\n const current = Array.isArray(value) ? (value as string[]) : [];\n return (\n <MultiSelectCell\n ariaLabel={ariaLabel}\n value={current}\n options={field.options ?? []}\n placeholder={field.placeholder}\n onChange={(next) => updateRow(wellId, { [fieldKey]: next.length === 0 ? undefined : next } as Partial<T>)}\n />\n );\n }\n if (field.kind === \"boolean\") return renderBooleanCellEditable(field, fieldKey, value, wellId, ariaLabel);\n return renderInputCellEditable(field, fieldKey, value, wellId, ariaLabel);\n };\n\n const renderReadonlyCell = (field: WellField<T> | undefined, value: unknown) => {\n if (field?.kind === \"select\") {\n const option = (field.options ?? []).find((opt) => opt.value === value);\n if (!option) {\n return <span className=\"text-muted-foreground\">—</span>;\n }\n\n return (\n <Badge variant=\"secondary\">\n {option.swatch ? (\n <span\n className=\"size-2 rounded-sm border border-foreground/20\"\n style={{ backgroundColor: option.swatch }}\n aria-hidden\n />\n ) : null}\n {option.label}\n </Badge>\n );\n }\n\n if (field?.kind === \"multiselect\") {\n const arr = Array.isArray(value) ? (value as string[]) : [];\n if (arr.length === 0) {\n return <span className=\"text-muted-foreground\">—</span>;\n }\n return (\n <div className=\"flex flex-wrap gap-1\">\n {arr.map((v) => {\n const opt = (field.options ?? []).find((o) => o.value === v);\n return (\n <Badge key={v} variant=\"secondary\">\n {opt?.swatch ? (\n <span\n className=\"size-2 rounded-sm border border-foreground/20\"\n style={{ backgroundColor: opt.swatch }}\n aria-hidden\n />\n ) : null}\n {opt?.label ?? v}\n </Badge>\n );\n })}\n </div>\n );\n }\n\n if (field?.kind === \"boolean\") {\n return value ? (\n <Check aria-label=\"Yes\" className=\"size-4 text-foreground\" />\n ) : (\n <span className=\"text-muted-foreground\">—</span>\n );\n }\n\n if (!hasFillValue(value)) {\n return <span className=\"text-muted-foreground\">—</span>;\n }\n\n return String(value);\n };\n\n const renderCell = (col: WellColumn<T>, wellId: WellId, row: T) => {\n if (col.render) {\n return col.render({\n row,\n wellId,\n update: (patch) => updateRow(wellId, patch),\n });\n }\n if (!col.field) return null;\n\n const field = fieldByKey.get(col.field);\n const value = row[col.field];\n\n if (field?.editableInTable && field.kind !== \"custom\") {\n return renderEditableCell(field, col, wellId, row);\n }\n\n return renderReadonlyCell(field, value);\n };\n\n const renderColumnHeader = (col: WellColumn<T>) => {\n const matchingField = col.field ? fieldByKey.get(col.field) : undefined;\n const icon = col.icon ?? matchingField?.icon;\n const fillPlan = enableFillDown ? getFillDownPlan(col) : null;\n const canFillDown = !!fillPlan && fillPlan.targets.length > 0;\n const fillHint =\n selection && selection.size > 0\n ? `Fill selected ${col.header} cells from the first selected value`\n : `Fill visible ${col.header} cells downward from the first value`;\n return (\n <span className=\"flex min-w-0 items-center justify-between gap-2\">\n <span className=\"inline-flex min-w-0 items-center gap-1.5\">\n {icon ? <span className=\"inline-flex text-muted-foreground [&_svg]:size-3.5\">{icon}</span> : null}\n <span className=\"truncate\">{col.header}</span>\n </span>\n {enableFillDown && col.field ? (\n <Tooltip>\n <TooltipTrigger asChild>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-xs\"\n className=\"-mr-1 text-muted-foreground hover:text-foreground\"\n disabled={!canFillDown}\n aria-label={`Fill down ${col.header}`}\n onClick={(e) => {\n e.preventDefault();\n e.stopPropagation();\n fillColumnDown(col);\n }}\n >\n <ArrowDownToLine />\n </Button>\n </TooltipTrigger>\n <TooltipContent>{fillHint}</TooltipContent>\n </Tooltip>\n ) : null}\n </span>\n );\n };\n\n const groupableColumns = React.useMemo(() => columns.filter((col) => !!col.field), [columns]);\n const activeGroupField = groupable && groupByField ? groupByField : \"\";\n const grouped = React.useMemo(\n () => (activeGroupField ? groupRowsBy(rows, activeGroupField) : null),\n [activeGroupField, rows],\n );\n\n const totalRows = rows.length;\n const lastPage = Math.max(0, Math.ceil(totalRows / pageSize) - 1);\n const selSize = selection?.size ?? 0;\n const totalColSpan = columns.length + 1 + (onSelectionChange ? 1 : 0);\n\n const renderDataRow = (id: WellId, row: T) => {\n const isSelected = selection?.has(id);\n const extra = rowProps?.({ wellId: id, row, isSelected: !!isSelected });\n return (\n <TableRow key={id} {...extra}>\n {onSelectionChange ? (\n <TableCell className=\"w-10\">\n <Checkbox checked={!!isSelected} onCheckedChange={() => toggleSelect(id)} aria-label={`Select ${id}`} />\n </TableCell>\n ) : null}\n <TableCell className=\"font-semibold\">{id}</TableCell>\n {columns.map((col) => (\n <TableCell\n key={col.id ?? col.field ?? col.header}\n style={col.minWidth ? { minWidth: col.minWidth } : undefined}\n >\n {renderCell(col, id, row)}\n </TableCell>\n ))}\n </TableRow>\n );\n };\n\n const toggleGroup = (key: string) => {\n setCollapsedGroups((prev) => {\n const next = new Set(prev);\n if (next.has(key)) next.delete(key);\n else next.add(key);\n return next;\n });\n };\n\n const groupHeaderLabel = (() => {\n if (!activeGroupField) return \"\";\n const col = columns.find((c) => c.field === activeGroupField);\n return col?.header ?? activeGroupField;\n })();\n\n return (\n <div data-slot=\"well-manifest-table\" className={cn(\"flex flex-col gap-2\", className)}>\n <div className=\"flex flex-wrap items-center gap-2\">\n <Button variant=\"outline\" size=\"sm\" onClick={() => setShowAll((v) => !v)}>\n {showAll ? \"Hide empty wells\" : \"Show all wells\"}\n </Button>\n {filterable ? (\n <ManifestFilterPopover columns={resolvedFilterColumns} filters={filters} onFiltersChange={setFilters} />\n ) : null}\n {groupable ? (\n <div className=\"inline-flex items-center gap-1.5\">\n <Layers aria-hidden className=\"size-3.5 text-muted-foreground\" />\n <Select value={groupByField || \"__none\"} onValueChange={(v) => setGroupByField(v === \"__none\" ? \"\" : v)}>\n <SelectTrigger size=\"sm\" className=\"h-7 min-w-40\" aria-label=\"Group by\">\n <SelectValue placeholder=\"Group by…\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"__none\">No grouping</SelectItem>\n {groupableColumns.map((col) => (\n <SelectItem key={col.id ?? col.field} value={col.field ?? \"\"}>\n {col.header}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n ) : null}\n <span className=\"text-xs text-muted-foreground\">\n {totalRows} rows · {selSize} selected\n </span>\n </div>\n\n <TooltipProvider>\n <Table data-density=\"default\">\n <TableHeader>\n <TableRow>\n {onSelectionChange ? (\n <TableHead className=\"w-10 text-center\">\n <span className=\"inline-flex items-center justify-center text-muted-foreground [&_svg]:size-3.5\">\n <Check aria-hidden />\n <span className=\"sr-only\">Selected</span>\n </span>\n </TableHead>\n ) : null}\n <TableHead style={{ minWidth: 60 }}>Well</TableHead>\n {columns.map((col) => (\n <TableHead\n key={col.id ?? col.field ?? col.header}\n style={col.minWidth ? { minWidth: col.minWidth } : undefined}\n >\n {renderColumnHeader(col)}\n </TableHead>\n ))}\n </TableRow>\n </TableHeader>\n <TableBody>\n {grouped\n ? grouped.map((group) => {\n const isCollapsed = collapsedGroups.has(group.key);\n return (\n <React.Fragment key={group.key}>\n <TableRow\n className=\"cursor-pointer bg-muted/40\"\n onClick={() => toggleGroup(group.key)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n toggleGroup(group.key);\n }\n }}\n role=\"button\"\n tabIndex={0}\n aria-expanded={!isCollapsed}\n >\n <TableCell colSpan={totalColSpan} className=\"py-1.5\">\n <div className=\"flex items-center gap-2 text-xs font-medium\">\n {isCollapsed ? (\n <ChevronRight aria-hidden className=\"size-3.5 text-muted-foreground\" />\n ) : (\n <ChevronDown aria-hidden className=\"size-3.5 text-muted-foreground\" />\n )}\n <span>\n {groupHeaderLabel}: {group.key}\n </span>\n <span className=\"text-muted-foreground\">\n ({group.rows.length} {group.rows.length === 1 ? \"row\" : \"rows\"})\n </span>\n </div>\n </TableCell>\n </TableRow>\n {isCollapsed ? null : group.rows.map(({ id, row }) => renderDataRow(id, row))}\n </React.Fragment>\n );\n })\n : pagedRows.map(({ id, row }) => renderDataRow(id, row))}\n {(grouped ? grouped.length === 0 : pagedRows.length === 0) ? (\n <TableRow>\n <TableCell colSpan={totalColSpan} className=\"text-xs text-muted-foreground\">\n No rows. Paint wells on the plate.\n </TableCell>\n </TableRow>\n ) : null}\n </TableBody>\n </Table>\n </TooltipProvider>\n\n {grouped ? null : (\n <div className=\"flex items-center justify-end gap-3 text-xs text-muted-foreground\">\n <span className=\"text-muted-foreground\">Rows per page</span>\n <Select\n value={String(pageSize)}\n onValueChange={(v) => {\n setPageSize(parseInt(v, 10));\n setPage(0);\n }}\n >\n <SelectTrigger size=\"sm\" className=\"h-7 w-18\" aria-label=\"Rows per page\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {pageSizeOptions.map((s) => (\n <SelectItem key={s} value={String(s)}>\n {s}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <span>\n {totalRows === 0\n ? \"0 of 0\"\n : `${page * pageSize + 1}–${Math.min((page + 1) * pageSize, totalRows)} of ${totalRows}`}\n </span>\n <Button variant=\"outline\" size=\"sm\" disabled={page === 0} onClick={() => setPage((p) => Math.max(0, p - 1))}>\n Prev\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n disabled={page >= lastPage}\n onClick={() => setPage((p) => Math.min(lastPage, p + 1))}\n >\n Next\n </Button>\n </div>\n )}\n </div>\n );\n}\n"],"names":["MultiSelectCell","ariaLabel","value","options","placeholder","onChange","anchorRef","useComboboxAnchor","labelByValue","React","o","jsxs","Combobox","ComboboxChips","cn","CELL_EDITOR_CLASS","jsx","ComboboxValue","items","item","ComboboxChip","ComboboxChipsInput","ComboboxContent","ComboboxEmpty","ComboboxList","ComboboxItem","PAGE_SIZE_SMALL","PAGE_SIZE_MEDIUM","PAGE_SIZE_LARGE","DEFAULT_PAGE_SIZE","DEFAULT_PAGE_SIZE_OPTIONS","hasFillValue","INPUT_TYPE_BY_KIND","resolveInputType","kind","parseInputValue","raw","num","groupRowsBy","rows","field","map","entry","key","existing","inferFilterColumns","columns","col","WellManifestTable","values","fields","selection","onSelectionChange","emptyEntry","isPopulated","initialPageSize","pageSizeOptions","enableFillDown","rowProps","filterable","filterColumns","groupable","className","showAll","setShowAll","page","setPage","pageSize","setPageSize","filters","setFilters","groupByField","setGroupByField","collapsedGroups","setCollapsedGroups","fieldByKey","m","f","resolvedFilterColumns","arr","id","row","filtered","record","condition","cellRaw","cellValue","applyFilterCondition","have","r","p","a","b","pagedRows","updateRow","wellId","patch","next","cur","toggleSelect","s","getFillDownPlan","selectionActive","sourceRows","sourceIndex","source","targets","fillColumnDown","plan","renderSelectCellEditable","fieldKey","Select","v","SelectTrigger","SelectValue","SelectContent","opt","SelectItem","renderBooleanCellEditable","checked","Switch","c","Checkbox","renderInputCellEditable","Input","e","renderEditableCell","current","renderReadonlyCell","option","Badge","Check","renderCell","renderColumnHeader","matchingField","icon","fillPlan","canFillDown","fillHint","Tooltip","TooltipTrigger","Button","ArrowDownToLine","TooltipContent","groupableColumns","activeGroupField","grouped","totalRows","lastPage","selSize","totalColSpan","renderDataRow","isSelected","extra","TableRow","TableCell","toggleGroup","prev","groupHeaderLabel","ManifestFilterPopover","Layers","TooltipProvider","Table","TableHeader","TableHead","TableBody","group","isCollapsed","ChevronRight","ChevronDown"],"mappings":"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"}
1
+ {"version":3,"file":"WellManifestTable.js","sources":["../../../../src/components/composed/PlateMapEditor/WellManifestTable.tsx"],"sourcesContent":["import { ArrowDownToLine, Check, ChevronDown, ChevronRight, Layers } from \"lucide-react\";\nimport * as React from \"react\";\n\nimport { ManifestFilterPopover } from \"./ManifestFilterPopover\";\n\nimport type { WellColumn, WellField, WellId, WellManifestTableLabels, WellRecord, WellSelectOption } from \"./types\";\nimport type { FilterColumnConfig, FilterCondition } from \"@/components/ui/data-table/data-table\";\n\nimport { Badge } from \"@/components/ui/badge\";\nimport { Button } from \"@/components/ui/button\";\nimport { Checkbox } from \"@/components/ui/checkbox\";\nimport {\n Combobox,\n ComboboxChip,\n ComboboxChips,\n ComboboxChipsInput,\n ComboboxContent,\n ComboboxEmpty,\n ComboboxItem,\n ComboboxList,\n ComboboxValue,\n useComboboxAnchor,\n} from \"@/components/ui/combobox\";\nimport { applyFilterCondition } from \"@/components/ui/data-table/data-table\";\nimport { Input } from \"@/components/ui/input\";\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from \"@/components/ui/select\";\nimport { Switch } from \"@/components/ui/switch\";\nimport { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from \"@/components/ui/table\";\nimport { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from \"@/components/ui/tooltip\";\nimport { cn } from \"@/lib/utils\";\n\nfunction MultiSelectCell({\n ariaLabel,\n value,\n options,\n placeholder,\n onChange,\n}: {\n ariaLabel: string;\n value: string[];\n options: WellSelectOption[];\n placeholder?: string;\n onChange: (next: string[]) => void;\n}) {\n const anchorRef = useComboboxAnchor();\n const labelByValue = React.useMemo(() => {\n const m = new Map<string, string>();\n options.forEach((o) => m.set(o.value, o.label));\n return m;\n }, [options]);\n\n return (\n <Combobox multiple items={options.map((o) => o.value)} value={value} onValueChange={onChange}>\n <ComboboxChips ref={anchorRef} className={cn(\"min-h-7 w-full py-0.5\", CELL_EDITOR_CLASS)}>\n <ComboboxValue>\n {(items: string[]) =>\n items.map((item) => <ComboboxChip key={item}>{labelByValue.get(item) ?? item}</ComboboxChip>)\n }\n </ComboboxValue>\n <ComboboxChipsInput aria-label={ariaLabel} placeholder={placeholder ?? \"Select…\"} />\n </ComboboxChips>\n <ComboboxContent anchor={anchorRef}>\n <ComboboxEmpty>No options.</ComboboxEmpty>\n <ComboboxList aria-label={ariaLabel}>\n {(item: string) => (\n <ComboboxItem key={item} value={item}>\n {labelByValue.get(item) ?? item}\n </ComboboxItem>\n )}\n </ComboboxList>\n </ComboboxContent>\n </Combobox>\n );\n}\n\n/**\n * Cell editors render borderless by default so the table reads flat. The\n * underlying primitives keep their `focus-visible` / `focus-within` rings, so\n * an outline only appears while the user is actively editing the cell.\n */\nconst CELL_EDITOR_CLASS = \"border-transparent shadow-none hover:border-input/40\";\n\nconst PAGE_SIZE_SMALL = 25;\nconst PAGE_SIZE_MEDIUM = 50;\nconst PAGE_SIZE_LARGE = 100;\nconst DEFAULT_PAGE_SIZE = PAGE_SIZE_SMALL;\nconst DEFAULT_PAGE_SIZE_OPTIONS: number[] = [PAGE_SIZE_SMALL, PAGE_SIZE_MEDIUM, PAGE_SIZE_LARGE];\n\nfunction hasFillValue(value: unknown): boolean {\n return value !== undefined && value !== null && value !== \"\";\n}\n\nconst INPUT_TYPE_BY_KIND: Record<string, string> = {\n number: \"number\",\n integer: \"number\",\n date: \"date\",\n datetime: \"datetime-local\",\n time: \"time\",\n};\n\nfunction resolveInputType(kind: string): string {\n return INPUT_TYPE_BY_KIND[kind] ?? \"text\";\n}\n\nfunction parseInputValue(kind: string, raw: string): unknown {\n if (raw === \"\") return undefined;\n if (kind === \"number\") {\n const num = parseFloat(raw);\n return Number.isFinite(num) ? num : raw;\n }\n if (kind === \"integer\") {\n const num = parseInt(raw, 10);\n return Number.isFinite(num) ? num : raw;\n }\n return raw;\n}\n\nexport interface WellManifestTableRowContext<T extends WellRecord = WellRecord> {\n wellId: WellId;\n row: T;\n isSelected: boolean;\n}\n\nexport interface WellManifestTableProps<T extends WellRecord = WellRecord> {\n values: Map<WellId, T>;\n columns: WellColumn<T>[];\n /**\n * Field schema. If a column has `field` matching a `select`-kind field, a\n * Select cell renders automatically with that field's options.\n */\n fields?: WellField<T>[];\n selection?: Set<WellId>;\n onSelectionChange?: (next: Set<WellId>) => void;\n onChange: (next: Map<WellId, T>) => void;\n /** Builds an empty record for a freshly-created row. */\n emptyEntry: (id: WellId) => T;\n /** Filter that controls which empty rows surface. Defaults to `false`. */\n isPopulated?: (row: T) => boolean;\n pageSize?: number;\n pageSizeOptions?: number[];\n /** Adds a column header action that copies the first non-empty value downward. */\n enableFillDown?: boolean;\n /**\n * Extra props spread onto each `<tr>` — typically used to attach a DnD\n * library's `setNodeRef`, listeners, and data attributes so rows can act as\n * drag sources. The kit stays DnD-library-agnostic.\n */\n rowProps?: (ctx: WellManifestTableRowContext<T>) => React.ComponentProps<\"tr\"> | undefined;\n /** Enables an inline filter popover above the table. Defaults to false. */\n filterable?: boolean;\n /**\n * Optional override of filterable column configs. When omitted, every column\n * with a `field` becomes filterable using the default operator set from the\n * shared data-table filter system.\n */\n filterColumns?: FilterColumnConfig[];\n /** Enables an inline group-by selector. Defaults to false. */\n groupable?: boolean;\n /** Overrides any user-facing string in the table. Omitted keys use English defaults. */\n labels?: WellManifestTableLabels;\n /** Field grouped by on first render. Requires `groupable`. */\n defaultGroupBy?: string;\n className?: string;\n}\n\nconst MANIFEST_LABEL_DEFAULTS = {\n showAllWells: \"Show all wells\",\n hideEmptyWells: \"Hide empty wells\",\n groupBy: \"Group by\",\n groupByPlaceholder: \"Group by…\",\n noGrouping: \"No grouping\",\n selectedColumn: \"Selected\",\n wellColumn: \"Well\",\n emptyRows: \"No rows. Paint wells on the plate.\",\n rowsPerPage: \"Rows per page\",\n previousPage: \"Prev\",\n nextPage: \"Next\",\n blankGroup: \"(blank)\",\n filter: \"Filter\",\n filterValuePlaceholder: \"Value…\",\n clearFilters: \"Clear all\",\n rowSummary: (total: number, selected: number) => `${total} rows · ${selected} selected`,\n groupRowCount: (count: number) => `(${count} ${count === 1 ? \"row\" : \"rows\"})`,\n pageRange: (from: number, to: number, total: number) => (total === 0 ? \"0 of 0\" : `${from}–${to} of ${total}`),\n} satisfies Required<WellManifestTableLabels>;\n\n/** Merges overrides over defaults, ignoring keys explicitly set to `undefined`. */\nfunction resolveLabels<D extends object>(defaults: D, overrides: object | undefined): D {\n if (!overrides) return defaults;\n const merged = { ...defaults };\n for (const [key, value] of Object.entries(overrides)) {\n if (value !== undefined) (merged as Record<string, unknown>)[key] = value;\n }\n return merged;\n}\n\ninterface GroupedRow<T> {\n key: string;\n rows: Array<{ id: WellId; row: T }>;\n}\n\nfunction groupRowsBy<T extends WellRecord>(\n rows: Array<{ id: WellId; row: T }>,\n field: string,\n blankLabel: string,\n): GroupedRow<T>[] {\n const map = new Map<string, GroupedRow<T>>();\n for (const entry of rows) {\n const raw = (entry.row as Record<string, unknown>)[field];\n const key = raw === undefined || raw === null || raw === \"\" ? blankLabel : String(raw);\n const existing = map.get(key);\n if (existing) existing.rows.push(entry);\n else map.set(key, { key, rows: [entry] });\n }\n return [...map.values()];\n}\n\nfunction inferFilterColumns<T extends WellRecord>(columns: WellColumn<T>[]): FilterColumnConfig[] {\n return columns.filter((col) => !!col.field).map((col) => ({ columnId: col.field as string, label: col.header }));\n}\n\nexport function WellManifestTable<T extends WellRecord = WellRecord>({\n values,\n columns,\n fields,\n selection,\n onSelectionChange,\n onChange,\n emptyEntry,\n isPopulated,\n pageSize: initialPageSize = DEFAULT_PAGE_SIZE,\n pageSizeOptions = DEFAULT_PAGE_SIZE_OPTIONS,\n enableFillDown = true,\n rowProps,\n filterable = false,\n filterColumns,\n groupable = false,\n defaultGroupBy = \"\",\n labels,\n className,\n}: WellManifestTableProps<T>) {\n // Plain spread would let an explicit `undefined` clobber the default —\n // exactly what `labels={{ apply: t(\"apply\") }}` produces when the lookup\n // misses, blanking the UI instead of falling back to English.\n const t = React.useMemo(() => resolveLabels(MANIFEST_LABEL_DEFAULTS, labels), [labels]);\n const [showAll, setShowAll] = React.useState(false);\n const [page, setPage] = React.useState(0);\n const [pageSize, setPageSize] = React.useState(initialPageSize);\n const [filters, setFilters] = React.useState<FilterCondition[]>([]);\n const [groupByField, setGroupByField] = React.useState<string>(defaultGroupBy);\n const [collapsedGroups, setCollapsedGroups] = React.useState<Set<string>>(new Set());\n\n React.useEffect(() => {\n setPage(0);\n }, [showAll]);\n\n const fieldByKey = React.useMemo(() => {\n const m = new Map<string, WellField<T>>();\n (fields ?? []).forEach((f) => m.set(f.key, f));\n return m;\n }, [fields]);\n\n const resolvedFilterColumns = React.useMemo<FilterColumnConfig[]>(\n () => filterColumns ?? inferFilterColumns(columns),\n [columns, filterColumns],\n );\n\n const rows = React.useMemo(() => {\n const arr = [...values.entries()].map(([id, row]) => ({\n id,\n row,\n }));\n let filtered = arr;\n if (!showAll && isPopulated) {\n filtered = arr.filter((r) => isPopulated(r.row));\n }\n if (filterable && filters.length > 0) {\n filtered = filtered.filter((entry) => {\n const record = entry.row as Record<string, unknown>;\n return filters.every((condition) => {\n const cellRaw = record[condition.columnId];\n const cellValue = cellRaw === undefined || cellRaw === null ? \"\" : String(cellRaw);\n return applyFilterCondition(cellValue, condition.operator, condition.value);\n });\n });\n }\n if (selection && selection.size > 0) {\n const have = new Set(filtered.map((r) => r.id));\n selection.forEach((p) => {\n if (!have.has(p) && !values.has(p)) {\n filtered = [...filtered, { id: p, row: emptyEntry(p) }];\n }\n });\n }\n return filtered.sort((a, b) => a.id.localeCompare(b.id));\n }, [values, showAll, isPopulated, selection, emptyEntry, filterable, filters]);\n\n React.useEffect(() => {\n setPage(0);\n }, [filters]);\n\n const pagedRows = React.useMemo(\n () => rows.slice(page * pageSize, page * pageSize + pageSize),\n [rows, page, pageSize],\n );\n\n const updateRow = (wellId: WellId, patch: Partial<T>) => {\n const next = new Map(values);\n const cur = next.get(wellId) ?? emptyEntry(wellId);\n next.set(wellId, { ...cur, ...patch });\n onChange(next);\n };\n\n const toggleSelect = (wellId: WellId) => {\n if (!onSelectionChange) return;\n const s = new Set(selection ?? []);\n if (s.has(wellId)) {\n s.delete(wellId);\n } else {\n s.add(wellId);\n }\n onSelectionChange(s);\n };\n\n const getFillDownPlan = (col: WellColumn<T>) => {\n if (!col.field) return null;\n\n const selectionActive = !!selection && selection.size > 0;\n const groupingActive = groupable && !!groupByField;\n const sourceRows = selectionActive ? rows.filter(({ id }) => selection.has(id)) : groupingActive ? rows : pagedRows;\n const sourceIndex = sourceRows.findIndex(({ row }) => hasFillValue(row[col.field!]));\n if (sourceIndex < 0) return null;\n\n const source = sourceRows[sourceIndex];\n const targets = selectionActive\n ? sourceRows.filter(({ id }) => id !== source.id)\n : sourceRows.slice(sourceIndex + 1);\n\n return {\n field: col.field,\n source,\n targets,\n value: source.row[col.field],\n };\n };\n\n const fillColumnDown = (col: WellColumn<T>) => {\n const plan = getFillDownPlan(col);\n if (!plan || plan.targets.length === 0) return;\n\n const next = new Map(values);\n plan.targets.forEach(({ id }) => {\n const cur = next.get(id) ?? emptyEntry(id);\n next.set(id, { ...cur, [plan.field]: plan.value } as T);\n });\n onChange(next);\n };\n\n const renderSelectCellEditable = (\n field: WellField<T>,\n fieldKey: keyof T & string,\n value: unknown,\n wellId: WellId,\n ariaLabel: string,\n ) => (\n <Select\n value={(value as string | undefined) ?? \"\"}\n onValueChange={(v) => updateRow(wellId, { [fieldKey]: v } as Partial<T>)}\n >\n <SelectTrigger size=\"sm\" className={cn(\"h-7 w-full\", CELL_EDITOR_CLASS)} aria-label={ariaLabel}>\n <SelectValue placeholder={field.placeholder ?? \"Select…\"} />\n </SelectTrigger>\n <SelectContent>\n {(field.options ?? []).map((opt) => (\n <SelectItem key={opt.value} value={opt.value}>\n <span className=\"inline-flex items-center gap-2\">\n {opt.swatch ? (\n <span\n className=\"inline-block h-2.5 w-2.5 rounded-sm border border-foreground/20\"\n style={{ backgroundColor: opt.swatch }}\n aria-hidden\n />\n ) : null}\n {opt.label}\n </span>\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n );\n\n const renderBooleanCellEditable = (\n field: WellField<T>,\n fieldKey: keyof T & string,\n value: unknown,\n wellId: WellId,\n ariaLabel: string,\n ) => {\n const checked = !!value;\n if (field.boolStyle === \"switch\") {\n return (\n <Switch\n aria-label={ariaLabel}\n checked={checked}\n onCheckedChange={(c) => updateRow(wellId, { [fieldKey]: c } as Partial<T>)}\n />\n );\n }\n return (\n <Checkbox\n aria-label={ariaLabel}\n checked={checked}\n onCheckedChange={(c) => updateRow(wellId, { [fieldKey]: c === true } as Partial<T>)}\n />\n );\n };\n\n const renderInputCellEditable = (\n field: WellField<T>,\n fieldKey: keyof T & string,\n value: unknown,\n wellId: WellId,\n ariaLabel: string,\n ) => (\n <Input\n type={resolveInputType(field.kind)}\n step={field.kind === \"integer\" ? 1 : undefined}\n placeholder={field.placeholder}\n aria-label={ariaLabel}\n className={cn(\"h-7\", CELL_EDITOR_CLASS)}\n value={(value as string | number | undefined) ?? \"\"}\n onChange={(e) => updateRow(wellId, { [fieldKey]: parseInputValue(field.kind, e.target.value) } as Partial<T>)}\n />\n );\n\n const renderEditableCell = (field: WellField<T>, col: WellColumn<T>, wellId: WellId, row: T) => {\n const fieldKey = col.field!;\n const value = row[fieldKey];\n const ariaLabel = `${field.label} for ${wellId}`;\n\n if (field.kind === \"select\") return renderSelectCellEditable(field, fieldKey, value, wellId, ariaLabel);\n if (field.kind === \"multiselect\") {\n const current = Array.isArray(value) ? (value as string[]) : [];\n return (\n <MultiSelectCell\n ariaLabel={ariaLabel}\n value={current}\n options={field.options ?? []}\n placeholder={field.placeholder}\n onChange={(next) => updateRow(wellId, { [fieldKey]: next.length === 0 ? undefined : next } as Partial<T>)}\n />\n );\n }\n if (field.kind === \"boolean\") return renderBooleanCellEditable(field, fieldKey, value, wellId, ariaLabel);\n return renderInputCellEditable(field, fieldKey, value, wellId, ariaLabel);\n };\n\n const renderReadonlyCell = (field: WellField<T> | undefined, value: unknown) => {\n if (field?.kind === \"select\") {\n const option = (field.options ?? []).find((opt) => opt.value === value);\n if (!option) {\n return <span className=\"text-muted-foreground\">—</span>;\n }\n\n return (\n <Badge variant=\"secondary\">\n {option.swatch ? (\n <span\n className=\"size-2 rounded-sm border border-foreground/20\"\n style={{ backgroundColor: option.swatch }}\n aria-hidden\n />\n ) : null}\n {option.label}\n </Badge>\n );\n }\n\n if (field?.kind === \"multiselect\") {\n const arr = Array.isArray(value) ? (value as string[]) : [];\n if (arr.length === 0) {\n return <span className=\"text-muted-foreground\">—</span>;\n }\n return (\n <div className=\"flex flex-wrap gap-1\">\n {arr.map((v) => {\n const opt = (field.options ?? []).find((o) => o.value === v);\n return (\n <Badge key={v} variant=\"secondary\">\n {opt?.swatch ? (\n <span\n className=\"size-2 rounded-sm border border-foreground/20\"\n style={{ backgroundColor: opt.swatch }}\n aria-hidden\n />\n ) : null}\n {opt?.label ?? v}\n </Badge>\n );\n })}\n </div>\n );\n }\n\n if (field?.kind === \"boolean\") {\n return value ? (\n <Check aria-label=\"Yes\" className=\"size-4 text-foreground\" />\n ) : (\n <span className=\"text-muted-foreground\">—</span>\n );\n }\n\n if (!hasFillValue(value)) {\n return <span className=\"text-muted-foreground\">—</span>;\n }\n\n return String(value);\n };\n\n const renderCell = (col: WellColumn<T>, wellId: WellId, row: T) => {\n if (col.render) {\n return col.render({\n row,\n wellId,\n update: (patch) => updateRow(wellId, patch),\n });\n }\n if (!col.field) return null;\n\n const field = fieldByKey.get(col.field);\n const value = row[col.field];\n\n if (field?.editableInTable && field.kind !== \"custom\") {\n return renderEditableCell(field, col, wellId, row);\n }\n\n return renderReadonlyCell(field, value);\n };\n\n const renderColumnHeader = (col: WellColumn<T>) => {\n const matchingField = col.field ? fieldByKey.get(col.field) : undefined;\n const icon = col.icon ?? matchingField?.icon;\n const fillPlan = enableFillDown ? getFillDownPlan(col) : null;\n const canFillDown = !!fillPlan && fillPlan.targets.length > 0;\n const fillHint =\n selection && selection.size > 0\n ? `Fill selected ${col.header} cells from the first selected value`\n : `Fill visible ${col.header} cells downward from the first value`;\n return (\n <span className=\"flex min-w-0 items-center justify-between gap-2\">\n <span className=\"inline-flex min-w-0 items-center gap-1.5\">\n {icon ? <span className=\"inline-flex text-muted-foreground [&_svg]:size-3.5\">{icon}</span> : null}\n <span className=\"truncate\">{col.header}</span>\n </span>\n {enableFillDown && col.field ? (\n <Tooltip>\n <TooltipTrigger asChild>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-xs\"\n className=\"-mr-1 text-muted-foreground hover:text-foreground\"\n disabled={!canFillDown}\n aria-label={`Fill down ${col.header}`}\n onClick={(e) => {\n e.preventDefault();\n e.stopPropagation();\n fillColumnDown(col);\n }}\n >\n <ArrowDownToLine />\n </Button>\n </TooltipTrigger>\n <TooltipContent>{fillHint}</TooltipContent>\n </Tooltip>\n ) : null}\n </span>\n );\n };\n\n const groupableColumns = React.useMemo(() => columns.filter((col) => !!col.field), [columns]);\n const activeGroupField = groupable && groupByField ? groupByField : \"\";\n const grouped = React.useMemo(\n () => (activeGroupField ? groupRowsBy(rows, activeGroupField, t.blankGroup) : null),\n [activeGroupField, rows, t.blankGroup],\n );\n\n const totalRows = rows.length;\n const lastPage = Math.max(0, Math.ceil(totalRows / pageSize) - 1);\n const selSize = selection?.size ?? 0;\n const totalColSpan = columns.length + 1 + (onSelectionChange ? 1 : 0);\n\n const renderDataRow = (id: WellId, row: T) => {\n const isSelected = selection?.has(id);\n const extra = rowProps?.({ wellId: id, row, isSelected: !!isSelected });\n return (\n <TableRow key={id} {...extra}>\n {onSelectionChange ? (\n <TableCell className=\"w-10\">\n <Checkbox checked={!!isSelected} onCheckedChange={() => toggleSelect(id)} aria-label={`Select ${id}`} />\n </TableCell>\n ) : null}\n <TableCell className=\"font-semibold\">{id}</TableCell>\n {columns.map((col) => (\n <TableCell\n key={col.id ?? col.field ?? col.header}\n style={col.minWidth ? { minWidth: col.minWidth } : undefined}\n >\n {renderCell(col, id, row)}\n </TableCell>\n ))}\n </TableRow>\n );\n };\n\n const toggleGroup = (key: string) => {\n setCollapsedGroups((prev) => {\n const next = new Set(prev);\n if (next.has(key)) next.delete(key);\n else next.add(key);\n return next;\n });\n };\n\n const groupHeaderLabel = (() => {\n if (!activeGroupField) return \"\";\n const col = columns.find((c) => c.field === activeGroupField);\n return col?.header ?? activeGroupField;\n })();\n\n return (\n <div data-slot=\"well-manifest-table\" className={cn(\"flex flex-col gap-2\", className)}>\n <div className=\"flex flex-wrap items-center gap-2\">\n <Button variant=\"outline\" size=\"sm\" onClick={() => setShowAll((v) => !v)}>\n {showAll ? t.hideEmptyWells : t.showAllWells}\n </Button>\n {filterable ? (\n <ManifestFilterPopover\n columns={resolvedFilterColumns}\n filters={filters}\n onFiltersChange={setFilters}\n triggerLabel={t.filter}\n valuePlaceholder={t.filterValuePlaceholder}\n clearAllLabel={t.clearFilters}\n />\n ) : null}\n {groupable ? (\n <div className=\"inline-flex items-center gap-1.5\">\n <Layers aria-hidden className=\"size-3.5 text-muted-foreground\" />\n <Select value={groupByField || \"__none\"} onValueChange={(v) => setGroupByField(v === \"__none\" ? \"\" : v)}>\n <SelectTrigger size=\"sm\" className=\"h-7 min-w-40\" aria-label={t.groupBy}>\n <SelectValue placeholder={t.groupByPlaceholder} />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"__none\">{t.noGrouping}</SelectItem>\n {groupableColumns.map((col) => (\n <SelectItem key={col.id ?? col.field} value={col.field ?? \"\"}>\n {col.header}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n ) : null}\n <span className=\"text-xs text-muted-foreground\">{t.rowSummary(totalRows, selSize)}</span>\n </div>\n\n <TooltipProvider>\n <Table data-density=\"default\">\n <TableHeader>\n <TableRow>\n {onSelectionChange ? (\n <TableHead className=\"w-10 text-center\">\n <span className=\"inline-flex items-center justify-center text-muted-foreground [&_svg]:size-3.5\">\n <Check aria-hidden />\n <span className=\"sr-only\">{t.selectedColumn}</span>\n </span>\n </TableHead>\n ) : null}\n <TableHead style={{ minWidth: 60 }}>{t.wellColumn}</TableHead>\n {columns.map((col) => (\n <TableHead\n key={col.id ?? col.field ?? col.header}\n style={col.minWidth ? { minWidth: col.minWidth } : undefined}\n >\n {renderColumnHeader(col)}\n </TableHead>\n ))}\n </TableRow>\n </TableHeader>\n <TableBody>\n {grouped\n ? grouped.map((group) => {\n const isCollapsed = collapsedGroups.has(group.key);\n return (\n <React.Fragment key={group.key}>\n <TableRow\n className=\"cursor-pointer bg-muted/40\"\n onClick={() => toggleGroup(group.key)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n toggleGroup(group.key);\n }\n }}\n role=\"button\"\n tabIndex={0}\n aria-expanded={!isCollapsed}\n >\n <TableCell colSpan={totalColSpan} className=\"py-1.5\">\n <div className=\"flex items-center gap-2 text-xs font-medium\">\n {isCollapsed ? (\n <ChevronRight aria-hidden className=\"size-3.5 text-muted-foreground\" />\n ) : (\n <ChevronDown aria-hidden className=\"size-3.5 text-muted-foreground\" />\n )}\n <span>\n {groupHeaderLabel}: {group.key}\n </span>\n <span className=\"text-muted-foreground\">{t.groupRowCount(group.rows.length)}</span>\n </div>\n </TableCell>\n </TableRow>\n {isCollapsed ? null : group.rows.map(({ id, row }) => renderDataRow(id, row))}\n </React.Fragment>\n );\n })\n : pagedRows.map(({ id, row }) => renderDataRow(id, row))}\n {(grouped ? grouped.length === 0 : pagedRows.length === 0) ? (\n <TableRow>\n <TableCell colSpan={totalColSpan} className=\"text-xs text-muted-foreground\">\n {t.emptyRows}\n </TableCell>\n </TableRow>\n ) : null}\n </TableBody>\n </Table>\n </TooltipProvider>\n\n {grouped ? null : (\n <div className=\"flex items-center justify-end gap-3 text-xs text-muted-foreground\">\n <span className=\"text-muted-foreground\">{t.rowsPerPage}</span>\n <Select\n value={String(pageSize)}\n onValueChange={(v) => {\n setPageSize(parseInt(v, 10));\n setPage(0);\n }}\n >\n <SelectTrigger size=\"sm\" className=\"h-7 w-18\" aria-label={t.rowsPerPage}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {pageSizeOptions.map((s) => (\n <SelectItem key={s} value={String(s)}>\n {s}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <span>\n {t.pageRange(\n totalRows === 0 ? 0 : page * pageSize + 1,\n Math.min((page + 1) * pageSize, totalRows),\n totalRows,\n )}\n </span>\n <Button variant=\"outline\" size=\"sm\" disabled={page === 0} onClick={() => setPage((p) => Math.max(0, p - 1))}>\n {t.previousPage}\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n disabled={page >= lastPage}\n onClick={() => setPage((p) => Math.min(lastPage, p + 1))}\n >\n {t.nextPage}\n </Button>\n </div>\n )}\n </div>\n );\n}\n"],"names":["MultiSelectCell","ariaLabel","value","options","placeholder","onChange","anchorRef","useComboboxAnchor","labelByValue","React","m","o","jsxs","Combobox","ComboboxChips","cn","CELL_EDITOR_CLASS","jsx","ComboboxValue","items","item","ComboboxChip","ComboboxChipsInput","ComboboxContent","ComboboxEmpty","ComboboxList","ComboboxItem","PAGE_SIZE_SMALL","PAGE_SIZE_MEDIUM","PAGE_SIZE_LARGE","DEFAULT_PAGE_SIZE","DEFAULT_PAGE_SIZE_OPTIONS","hasFillValue","INPUT_TYPE_BY_KIND","resolveInputType","kind","parseInputValue","raw","num","MANIFEST_LABEL_DEFAULTS","total","selected","count","from","to","resolveLabels","defaults","overrides","merged","key","groupRowsBy","rows","field","blankLabel","map","entry","existing","inferFilterColumns","columns","col","WellManifestTable","values","fields","selection","onSelectionChange","emptyEntry","isPopulated","initialPageSize","pageSizeOptions","enableFillDown","rowProps","filterable","filterColumns","groupable","defaultGroupBy","labels","className","t","showAll","setShowAll","page","setPage","pageSize","setPageSize","filters","setFilters","groupByField","setGroupByField","collapsedGroups","setCollapsedGroups","fieldByKey","f","resolvedFilterColumns","arr","id","row","filtered","r","record","condition","cellRaw","cellValue","applyFilterCondition","have","p","a","b","pagedRows","updateRow","wellId","patch","next","cur","toggleSelect","s","getFillDownPlan","selectionActive","sourceRows","sourceIndex","source","targets","fillColumnDown","plan","renderSelectCellEditable","fieldKey","Select","v","SelectTrigger","SelectValue","SelectContent","opt","SelectItem","renderBooleanCellEditable","checked","Switch","c","Checkbox","renderInputCellEditable","Input","e","renderEditableCell","current","renderReadonlyCell","option","Badge","Check","renderCell","renderColumnHeader","matchingField","icon","fillPlan","canFillDown","fillHint","Tooltip","TooltipTrigger","Button","ArrowDownToLine","TooltipContent","groupableColumns","activeGroupField","grouped","totalRows","lastPage","selSize","totalColSpan","renderDataRow","isSelected","extra","TableRow","TableCell","toggleGroup","prev","groupHeaderLabel","ManifestFilterPopover","Layers","TooltipProvider","Table","TableHeader","TableHead","TableBody","group","isCollapsed","ChevronRight","ChevronDown"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const n=require("react/jsx-runtime"),w=require("react"),k=require("../../../ui/button.cjs"),S=require("../../../ui/checkbox.cjs"),i=require("../../../ui/combobox.cjs"),q=require("../../../ui/input.cjs"),I=require("../../../ui/label.cjs"),x=require("../../../ui/select.cjs"),F=require("../../../ui/switch.cjs"),M=require("../../../lib/utils.cjs");function $(o){const l=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(o){for(const r in o)if(r!=="default"){const c=Object.getOwnPropertyDescriptor(o,r);Object.defineProperty(l,r,c.get?c:{enumerable:!0,get:()=>o[r]})}}return l.default=o,Object.freeze(l)}const O=$(w);function T({id:o,value:l,options:r,placeholder:c,onChange:j}){const b=i.useComboboxAnchor(),p=O.useMemo(()=>{const a=new Map;return r.forEach(u=>a.set(u.value,u.label)),a},[r]);return n.jsxs(i.Combobox,{multiple:!0,items:r.map(a=>a.value),value:l,onValueChange:j,children:[n.jsxs(i.ComboboxChips,{ref:b,className:"min-h-9 w-full",children:[n.jsx(i.ComboboxValue,{children:a=>a.map(u=>n.jsx(i.ComboboxChip,{children:p.get(u)??u},u))}),n.jsx(i.ComboboxChipsInput,{id:o,placeholder:c??"Select…"})]}),n.jsxs(i.ComboboxContent,{anchor:b,children:[n.jsx(i.ComboboxEmpty,{children:"No options."}),n.jsx(i.ComboboxList,{children:a=>n.jsx(i.ComboboxItem,{value:a,children:n.jsxs("span",{className:"inline-flex items-center gap-2",children:[(()=>{const u=r.find(g=>g.value===a);return u?.swatch?n.jsx("span",{className:"inline-block h-2.5 w-2.5 rounded-sm border border-foreground/20",style:{backgroundColor:u.swatch},"aria-hidden":!0}):null})(),p.get(a)??a]})},a)})]})]})}const V={number:"number",integer:"number",date:"date",datetime:"datetime-local",time:"time"};function A(o){return V[o]??"text"}function B(o,l){if(l!==""){if(o==="number"){const r=parseFloat(l);return Number.isFinite(r)?r:l}if(o==="integer"){const r=parseInt(l,10);return Number.isFinite(r)?r:l}return l}}function P({fields:o,value:l,onChange:r,selectionSize:c,onApply:j,onClear:b,applyLabel:p="Apply",clearLabel:a="Clear wells",extras:u,className:g}){const d=(e,t)=>{r({...l,[e]:t})},m=e=>n.jsxs(I.Label,{htmlFor:`field-${e.key}`,className:"gap-1.5",children:[e.icon?n.jsx("span",{className:"inline-flex text-muted-foreground [&_svg]:size-3.5",children:e.icon}):null,e.label]}),y=(e,t)=>n.jsxs("div",{className:"flex flex-col gap-1.5",children:[m(e),e.render({value:t,onChange:s=>d(e.key,s),selectionSize:c})]},e.key),C=(e,t)=>n.jsxs("div",{className:"flex flex-col gap-1.5",children:[m(e),n.jsxs(x.Select,{value:t??"",onValueChange:s=>d(e.key,s),children:[n.jsx(x.SelectTrigger,{id:`field-${e.key}`,size:"sm",className:"w-full",children:n.jsx(x.SelectValue,{placeholder:e.placeholder??"Select…"})}),n.jsx(x.SelectContent,{children:(e.options??[]).map(s=>n.jsx(x.SelectItem,{value:s.value,children:n.jsxs("span",{className:"inline-flex items-center gap-2",children:[s.swatch?n.jsx("span",{className:"inline-block h-2.5 w-2.5 rounded-sm border border-foreground/20",style:{backgroundColor:s.swatch},"aria-hidden":!0}):null,s.label]})},s.value))})]})]},e.key),v=(e,t)=>{const s=Array.isArray(t)?t:[];return n.jsxs("div",{className:"flex flex-col gap-1.5",children:[m(e),n.jsx(T,{id:`field-${e.key}`,value:s,options:e.options??[],placeholder:e.placeholder,onChange:h=>d(e.key,h.length===0?void 0:h)})]},e.key)},N=(e,t)=>{const s=!!t;return e.boolStyle==="switch"?n.jsxs("div",{className:"flex items-center justify-between gap-2",children:[m(e),n.jsx(F.Switch,{id:`field-${e.key}`,checked:s,onCheckedChange:h=>d(e.key,h)})]},e.key):n.jsxs("div",{className:"flex items-center gap-2",children:[n.jsx(S.Checkbox,{id:`field-${e.key}`,checked:s,onCheckedChange:h=>d(e.key,h===!0)}),m(e)]},e.key)},f=(e,t)=>n.jsxs("div",{className:"flex flex-col gap-1.5",children:[m(e),n.jsx(q.Input,{id:`field-${e.key}`,type:A(e.kind),step:e.kind==="integer"?1:void 0,placeholder:e.placeholder,value:t??"",onChange:s=>d(e.key,B(e.kind,s.target.value))})]},e.key),_=e=>{const t=l[e.key];return e.render?y(e,t):e.kind==="select"?C(e,t):e.kind==="multiselect"?v(e,t):e.kind==="boolean"?N(e,t):f(e,t)};return n.jsxs("div",{"data-slot":"well-metadata-form",className:M.cn("flex flex-col gap-3",g),children:[n.jsx("div",{className:"text-sm font-medium",children:c>0?`Apply to ${c} well${c===1?"":"s"}`:"Select wells to edit"}),o.map(_),u,n.jsxs("div",{className:"mt-auto flex gap-2 pt-1",children:[n.jsx(k.Button,{variant:"default",size:"sm",disabled:c===0,onClick:j,children:p}),n.jsx(k.Button,{variant:"outline",size:"sm",disabled:c===0,onClick:b,children:a})]})]})}exports.WellMetadataForm=P;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const n=require("react/jsx-runtime"),q=require("react"),k=require("../../../ui/button.cjs"),I=require("../../../ui/checkbox.cjs"),i=require("../../../ui/combobox.cjs"),F=require("../../../ui/input.cjs"),M=require("../../../ui/label.cjs"),x=require("../../../ui/select.cjs"),$=require("../../../ui/switch.cjs"),O=require("../../../lib/utils.cjs");function T(o){const l=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(o){for(const r in o)if(r!=="default"){const u=Object.getOwnPropertyDescriptor(o,r);Object.defineProperty(l,r,u.get?u:{enumerable:!0,get:()=>o[r]})}}return l.default=o,Object.freeze(l)}const V=T(q);function A({id:o,value:l,options:r,placeholder:u,onChange:j}){const b=i.useComboboxAnchor(),p=V.useMemo(()=>{const a=new Map;return r.forEach(c=>a.set(c.value,c.label)),a},[r]);return n.jsxs(i.Combobox,{multiple:!0,items:r.map(a=>a.value),value:l,onValueChange:j,children:[n.jsxs(i.ComboboxChips,{ref:b,className:"min-h-9 w-full",children:[n.jsx(i.ComboboxValue,{children:a=>a.map(c=>n.jsx(i.ComboboxChip,{children:p.get(c)??c},c))}),n.jsx(i.ComboboxChipsInput,{id:o,placeholder:u??"Select…"})]}),n.jsxs(i.ComboboxContent,{anchor:b,children:[n.jsx(i.ComboboxEmpty,{children:"No options."}),n.jsx(i.ComboboxList,{children:a=>n.jsx(i.ComboboxItem,{value:a,children:n.jsxs("span",{className:"inline-flex items-center gap-2",children:[(()=>{const c=r.find(g=>g.value===a);return c?.swatch?n.jsx("span",{className:"inline-block h-2.5 w-2.5 rounded-sm border border-foreground/20",style:{backgroundColor:c.swatch},"aria-hidden":!0}):null})(),p.get(a)??a]})},a)})]})]})}const B={number:"number",integer:"number",date:"date",datetime:"datetime-local",time:"time"};function P(o){return B[o]??"text"}function R(o,l){if(l!==""){if(o==="number"){const r=parseFloat(l);return Number.isFinite(r)?r:l}if(o==="integer"){const r=parseInt(l,10);return Number.isFinite(r)?r:l}return l}}function D({fields:o,value:l,onChange:r,selectionSize:u,onApply:j,onClear:b,applyLabel:p="Apply",clearLabel:a="Clear wells",selectionEmptyLabel:c="Select wells to edit",selectionCountLabel:g=d=>`Apply to ${d} well${d===1?"":"s"}`,extras:y,className:C}){const d=(e,t)=>{r({...l,[e]:t})},m=e=>n.jsxs(M.Label,{htmlFor:`field-${e.key}`,className:"gap-1.5",children:[e.icon?n.jsx("span",{className:"inline-flex text-muted-foreground [&_svg]:size-3.5",children:e.icon}):null,e.label]}),v=(e,t)=>n.jsxs("div",{className:"flex flex-col gap-1.5",children:[m(e),e.render({value:t,onChange:s=>d(e.key,s),selectionSize:u})]},e.key),N=(e,t)=>n.jsxs("div",{className:"flex flex-col gap-1.5",children:[m(e),n.jsxs(x.Select,{value:t??"",onValueChange:s=>d(e.key,s),children:[n.jsx(x.SelectTrigger,{id:`field-${e.key}`,size:"sm",className:"w-full",children:n.jsx(x.SelectValue,{placeholder:e.placeholder??"Select…"})}),n.jsx(x.SelectContent,{children:(e.options??[]).map(s=>n.jsx(x.SelectItem,{value:s.value,children:n.jsxs("span",{className:"inline-flex items-center gap-2",children:[s.swatch?n.jsx("span",{className:"inline-block h-2.5 w-2.5 rounded-sm border border-foreground/20",style:{backgroundColor:s.swatch},"aria-hidden":!0}):null,s.label]})},s.value))})]})]},e.key),f=(e,t)=>{const s=Array.isArray(t)?t:[];return n.jsxs("div",{className:"flex flex-col gap-1.5",children:[m(e),n.jsx(A,{id:`field-${e.key}`,value:s,options:e.options??[],placeholder:e.placeholder,onChange:h=>d(e.key,h.length===0?void 0:h)})]},e.key)},_=(e,t)=>{const s=!!t;return e.boolStyle==="switch"?n.jsxs("div",{className:"flex items-center justify-between gap-2",children:[m(e),n.jsx($.Switch,{id:`field-${e.key}`,checked:s,onCheckedChange:h=>d(e.key,h)})]},e.key):n.jsxs("div",{className:"flex items-center gap-2",children:[n.jsx(I.Checkbox,{id:`field-${e.key}`,checked:s,onCheckedChange:h=>d(e.key,h===!0)}),m(e)]},e.key)},w=(e,t)=>n.jsxs("div",{className:"flex flex-col gap-1.5",children:[m(e),n.jsx(F.Input,{id:`field-${e.key}`,type:P(e.kind),step:e.kind==="integer"?1:void 0,placeholder:e.placeholder,value:t??"",onChange:s=>d(e.key,R(e.kind,s.target.value))})]},e.key),S=e=>{const t=l[e.key];return e.render?v(e,t):e.kind==="select"?N(e,t):e.kind==="multiselect"?f(e,t):e.kind==="boolean"?_(e,t):w(e,t)};return n.jsxs("div",{"data-slot":"well-metadata-form",className:O.cn("flex flex-col gap-3",C),children:[n.jsx("div",{className:"text-sm font-medium",children:u>0?g(u):c}),o.map(S),y,n.jsxs("div",{className:"mt-auto flex gap-2 pt-1",children:[n.jsx(k.Button,{variant:"default",size:"sm",disabled:u===0,onClick:j,children:p}),n.jsx(k.Button,{variant:"outline",size:"sm",disabled:u===0,onClick:b,children:a})]})]})}exports.WellMetadataForm=D;
2
2
  //# sourceMappingURL=WellMetadataForm.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"WellMetadataForm.cjs","sources":["../../../../src/components/composed/PlateMapEditor/WellMetadataForm.tsx"],"sourcesContent":["import * as React from \"react\";\n\nimport type { WellField, WellRecord, WellSelectOption } from \"./types\";\n\nimport { Button } from \"@/components/ui/button\";\nimport { Checkbox } from \"@/components/ui/checkbox\";\nimport {\n Combobox,\n ComboboxChip,\n ComboboxChips,\n ComboboxChipsInput,\n ComboboxContent,\n ComboboxEmpty,\n ComboboxItem,\n ComboboxList,\n ComboboxValue,\n useComboboxAnchor,\n} from \"@/components/ui/combobox\";\nimport { Input } from \"@/components/ui/input\";\nimport { Label } from \"@/components/ui/label\";\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from \"@/components/ui/select\";\nimport { Switch } from \"@/components/ui/switch\";\nimport { cn } from \"@/lib/utils\";\n\nfunction MultiSelectControl({\n id,\n value,\n options,\n placeholder,\n onChange,\n}: {\n id: string;\n value: string[];\n options: WellSelectOption[];\n placeholder?: string;\n onChange: (next: string[]) => void;\n}) {\n const anchorRef = useComboboxAnchor();\n const labelByValue = React.useMemo(() => {\n const m = new Map<string, string>();\n options.forEach((o) => m.set(o.value, o.label));\n return m;\n }, [options]);\n\n return (\n <Combobox multiple items={options.map((o) => o.value)} value={value} onValueChange={onChange}>\n <ComboboxChips ref={anchorRef} className=\"min-h-9 w-full\">\n <ComboboxValue>\n {(items: string[]) =>\n items.map((item) => <ComboboxChip key={item}>{labelByValue.get(item) ?? item}</ComboboxChip>)\n }\n </ComboboxValue>\n <ComboboxChipsInput id={id} placeholder={placeholder ?? \"Select…\"} />\n </ComboboxChips>\n <ComboboxContent anchor={anchorRef}>\n <ComboboxEmpty>No options.</ComboboxEmpty>\n <ComboboxList>\n {(item: string) => (\n <ComboboxItem key={item} value={item}>\n <span className=\"inline-flex items-center gap-2\">\n {(() => {\n const opt = options.find((o) => o.value === item);\n return opt?.swatch ? (\n <span\n className=\"inline-block h-2.5 w-2.5 rounded-sm border border-foreground/20\"\n style={{ backgroundColor: opt.swatch }}\n aria-hidden\n />\n ) : null;\n })()}\n {labelByValue.get(item) ?? item}\n </span>\n </ComboboxItem>\n )}\n </ComboboxList>\n </ComboboxContent>\n </Combobox>\n );\n}\n\nexport interface WellMetadataFormProps<T extends WellRecord = WellRecord> {\n fields: WellField<T>[];\n /** Staged values used to apply across the selection. */\n value: Partial<T>;\n onChange: (next: Partial<T>) => void;\n selectionSize: number;\n onApply: () => void;\n onClear: () => void;\n applyLabel?: string;\n clearLabel?: string;\n /** Optional extra slot rendered between fields and action row. */\n extras?: React.ReactNode;\n className?: string;\n}\n\nconst INPUT_TYPE_BY_KIND: Record<string, string> = {\n number: \"number\",\n integer: \"number\",\n date: \"date\",\n datetime: \"datetime-local\",\n time: \"time\",\n};\n\nfunction resolveInputType(kind: string): string {\n return INPUT_TYPE_BY_KIND[kind] ?? \"text\";\n}\n\nfunction parseInputValue(kind: string, raw: string): unknown {\n if (raw === \"\") return undefined;\n if (kind === \"number\") {\n const num = parseFloat(raw);\n return Number.isFinite(num) ? num : raw;\n }\n if (kind === \"integer\") {\n const num = parseInt(raw, 10);\n return Number.isFinite(num) ? num : raw;\n }\n return raw;\n}\n\nexport function WellMetadataForm<T extends WellRecord = WellRecord>({\n fields,\n value,\n onChange,\n selectionSize,\n onApply,\n onClear,\n applyLabel = \"Apply\",\n clearLabel = \"Clear wells\",\n extras,\n className,\n}: WellMetadataFormProps<T>) {\n const setField = (key: keyof T & string, next: unknown) => {\n onChange({ ...value, [key]: next } as Partial<T>);\n };\n\n const renderLabel = (field: WellField<T>) => (\n <Label htmlFor={`field-${field.key}`} className=\"gap-1.5\">\n {field.icon ? <span className=\"inline-flex text-muted-foreground [&_svg]:size-3.5\">{field.icon}</span> : null}\n {field.label}\n </Label>\n );\n\n const renderCustom = (field: WellField<T>, fieldValue: unknown) => (\n <div key={field.key} className=\"flex flex-col gap-1.5\">\n {renderLabel(field)}\n {field.render!({\n value: fieldValue,\n onChange: (next) => setField(field.key, next),\n selectionSize,\n })}\n </div>\n );\n\n const renderSelect = (field: WellField<T>, fieldValue: unknown) => (\n <div key={field.key} className=\"flex flex-col gap-1.5\">\n {renderLabel(field)}\n <Select value={(fieldValue as string | undefined) ?? \"\"} onValueChange={(v) => setField(field.key, v)}>\n <SelectTrigger id={`field-${field.key}`} size=\"sm\" className=\"w-full\">\n <SelectValue placeholder={field.placeholder ?? \"Select…\"} />\n </SelectTrigger>\n <SelectContent>\n {(field.options ?? []).map((opt) => (\n <SelectItem key={opt.value} value={opt.value}>\n <span className=\"inline-flex items-center gap-2\">\n {opt.swatch ? (\n <span\n className=\"inline-block h-2.5 w-2.5 rounded-sm border border-foreground/20\"\n style={{ backgroundColor: opt.swatch }}\n aria-hidden\n />\n ) : null}\n {opt.label}\n </span>\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n );\n\n const renderMultiSelect = (field: WellField<T>, fieldValue: unknown) => {\n const current = Array.isArray(fieldValue) ? (fieldValue as string[]) : [];\n return (\n <div key={field.key} className=\"flex flex-col gap-1.5\">\n {renderLabel(field)}\n <MultiSelectControl\n id={`field-${field.key}`}\n value={current}\n options={field.options ?? []}\n placeholder={field.placeholder}\n onChange={(next) => setField(field.key, next.length === 0 ? undefined : next)}\n />\n </div>\n );\n };\n\n const renderBoolean = (field: WellField<T>, fieldValue: unknown) => {\n const checked = !!fieldValue;\n if (field.boolStyle === \"switch\") {\n return (\n <div key={field.key} className=\"flex items-center justify-between gap-2\">\n {renderLabel(field)}\n <Switch\n id={`field-${field.key}`}\n checked={checked}\n onCheckedChange={(c) => setField(field.key, c)}\n />\n </div>\n );\n }\n return (\n <div key={field.key} className=\"flex items-center gap-2\">\n <Checkbox\n id={`field-${field.key}`}\n checked={checked}\n onCheckedChange={(c) => setField(field.key, c === true)}\n />\n {renderLabel(field)}\n </div>\n );\n };\n\n const renderInput = (field: WellField<T>, fieldValue: unknown) => (\n <div key={field.key} className=\"flex flex-col gap-1.5\">\n {renderLabel(field)}\n <Input\n id={`field-${field.key}`}\n type={resolveInputType(field.kind)}\n step={field.kind === \"integer\" ? 1 : undefined}\n placeholder={field.placeholder}\n value={(fieldValue as string | number | undefined) ?? \"\"}\n onChange={(e) => setField(field.key, parseInputValue(field.kind, e.target.value))}\n />\n </div>\n );\n\n const renderField = (field: WellField<T>) => {\n const fieldValue = value[field.key];\n if (field.render) return renderCustom(field, fieldValue);\n if (field.kind === \"select\") return renderSelect(field, fieldValue);\n if (field.kind === \"multiselect\") return renderMultiSelect(field, fieldValue);\n if (field.kind === \"boolean\") return renderBoolean(field, fieldValue);\n return renderInput(field, fieldValue);\n };\n\n return (\n <div data-slot=\"well-metadata-form\" className={cn(\"flex flex-col gap-3\", className)}>\n <div className=\"text-sm font-medium\">\n {selectionSize > 0 ? `Apply to ${selectionSize} well${selectionSize === 1 ? \"\" : \"s\"}` : \"Select wells to edit\"}\n </div>\n\n {fields.map(renderField)}\n\n {extras}\n\n <div className=\"mt-auto flex gap-2 pt-1\">\n <Button variant=\"default\" size=\"sm\" disabled={selectionSize === 0} onClick={onApply}>\n {applyLabel}\n </Button>\n <Button variant=\"outline\" size=\"sm\" disabled={selectionSize === 0} onClick={onClear}>\n {clearLabel}\n </Button>\n </div>\n </div>\n );\n}\n"],"names":["MultiSelectControl","id","value","options","placeholder","onChange","anchorRef","useComboboxAnchor","labelByValue","React","m","o","jsxs","Combobox","ComboboxChips","jsx","ComboboxValue","items","item","ComboboxChip","ComboboxChipsInput","ComboboxContent","ComboboxEmpty","ComboboxList","ComboboxItem","opt","INPUT_TYPE_BY_KIND","resolveInputType","kind","parseInputValue","raw","num","WellMetadataForm","fields","selectionSize","onApply","onClear","applyLabel","clearLabel","extras","className","setField","key","next","renderLabel","field","Label","renderCustom","fieldValue","renderSelect","Select","v","SelectTrigger","SelectValue","SelectContent","SelectItem","renderMultiSelect","current","renderBoolean","checked","Switch","c","Checkbox","renderInput","Input","e","renderField","cn","Button"],"mappings":"osBAwBA,SAASA,EAAmB,CAC1B,GAAAC,EACA,MAAAC,EACA,QAAAC,EACA,YAAAC,EACA,SAAAC,CACF,EAMG,CACD,MAAMC,EAAYC,EAAAA,kBAAA,EACZC,EAAeC,EAAM,QAAQ,IAAM,CACvC,MAAMC,MAAQ,IACd,OAAAP,EAAQ,QAASQ,GAAMD,EAAE,IAAIC,EAAE,MAAOA,EAAE,KAAK,CAAC,EACvCD,CACT,EAAG,CAACP,CAAO,CAAC,EAEZ,OACES,EAAAA,KAACC,EAAAA,SAAA,CAAS,SAAQ,GAAC,MAAOV,EAAQ,IAAKQ,GAAMA,EAAE,KAAK,EAAG,MAAAT,EAAc,cAAeG,EAClF,SAAA,CAAAO,EAAAA,KAACE,EAAAA,cAAA,CAAc,IAAKR,EAAW,UAAU,iBACvC,SAAA,CAAAS,MAACC,EAAAA,eACE,SAACC,GACAA,EAAM,IAAKC,GAASH,EAAAA,IAACI,EAAAA,aAAA,CAAyB,SAAAX,EAAa,IAAIU,CAAI,GAAKA,CAAA,EAAjCA,CAAsC,CAAe,EAEhG,EACAH,EAAAA,IAACK,EAAAA,mBAAA,CAAmB,GAAAnB,EAAQ,YAAaG,GAAe,SAAA,CAAW,CAAA,EACrE,EACAQ,EAAAA,KAACS,EAAAA,gBAAA,CAAgB,OAAQf,EACvB,SAAA,CAAAS,EAAAA,IAACO,EAAAA,eAAc,SAAA,aAAA,CAAW,EAC1BP,EAAAA,IAACQ,EAAAA,aAAA,CACE,SAACL,GACAH,EAAAA,IAACS,eAAA,CAAwB,MAAON,EAC9B,SAAAN,OAAC,OAAA,CAAK,UAAU,iCACZ,SAAA,EAAA,IAAM,CACN,MAAMa,EAAMtB,EAAQ,KAAMQ,GAAMA,EAAE,QAAUO,CAAI,EAChD,OAAOO,GAAK,OACVV,EAAAA,IAAC,OAAA,CACC,UAAU,kEACV,MAAO,CAAE,gBAAiBU,EAAI,MAAA,EAC9B,cAAW,EAAA,CAAA,EAEX,IACN,GAAA,EACCjB,EAAa,IAAIU,CAAI,GAAKA,CAAA,EAC7B,CAAA,EAbiBA,CAcnB,CAAA,CAEJ,CAAA,CAAA,CACF,CAAA,EACF,CAEJ,CAiBA,MAAMQ,EAA6C,CACjD,OAAQ,SACR,QAAS,SACT,KAAM,OACN,SAAU,iBACV,KAAM,MACR,EAEA,SAASC,EAAiBC,EAAsB,CAC9C,OAAOF,EAAmBE,CAAI,GAAK,MACrC,CAEA,SAASC,EAAgBD,EAAcE,EAAsB,CAC3D,GAAIA,IAAQ,GACZ,IAAIF,IAAS,SAAU,CACrB,MAAMG,EAAM,WAAWD,CAAG,EAC1B,OAAO,OAAO,SAASC,CAAG,EAAIA,EAAMD,CACtC,CACA,GAAIF,IAAS,UAAW,CACtB,MAAMG,EAAM,SAASD,EAAK,EAAE,EAC5B,OAAO,OAAO,SAASC,CAAG,EAAIA,EAAMD,CACtC,CACA,OAAOA,EACT,CAEO,SAASE,EAAoD,CAClE,OAAAC,EACA,MAAA/B,EACA,SAAAG,EACA,cAAA6B,EACA,QAAAC,EACA,QAAAC,EACA,WAAAC,EAAa,QACb,WAAAC,EAAa,cACb,OAAAC,EACA,UAAAC,CACF,EAA6B,CAC3B,MAAMC,EAAW,CAACC,EAAuBC,IAAkB,CACzDtC,EAAS,CAAE,GAAGH,EAAO,CAACwC,CAAG,EAAGC,EAAoB,CAClD,EAEMC,EAAeC,GACnBjC,EAAAA,KAACkC,EAAAA,MAAA,CAAM,QAAS,SAASD,EAAM,GAAG,GAAI,UAAU,UAC7C,SAAA,CAAAA,EAAM,KAAO9B,MAAC,OAAA,CAAK,UAAU,qDAAsD,SAAA8B,EAAM,KAAK,EAAU,KACxGA,EAAM,KAAA,EACT,EAGIE,EAAe,CAACF,EAAqBG,IACzCpC,EAAAA,KAAC,MAAA,CAAoB,UAAU,wBAC5B,SAAA,CAAAgC,EAAYC,CAAK,EACjBA,EAAM,OAAQ,CACb,MAAOG,EACP,SAAWL,GAASF,EAASI,EAAM,IAAKF,CAAI,EAC5C,cAAAT,CAAA,CACD,CAAA,CAAA,EANOW,EAAM,GAOhB,EAGII,EAAe,CAACJ,EAAqBG,IACzCpC,EAAAA,KAAC,MAAA,CAAoB,UAAU,wBAC5B,SAAA,CAAAgC,EAAYC,CAAK,EAClBjC,EAAAA,KAACsC,EAAAA,OAAA,CAAO,MAAQF,GAAqC,GAAI,cAAgBG,GAAMV,EAASI,EAAM,IAAKM,CAAC,EAClG,SAAA,CAAApC,MAACqC,EAAAA,eAAc,GAAI,SAASP,EAAM,GAAG,GAAI,KAAK,KAAK,UAAU,SAC3D,eAACQ,cAAA,CAAY,YAAaR,EAAM,aAAe,UAAW,EAC5D,QACCS,EAAAA,cAAA,CACG,UAAAT,EAAM,SAAW,IAAI,IAAKpB,GAC1BV,EAAAA,IAACwC,EAAAA,YAA2B,MAAO9B,EAAI,MACrC,SAAAb,OAAC,OAAA,CAAK,UAAU,iCACb,SAAA,CAAAa,EAAI,OACHV,EAAAA,IAAC,OAAA,CACC,UAAU,kEACV,MAAO,CAAE,gBAAiBU,EAAI,MAAA,EAC9B,cAAW,EAAA,CAAA,EAEX,KACHA,EAAI,KAAA,CAAA,CACP,CAAA,EAVeA,EAAI,KAWrB,CACD,CAAA,CACH,CAAA,CAAA,CACF,CAAA,CAAA,EAtBQoB,EAAM,GAuBhB,EAGIW,EAAoB,CAACX,EAAqBG,IAAwB,CACtE,MAAMS,EAAU,MAAM,QAAQT,CAAU,EAAKA,EAA0B,CAAA,EACvE,OACEpC,EAAAA,KAAC,MAAA,CAAoB,UAAU,wBAC5B,SAAA,CAAAgC,EAAYC,CAAK,EAClB9B,EAAAA,IAACf,EAAA,CACC,GAAI,SAAS6C,EAAM,GAAG,GACtB,MAAOY,EACP,QAASZ,EAAM,SAAW,CAAA,EAC1B,YAAaA,EAAM,YACnB,SAAWF,GAASF,EAASI,EAAM,IAAKF,EAAK,SAAW,EAAI,OAAYA,CAAI,CAAA,CAAA,CAC9E,CAAA,EARQE,EAAM,GAShB,CAEJ,EAEMa,EAAgB,CAACb,EAAqBG,IAAwB,CAClE,MAAMW,EAAU,CAAC,CAACX,EAClB,OAAIH,EAAM,YAAc,SAEpBjC,EAAAA,KAAC,MAAA,CAAoB,UAAU,0CAC5B,SAAA,CAAAgC,EAAYC,CAAK,EAClB9B,EAAAA,IAAC6C,EAAAA,OAAA,CACC,GAAI,SAASf,EAAM,GAAG,GACtB,QAAAc,EACA,gBAAkBE,GAAMpB,EAASI,EAAM,IAAKgB,CAAC,CAAA,CAAA,CAC/C,CAAA,EANQhB,EAAM,GAOhB,EAIFjC,EAAAA,KAAC,MAAA,CAAoB,UAAU,0BAC7B,SAAA,CAAAG,EAAAA,IAAC+C,EAAAA,SAAA,CACC,GAAI,SAASjB,EAAM,GAAG,GACtB,QAAAc,EACA,gBAAkBE,GAAMpB,EAASI,EAAM,IAAKgB,IAAM,EAAI,CAAA,CAAA,EAEvDjB,EAAYC,CAAK,CAAA,CAAA,EANVA,EAAM,GAOhB,CAEJ,EAEMkB,EAAc,CAAClB,EAAqBG,IACxCpC,EAAAA,KAAC,MAAA,CAAoB,UAAU,wBAC5B,SAAA,CAAAgC,EAAYC,CAAK,EAClB9B,EAAAA,IAACiD,EAAAA,MAAA,CACC,GAAI,SAASnB,EAAM,GAAG,GACtB,KAAMlB,EAAiBkB,EAAM,IAAI,EACjC,KAAMA,EAAM,OAAS,UAAY,EAAI,OACrC,YAAaA,EAAM,YACnB,MAAQG,GAA8C,GACtD,SAAWiB,GAAMxB,EAASI,EAAM,IAAKhB,EAAgBgB,EAAM,KAAMoB,EAAE,OAAO,KAAK,CAAC,CAAA,CAAA,CAClF,CAAA,EATQpB,EAAM,GAUhB,EAGIqB,EAAerB,GAAwB,CAC3C,MAAMG,EAAa9C,EAAM2C,EAAM,GAAG,EAClC,OAAIA,EAAM,OAAeE,EAAaF,EAAOG,CAAU,EACnDH,EAAM,OAAS,SAAiBI,EAAaJ,EAAOG,CAAU,EAC9DH,EAAM,OAAS,cAAsBW,EAAkBX,EAAOG,CAAU,EACxEH,EAAM,OAAS,UAAkBa,EAAcb,EAAOG,CAAU,EAC7De,EAAYlB,EAAOG,CAAU,CACtC,EAEA,OACEpC,OAAC,OAAI,YAAU,qBAAqB,UAAWuD,EAAAA,GAAG,sBAAuB3B,CAAS,EAChF,SAAA,CAAAzB,EAAAA,IAAC,MAAA,CAAI,UAAU,sBACZ,SAAAmB,EAAgB,EAAI,YAAYA,CAAa,QAAQA,IAAkB,EAAI,GAAK,GAAG,GAAK,uBAC3F,EAECD,EAAO,IAAIiC,CAAW,EAEtB3B,EAED3B,EAAAA,KAAC,MAAA,CAAI,UAAU,0BACb,SAAA,CAAAG,EAAAA,IAACqD,EAAAA,OAAA,CAAO,QAAQ,UAAU,KAAK,KAAK,SAAUlC,IAAkB,EAAG,QAASC,EACzE,SAAAE,CAAA,CACH,EACAtB,EAAAA,IAACqD,EAAAA,OAAA,CAAO,QAAQ,UAAU,KAAK,KAAK,SAAUlC,IAAkB,EAAG,QAASE,EACzE,SAAAE,CAAA,CACH,CAAA,CAAA,CACF,CAAA,EACF,CAEJ"}
1
+ {"version":3,"file":"WellMetadataForm.cjs","sources":["../../../../src/components/composed/PlateMapEditor/WellMetadataForm.tsx"],"sourcesContent":["import * as React from \"react\";\n\nimport type { WellField, WellRecord, WellSelectOption } from \"./types\";\n\nimport { Button } from \"@/components/ui/button\";\nimport { Checkbox } from \"@/components/ui/checkbox\";\nimport {\n Combobox,\n ComboboxChip,\n ComboboxChips,\n ComboboxChipsInput,\n ComboboxContent,\n ComboboxEmpty,\n ComboboxItem,\n ComboboxList,\n ComboboxValue,\n useComboboxAnchor,\n} from \"@/components/ui/combobox\";\nimport { Input } from \"@/components/ui/input\";\nimport { Label } from \"@/components/ui/label\";\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from \"@/components/ui/select\";\nimport { Switch } from \"@/components/ui/switch\";\nimport { cn } from \"@/lib/utils\";\n\nfunction MultiSelectControl({\n id,\n value,\n options,\n placeholder,\n onChange,\n}: {\n id: string;\n value: string[];\n options: WellSelectOption[];\n placeholder?: string;\n onChange: (next: string[]) => void;\n}) {\n const anchorRef = useComboboxAnchor();\n const labelByValue = React.useMemo(() => {\n const m = new Map<string, string>();\n options.forEach((o) => m.set(o.value, o.label));\n return m;\n }, [options]);\n\n return (\n <Combobox multiple items={options.map((o) => o.value)} value={value} onValueChange={onChange}>\n <ComboboxChips ref={anchorRef} className=\"min-h-9 w-full\">\n <ComboboxValue>\n {(items: string[]) =>\n items.map((item) => <ComboboxChip key={item}>{labelByValue.get(item) ?? item}</ComboboxChip>)\n }\n </ComboboxValue>\n <ComboboxChipsInput id={id} placeholder={placeholder ?? \"Select…\"} />\n </ComboboxChips>\n <ComboboxContent anchor={anchorRef}>\n <ComboboxEmpty>No options.</ComboboxEmpty>\n <ComboboxList>\n {(item: string) => (\n <ComboboxItem key={item} value={item}>\n <span className=\"inline-flex items-center gap-2\">\n {(() => {\n const opt = options.find((o) => o.value === item);\n return opt?.swatch ? (\n <span\n className=\"inline-block h-2.5 w-2.5 rounded-sm border border-foreground/20\"\n style={{ backgroundColor: opt.swatch }}\n aria-hidden\n />\n ) : null;\n })()}\n {labelByValue.get(item) ?? item}\n </span>\n </ComboboxItem>\n )}\n </ComboboxList>\n </ComboboxContent>\n </Combobox>\n );\n}\n\nexport interface WellMetadataFormProps<T extends WellRecord = WellRecord> {\n fields: WellField<T>[];\n /** Staged values used to apply across the selection. */\n value: Partial<T>;\n onChange: (next: Partial<T>) => void;\n selectionSize: number;\n onApply: () => void;\n onClear: () => void;\n applyLabel?: string;\n clearLabel?: string;\n /** Heading shown when nothing is selected. Defaults to `\"Select wells to edit\"`. */\n selectionEmptyLabel?: string;\n /** Heading shown with a selection. Defaults to `` `Apply to ${n} wells` ``. */\n selectionCountLabel?: (selectionSize: number) => string;\n /** Optional extra slot rendered between fields and action row. */\n extras?: React.ReactNode;\n className?: string;\n}\n\nconst INPUT_TYPE_BY_KIND: Record<string, string> = {\n number: \"number\",\n integer: \"number\",\n date: \"date\",\n datetime: \"datetime-local\",\n time: \"time\",\n};\n\nfunction resolveInputType(kind: string): string {\n return INPUT_TYPE_BY_KIND[kind] ?? \"text\";\n}\n\nfunction parseInputValue(kind: string, raw: string): unknown {\n if (raw === \"\") return undefined;\n if (kind === \"number\") {\n const num = parseFloat(raw);\n return Number.isFinite(num) ? num : raw;\n }\n if (kind === \"integer\") {\n const num = parseInt(raw, 10);\n return Number.isFinite(num) ? num : raw;\n }\n return raw;\n}\n\nexport function WellMetadataForm<T extends WellRecord = WellRecord>({\n fields,\n value,\n onChange,\n selectionSize,\n onApply,\n onClear,\n applyLabel = \"Apply\",\n clearLabel = \"Clear wells\",\n selectionEmptyLabel = \"Select wells to edit\",\n selectionCountLabel = (n: number) => `Apply to ${n} well${n === 1 ? \"\" : \"s\"}`,\n extras,\n className,\n}: WellMetadataFormProps<T>) {\n const setField = (key: keyof T & string, next: unknown) => {\n onChange({ ...value, [key]: next } as Partial<T>);\n };\n\n const renderLabel = (field: WellField<T>) => (\n <Label htmlFor={`field-${field.key}`} className=\"gap-1.5\">\n {field.icon ? <span className=\"inline-flex text-muted-foreground [&_svg]:size-3.5\">{field.icon}</span> : null}\n {field.label}\n </Label>\n );\n\n const renderCustom = (field: WellField<T>, fieldValue: unknown) => (\n <div key={field.key} className=\"flex flex-col gap-1.5\">\n {renderLabel(field)}\n {field.render!({\n value: fieldValue,\n onChange: (next) => setField(field.key, next),\n selectionSize,\n })}\n </div>\n );\n\n const renderSelect = (field: WellField<T>, fieldValue: unknown) => (\n <div key={field.key} className=\"flex flex-col gap-1.5\">\n {renderLabel(field)}\n <Select value={(fieldValue as string | undefined) ?? \"\"} onValueChange={(v) => setField(field.key, v)}>\n <SelectTrigger id={`field-${field.key}`} size=\"sm\" className=\"w-full\">\n <SelectValue placeholder={field.placeholder ?? \"Select…\"} />\n </SelectTrigger>\n <SelectContent>\n {(field.options ?? []).map((opt) => (\n <SelectItem key={opt.value} value={opt.value}>\n <span className=\"inline-flex items-center gap-2\">\n {opt.swatch ? (\n <span\n className=\"inline-block h-2.5 w-2.5 rounded-sm border border-foreground/20\"\n style={{ backgroundColor: opt.swatch }}\n aria-hidden\n />\n ) : null}\n {opt.label}\n </span>\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n );\n\n const renderMultiSelect = (field: WellField<T>, fieldValue: unknown) => {\n const current = Array.isArray(fieldValue) ? (fieldValue as string[]) : [];\n return (\n <div key={field.key} className=\"flex flex-col gap-1.5\">\n {renderLabel(field)}\n <MultiSelectControl\n id={`field-${field.key}`}\n value={current}\n options={field.options ?? []}\n placeholder={field.placeholder}\n onChange={(next) => setField(field.key, next.length === 0 ? undefined : next)}\n />\n </div>\n );\n };\n\n const renderBoolean = (field: WellField<T>, fieldValue: unknown) => {\n const checked = !!fieldValue;\n if (field.boolStyle === \"switch\") {\n return (\n <div key={field.key} className=\"flex items-center justify-between gap-2\">\n {renderLabel(field)}\n <Switch id={`field-${field.key}`} checked={checked} onCheckedChange={(c) => setField(field.key, c)} />\n </div>\n );\n }\n return (\n <div key={field.key} className=\"flex items-center gap-2\">\n <Checkbox\n id={`field-${field.key}`}\n checked={checked}\n onCheckedChange={(c) => setField(field.key, c === true)}\n />\n {renderLabel(field)}\n </div>\n );\n };\n\n const renderInput = (field: WellField<T>, fieldValue: unknown) => (\n <div key={field.key} className=\"flex flex-col gap-1.5\">\n {renderLabel(field)}\n <Input\n id={`field-${field.key}`}\n type={resolveInputType(field.kind)}\n step={field.kind === \"integer\" ? 1 : undefined}\n placeholder={field.placeholder}\n value={(fieldValue as string | number | undefined) ?? \"\"}\n onChange={(e) => setField(field.key, parseInputValue(field.kind, e.target.value))}\n />\n </div>\n );\n\n const renderField = (field: WellField<T>) => {\n const fieldValue = value[field.key];\n if (field.render) return renderCustom(field, fieldValue);\n if (field.kind === \"select\") return renderSelect(field, fieldValue);\n if (field.kind === \"multiselect\") return renderMultiSelect(field, fieldValue);\n if (field.kind === \"boolean\") return renderBoolean(field, fieldValue);\n return renderInput(field, fieldValue);\n };\n\n return (\n <div data-slot=\"well-metadata-form\" className={cn(\"flex flex-col gap-3\", className)}>\n <div className=\"text-sm font-medium\">\n {selectionSize > 0 ? selectionCountLabel(selectionSize) : selectionEmptyLabel}\n </div>\n\n {fields.map(renderField)}\n\n {extras}\n\n <div className=\"mt-auto flex gap-2 pt-1\">\n <Button variant=\"default\" size=\"sm\" disabled={selectionSize === 0} onClick={onApply}>\n {applyLabel}\n </Button>\n <Button variant=\"outline\" size=\"sm\" disabled={selectionSize === 0} onClick={onClear}>\n {clearLabel}\n </Button>\n </div>\n </div>\n );\n}\n"],"names":["MultiSelectControl","id","value","options","placeholder","onChange","anchorRef","useComboboxAnchor","labelByValue","React","m","o","jsxs","Combobox","ComboboxChips","jsx","ComboboxValue","items","item","ComboboxChip","ComboboxChipsInput","ComboboxContent","ComboboxEmpty","ComboboxList","ComboboxItem","opt","INPUT_TYPE_BY_KIND","resolveInputType","kind","parseInputValue","raw","num","WellMetadataForm","fields","selectionSize","onApply","onClear","applyLabel","clearLabel","selectionEmptyLabel","selectionCountLabel","n","extras","className","setField","key","next","renderLabel","field","Label","renderCustom","fieldValue","renderSelect","Select","v","SelectTrigger","SelectValue","SelectContent","SelectItem","renderMultiSelect","current","renderBoolean","checked","Switch","c","Checkbox","renderInput","Input","e","renderField","cn","Button"],"mappings":"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"}
@@ -10,8 +10,12 @@ export interface WellMetadataFormProps<T extends WellRecord = WellRecord> {
10
10
  onClear: () => void;
11
11
  applyLabel?: string;
12
12
  clearLabel?: string;
13
+ /** Heading shown when nothing is selected. Defaults to `"Select wells to edit"`. */
14
+ selectionEmptyLabel?: string;
15
+ /** Heading shown with a selection. Defaults to `` `Apply to ${n} wells` ``. */
16
+ selectionCountLabel?: (selectionSize: number) => string;
13
17
  /** Optional extra slot rendered between fields and action row. */
14
18
  extras?: React.ReactNode;
15
19
  className?: string;
16
20
  }
17
- export declare function WellMetadataForm<T extends WellRecord = WellRecord>({ fields, value, onChange, selectionSize, onApply, onClear, applyLabel, clearLabel, extras, className, }: WellMetadataFormProps<T>): import("react/jsx-runtime").JSX.Element;
21
+ export declare function WellMetadataForm<T extends WellRecord = WellRecord>({ fields, value, onChange, selectionSize, onApply, onClear, applyLabel, clearLabel, selectionEmptyLabel, selectionCountLabel, extras, className, }: WellMetadataFormProps<T>): import("react/jsx-runtime").JSX.Element;
@@ -1,32 +1,32 @@
1
1
  import { jsxs as o, jsx as n } from "react/jsx-runtime";
2
- import * as I from "react";
2
+ import * as $ from "react";
3
3
  import { Button as x } from "../../../ui/button.js";
4
- import { Checkbox as S } from "../../../ui/checkbox.js";
5
- import { useComboboxAnchor as $, Combobox as F, ComboboxChips as V, ComboboxValue as A, ComboboxChip as M, ComboboxChipsInput as B, ComboboxContent as T, ComboboxEmpty as _, ComboboxList as j, ComboboxItem as E } from "../../../ui/combobox.js";
6
- import { Input as L } from "../../../ui/input.js";
7
- import { Label as P } from "../../../ui/label.js";
8
- import { Select as R, SelectTrigger as Y, SelectValue as D, SelectContent as K, SelectItem as U } from "../../../ui/select.js";
9
- import { Switch as W } from "../../../ui/switch.js";
10
- import { cn as q } from "../../../lib/utils.js";
11
- function G({
12
- id: i,
4
+ import { Checkbox as F } from "../../../ui/checkbox.js";
5
+ import { useComboboxAnchor as V, Combobox as A, ComboboxChips as M, ComboboxValue as B, ComboboxChip as T, ComboboxChipsInput as _, ComboboxContent as j, ComboboxEmpty as E, ComboboxList as L, ComboboxItem as P } from "../../../ui/combobox.js";
6
+ import { Input as R } from "../../../ui/input.js";
7
+ import { Label as Y } from "../../../ui/label.js";
8
+ import { Select as D, SelectTrigger as K, SelectValue as U, SelectContent as W, SelectItem as q } from "../../../ui/select.js";
9
+ import { Switch as z } from "../../../ui/switch.js";
10
+ import { cn as G } from "../../../lib/utils.js";
11
+ function H({
12
+ id: m,
13
13
  value: c,
14
14
  options: a,
15
- placeholder: m,
15
+ placeholder: u,
16
16
  onChange: k
17
17
  }) {
18
- const p = $(), b = I.useMemo(() => {
18
+ const p = V(), b = $.useMemo(() => {
19
19
  const l = /* @__PURE__ */ new Map();
20
20
  return a.forEach((s) => l.set(s.value, s.label)), l;
21
21
  }, [a]);
22
- return /* @__PURE__ */ o(F, { multiple: !0, items: a.map((l) => l.value), value: c, onValueChange: k, children: [
23
- /* @__PURE__ */ o(V, { ref: p, className: "min-h-9 w-full", children: [
24
- /* @__PURE__ */ n(A, { children: (l) => l.map((s) => /* @__PURE__ */ n(M, { children: b.get(s) ?? s }, s)) }),
25
- /* @__PURE__ */ n(B, { id: i, placeholder: m ?? "Select…" })
22
+ return /* @__PURE__ */ o(A, { multiple: !0, items: a.map((l) => l.value), value: c, onValueChange: k, children: [
23
+ /* @__PURE__ */ o(M, { ref: p, className: "min-h-9 w-full", children: [
24
+ /* @__PURE__ */ n(B, { children: (l) => l.map((s) => /* @__PURE__ */ n(T, { children: b.get(s) ?? s }, s)) }),
25
+ /* @__PURE__ */ n(_, { id: m, placeholder: u ?? "Select…" })
26
26
  ] }),
27
- /* @__PURE__ */ o(T, { anchor: p, children: [
28
- /* @__PURE__ */ n(_, { children: "No options." }),
29
- /* @__PURE__ */ n(j, { children: (l) => /* @__PURE__ */ n(E, { value: l, children: /* @__PURE__ */ o("span", { className: "inline-flex items-center gap-2", children: [
27
+ /* @__PURE__ */ o(j, { anchor: p, children: [
28
+ /* @__PURE__ */ n(E, { children: "No options." }),
29
+ /* @__PURE__ */ n(L, { children: (l) => /* @__PURE__ */ n(P, { value: l, children: /* @__PURE__ */ o("span", { className: "inline-flex items-center gap-2", children: [
30
30
  (() => {
31
31
  const s = a.find((g) => g.value === l);
32
32
  return s?.swatch ? /* @__PURE__ */ n(
@@ -43,58 +43,60 @@ function G({
43
43
  ] })
44
44
  ] });
45
45
  }
46
- const H = {
46
+ const J = {
47
47
  number: "number",
48
48
  integer: "number",
49
49
  date: "date",
50
50
  datetime: "datetime-local",
51
51
  time: "time"
52
52
  };
53
- function J(i) {
54
- return H[i] ?? "text";
53
+ function O(m) {
54
+ return J[m] ?? "text";
55
55
  }
56
- function O(i, c) {
56
+ function Q(m, c) {
57
57
  if (c !== "") {
58
- if (i === "number") {
58
+ if (m === "number") {
59
59
  const a = parseFloat(c);
60
60
  return Number.isFinite(a) ? a : c;
61
61
  }
62
- if (i === "integer") {
62
+ if (m === "integer") {
63
63
  const a = parseInt(c, 10);
64
64
  return Number.isFinite(a) ? a : c;
65
65
  }
66
66
  return c;
67
67
  }
68
68
  }
69
- function le({
70
- fields: i,
69
+ function ce({
70
+ fields: m,
71
71
  value: c,
72
72
  onChange: a,
73
- selectionSize: m,
73
+ selectionSize: u,
74
74
  onApply: k,
75
75
  onClear: p,
76
76
  applyLabel: b = "Apply",
77
77
  clearLabel: l = "Clear wells",
78
- extras: s,
79
- className: g
78
+ selectionEmptyLabel: s = "Select wells to edit",
79
+ selectionCountLabel: g = (i) => `Apply to ${i} well${i === 1 ? "" : "s"}`,
80
+ extras: C,
81
+ className: y
80
82
  }) {
81
- const u = (e, r) => {
83
+ const i = (e, r) => {
82
84
  a({ ...c, [e]: r });
83
- }, d = (e) => /* @__PURE__ */ o(P, { htmlFor: `field-${e.key}`, className: "gap-1.5", children: [
85
+ }, d = (e) => /* @__PURE__ */ o(Y, { htmlFor: `field-${e.key}`, className: "gap-1.5", children: [
84
86
  e.icon ? /* @__PURE__ */ n("span", { className: "inline-flex text-muted-foreground [&_svg]:size-3.5", children: e.icon }) : null,
85
87
  e.label
86
- ] }), C = (e, r) => /* @__PURE__ */ o("div", { className: "flex flex-col gap-1.5", children: [
88
+ ] }), v = (e, r) => /* @__PURE__ */ o("div", { className: "flex flex-col gap-1.5", children: [
87
89
  d(e),
88
90
  e.render({
89
91
  value: r,
90
- onChange: (t) => u(e.key, t),
91
- selectionSize: m
92
+ onChange: (t) => i(e.key, t),
93
+ selectionSize: u
92
94
  })
93
- ] }, e.key), y = (e, r) => /* @__PURE__ */ o("div", { className: "flex flex-col gap-1.5", children: [
95
+ ] }, e.key), N = (e, r) => /* @__PURE__ */ o("div", { className: "flex flex-col gap-1.5", children: [
94
96
  d(e),
95
- /* @__PURE__ */ o(R, { value: r ?? "", onValueChange: (t) => u(e.key, t), children: [
96
- /* @__PURE__ */ n(Y, { id: `field-${e.key}`, size: "sm", className: "w-full", children: /* @__PURE__ */ n(D, { placeholder: e.placeholder ?? "Select…" }) }),
97
- /* @__PURE__ */ n(K, { children: (e.options ?? []).map((t) => /* @__PURE__ */ n(U, { value: t.value, children: /* @__PURE__ */ o("span", { className: "inline-flex items-center gap-2", children: [
97
+ /* @__PURE__ */ o(D, { value: r ?? "", onValueChange: (t) => i(e.key, t), children: [
98
+ /* @__PURE__ */ n(K, { id: `field-${e.key}`, size: "sm", className: "w-full", children: /* @__PURE__ */ n(U, { placeholder: e.placeholder ?? "Select…" }) }),
99
+ /* @__PURE__ */ n(W, { children: (e.options ?? []).map((t) => /* @__PURE__ */ n(q, { value: t.value, children: /* @__PURE__ */ o("span", { className: "inline-flex items-center gap-2", children: [
98
100
  t.swatch ? /* @__PURE__ */ n(
99
101
  "span",
100
102
  {
@@ -106,72 +108,65 @@ function le({
106
108
  t.label
107
109
  ] }) }, t.value)) })
108
110
  ] })
109
- ] }, e.key), v = (e, r) => {
111
+ ] }, e.key), f = (e, r) => {
110
112
  const t = Array.isArray(r) ? r : [];
111
113
  return /* @__PURE__ */ o("div", { className: "flex flex-col gap-1.5", children: [
112
114
  d(e),
113
115
  /* @__PURE__ */ n(
114
- G,
116
+ H,
115
117
  {
116
118
  id: `field-${e.key}`,
117
119
  value: t,
118
120
  options: e.options ?? [],
119
121
  placeholder: e.placeholder,
120
- onChange: (h) => u(e.key, h.length === 0 ? void 0 : h)
122
+ onChange: (h) => i(e.key, h.length === 0 ? void 0 : h)
121
123
  }
122
124
  )
123
125
  ] }, e.key);
124
- }, N = (e, r) => {
126
+ }, w = (e, r) => {
125
127
  const t = !!r;
126
128
  return e.boolStyle === "switch" ? /* @__PURE__ */ o("div", { className: "flex items-center justify-between gap-2", children: [
127
129
  d(e),
128
- /* @__PURE__ */ n(
129
- W,
130
- {
131
- id: `field-${e.key}`,
132
- checked: t,
133
- onCheckedChange: (h) => u(e.key, h)
134
- }
135
- )
130
+ /* @__PURE__ */ n(z, { id: `field-${e.key}`, checked: t, onCheckedChange: (h) => i(e.key, h) })
136
131
  ] }, e.key) : /* @__PURE__ */ o("div", { className: "flex items-center gap-2", children: [
137
132
  /* @__PURE__ */ n(
138
- S,
133
+ F,
139
134
  {
140
135
  id: `field-${e.key}`,
141
136
  checked: t,
142
- onCheckedChange: (h) => u(e.key, h === !0)
137
+ onCheckedChange: (h) => i(e.key, h === !0)
143
138
  }
144
139
  ),
145
140
  d(e)
146
141
  ] }, e.key);
147
- }, f = (e, r) => /* @__PURE__ */ o("div", { className: "flex flex-col gap-1.5", children: [
142
+ }, I = (e, r) => /* @__PURE__ */ o("div", { className: "flex flex-col gap-1.5", children: [
148
143
  d(e),
149
144
  /* @__PURE__ */ n(
150
- L,
145
+ R,
151
146
  {
152
147
  id: `field-${e.key}`,
153
- type: J(e.kind),
148
+ type: O(e.kind),
154
149
  step: e.kind === "integer" ? 1 : void 0,
155
150
  placeholder: e.placeholder,
156
151
  value: r ?? "",
157
- onChange: (t) => u(e.key, O(e.kind, t.target.value))
152
+ onChange: (t) => i(e.key, Q(e.kind, t.target.value))
158
153
  }
159
154
  )
160
- ] }, e.key), w = (e) => {
155
+ ] }, e.key), S = (e) => {
161
156
  const r = c[e.key];
162
- return e.render ? C(e, r) : e.kind === "select" ? y(e, r) : e.kind === "multiselect" ? v(e, r) : e.kind === "boolean" ? N(e, r) : f(e, r);
157
+ return e.render ? v(e, r) : e.kind === "select" ? N(e, r) : e.kind === "multiselect" ? f(e, r) : e.kind === "boolean" ? w(e, r) : I(e, r);
163
158
  };
164
- return /* @__PURE__ */ o("div", { "data-slot": "well-metadata-form", className: q("flex flex-col gap-3", g), children: [
165
- /* @__PURE__ */ n("div", { className: "text-sm font-medium", children: m > 0 ? `Apply to ${m} well${m === 1 ? "" : "s"}` : "Select wells to edit" }),
166
- i.map(w),
167
- s,
159
+ return /* @__PURE__ */ o("div", { "data-slot": "well-metadata-form", className: G("flex flex-col gap-3", y), children: [
160
+ /* @__PURE__ */ n("div", { className: "text-sm font-medium", children: u > 0 ? g(u) : s }),
161
+ m.map(S),
162
+ C,
168
163
  /* @__PURE__ */ o("div", { className: "mt-auto flex gap-2 pt-1", children: [
169
- /* @__PURE__ */ n(x, { variant: "default", size: "sm", disabled: m === 0, onClick: k, children: b }),
170
- /* @__PURE__ */ n(x, { variant: "outline", size: "sm", disabled: m === 0, onClick: p, children: l })
164
+ /* @__PURE__ */ n(x, { variant: "default", size: "sm", disabled: u === 0, onClick: k, children: b }),
165
+ /* @__PURE__ */ n(x, { variant: "outline", size: "sm", disabled: u === 0, onClick: p, children: l })
171
166
  ] })
172
167
  ] });
173
168
  }
174
169
  export {
175
- le as WellMetadataForm
170
+ ce as WellMetadataForm
176
171
  };
177
172
  //# sourceMappingURL=WellMetadataForm.js.map