@stonecrop/atable 0.34.0 → 0.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/index.css +81 -44
- package/dist/atable.js +127 -123
- package/dist/atable.js.map +1 -1
- package/dist/src/components/ACell.vue.d.ts.map +1 -1
- package/dist/src/components/ARow.vue.d.ts +24 -0
- package/dist/src/components/ARow.vue.d.ts.map +1 -1
- package/dist/src/components/ATable.vue.d.ts +2810 -4
- package/dist/src/components/ATable.vue.d.ts.map +1 -1
- package/dist/src/components/ATableHeader.vue.d.ts.map +1 -1
- package/dist/src/components/ATableLoading.vue.d.ts.map +1 -1
- package/dist/src/components/ATableLoadingBar.vue.d.ts.map +1 -1
- package/dist/src/components/ATableModal.vue.d.ts.map +1 -1
- package/dist/src/stores/table.d.ts +24 -0
- package/dist/src/stores/table.d.ts.map +1 -1
- package/dist/src/types/index.d.ts +7 -0
- package/dist/src/types/index.d.ts.map +1 -1
- package/package.json +4 -4
package/dist/atable.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"atable.js","names":["$attrs"],"sources":["../src/linkSearchableText.ts","../src/resolveFilterType.ts","../src/utils.ts","../src/stores/table.ts","../src/components/ACell.vue","../src/components/ACell.vue","../src/components/AGanttCell.vue","../src/components/AGanttCell.vue","../src/icons/index.ts","../src/components/ARowActions.vue","../src/components/ARowActions.vue","../src/components/ARow.vue","../src/components/ARow.vue","../src/components/AGanttConnection.vue","../src/components/AGanttConnection.vue","../src/components/ATableColumnFilter.vue","../src/components/ATableColumnFilter.vue","../src/components/ATableHeader.vue","../src/components/ATableHeader.vue","../src/components/ATableModal.vue","../src/components/ATableModal.vue","../src/components/ATablePaginationFooter.vue","../src/components/ATablePaginationFooter.vue","../src/composables/table-pagination.ts","../src/schemaToColumns.ts","../src/components/ATable.vue","../src/components/ATable.vue","../src/components/ATableLoading.vue","../src/components/ATableLoadingBar.vue","../src/index.ts"],"sourcesContent":["/**\n * Normalize a scalar cell value to a non-empty string, or nothing.\n *\n * Rejecting objects is what the haystack wants: a nested value has no single textual form, and\n * `String()` on one contributes `[object Object]`, which matches a search for \"object\" and nothing\n * a user would actually type.\n */\nfunction scalarText(value: unknown): string | undefined {\n\tif (value == null || typeof value === 'object') return undefined\n\tif (typeof value === 'string') return value === '' ? undefined : value\n\tif (typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint') {\n\t\treturn String(value)\n\t}\n\treturn undefined\n}\n\n/**\n * Build the substring-search haystack for a link column cell.\n * Server middleware enriches inline FKs to `{ id, displayText }`; search both.\n * @public\n */\nexport function linkSearchableText(cellValue: unknown): string {\n\tif (cellValue == null || cellValue === '') return ''\n\n\t// `in` rather than an assertion to `Record<string, unknown>`: the assertion claims the value has\n\t// string keys of unknown type, which is narrower than `object` and so is a claim this function\n\t// cannot make about a cell it did not build.\n\tif (typeof cellValue === 'object') {\n\t\tconst parts: string[] = []\n\t\tif ('id' in cellValue) {\n\t\t\tconst id = scalarText(cellValue.id)\n\t\t\tif (id !== undefined) parts.push(id)\n\t\t}\n\t\tif ('displayText' in cellValue) {\n\t\t\tconst displayText = scalarText(cellValue.displayText)\n\t\t\tif (displayText !== undefined) parts.push(displayText)\n\t\t}\n\t\treturn parts.join(' ')\n\t}\n\n\treturn scalarText(cellValue) ?? ''\n}\n","import { componentCategory, type ComponentCategory } from '@stonecrop/schema'\n\nimport type { TableColumn } from './types'\n\n/** Filter widget type derived from a component's semantic category. */\nexport type ResolvedFilterType = 'text' | 'select' | 'number' | 'date' | 'dateRange' | 'checkbox' | 'component'\n\nconst CATEGORY_FILTER: Record<ComponentCategory, Exclude<ResolvedFilterType, 'component'>> = {\n\ttext: 'text',\n\tnumber: 'number',\n\tboolean: 'checkbox',\n\tdate: 'date',\n\tdatetime: 'dateRange',\n\tselect: 'select',\n\tcode: 'text',\n\tlink: 'text',\n\tattach: 'text',\n\tquantity: 'number',\n\tcurrency: 'number',\n}\n\n/**\n * Resolve the filter widget and filter logic type for a column.\n * Explicit `filterType` wins; otherwise derive from the component category.\n * @public\n */\nexport function resolveFilterType(column: Pick<TableColumn, 'filterType' | 'component'>): ResolvedFilterType {\n\tif (column.filterType) return column.filterType\n\tconst category = componentCategory(column.component)\n\tif (category) return CATEGORY_FILTER[category]\n\treturn 'text'\n}\n","export const isHtmlString = (htmlString: string) => {\n\tconst $document = new DOMParser().parseFromString(htmlString, 'text/html')\n\treturn Array.from($document.body.childNodes).some(node => node.nodeType === 1)\n}\n\nexport const generateHash = (length = 8) => {\n\treturn Array.from({ length }, () => Math.floor(Math.random() * 16).toString(16)).join('')\n}\n\n/**\n * Render a composite quantity value (`{ qty, uom }`, see `QuantityValue` in `@stonecrop/aform`)\n * as `\"<qty> <uom>\"`. Shared by the two paths a quantity column can reach formatting through:\n * the `format` that `schemaToColumns` attaches, and the table store's category-based default.\n */\nexport const formatQuantity = (value: any): string => {\n\tif (value === null || value === undefined) return ''\n\tif (typeof value === 'object') {\n\t\tconst qty = value.qty ?? ''\n\t\tconst uom = value.uom ?? ''\n\t\treturn uom ? `${qty} ${uom}`.trim() : String(qty)\n\t}\n\treturn String(value)\n}\n\n/**\n * Render a composite currency value (`{ amount, currency }`, see `CurrencyValue` in\n * `@stonecrop/aform`) as `\"<amount> <currency>\"`. `currency` is an AFormLinkValue FK reference —\n * its `displayText` is preferred, falling back to `id`. Shared by the two paths a currency column\n * can reach formatting through: the `format` that `schemaToColumns` attaches, and the table\n * store's category-based default.\n */\nexport const formatCurrency = (value: any): string => {\n\tif (value === null || value === undefined) return ''\n\tif (typeof value === 'object') {\n\t\tconst amount = value.amount ?? ''\n\t\tconst currency = value.currency?.displayText ?? value.currency?.id ?? ''\n\t\treturn currency ? `${amount} ${currency}`.trim() : String(amount)\n\t}\n\treturn String(value)\n}\n","import { defineStore } from 'pinia'\nimport { componentCategory } from '@stonecrop/schema'\nimport type { BadgeDescriptor } from '@stonecrop/schema'\nimport { type CSSProperties, computed, ref } from 'vue'\n\nimport { linkSearchableText } from '../linkSearchableText'\nimport type {\n\tCellContext,\n\tConnectionHandle,\n\tConnectionPath,\n\tGanttBarInfo,\n\tGanttDragEvent,\n\tTableColumn,\n\tTableConfig,\n\tTableDisplay,\n\tTableModal,\n\tTableRow,\n} from '../types'\nimport { resolveFilterType } from '../resolveFilterType'\nimport { formatCurrency, formatQuantity, generateHash } from '../utils'\n\n/**\n * Represents the state of a single filter\n * @public\n */\nexport interface FilterState {\n\t/** The main filter value */\n\tvalue: any\n\t/** Start value for date range filters */\n\tstartValue?: any\n\t/** End value for date range filters */\n\tendValue?: any\n}\n\n/**\n * Record mapping column indices to their filter states\n * @public\n */\nexport type FilterStateRecord = Record<number, FilterState>\n\n// Quantity columns hold a composite `{ qty, uom, ... }` value (see `QuantityValue` in\n// `@stonecrop/aform`); numeric comparisons (filtering, sorting) operate on `qty`.\n//\n// Currency columns hold a composite `{ amount, currency, baseAmount, ... }` value (see\n// `CurrencyValue` in `@stonecrop/aform`), and a single column routinely mixes currencies —\n// comparing raw `amount` would rank 5 EUR equal to 5 USD and match 100 JPY against a `> 100`\n// filter. `baseAmount` is the whole reason the value carries one: it restates every row in the\n// record's base currency, which is the only axis on which they are comparable. Fall back to\n// `amount` for a value that predates the base conversion (or was authored without one).\nfunction toComparableNumber(cellValue: unknown): number {\n\tif (cellValue !== null && typeof cellValue === 'object') {\n\t\tif ('qty' in cellValue) return Number(cellValue.qty)\n\t\tif ('baseAmount' in cellValue && (cellValue as { baseAmount: unknown }).baseAmount != null) {\n\t\t\treturn Number((cellValue as { baseAmount: unknown }).baseAmount)\n\t\t}\n\t\tif ('amount' in cellValue) return Number((cellValue as { amount: unknown }).amount)\n\t}\n\treturn Number(cellValue)\n}\n\nfunction isNodeOpen(rowIndex: number, treeDisplay: TableDisplay[]): boolean {\n\tconst row = treeDisplay[rowIndex]\n\tif (row.isRoot) {\n\t\treturn true // Root nodes are always open\n\t}\n\n\tif (row.parent === null || row.parent === undefined) {\n\t\treturn true\n\t}\n\n\tconst parentIndex = row.parent\n\tif (parentIndex < 0 || parentIndex >= treeDisplay.length) {\n\t\treturn false\n\t}\n\n\tconst parent = treeDisplay[parentIndex]\n\t// Node is open if parent's children are open AND parent itself is open\n\treturn (parent.childrenOpen || false) && isNodeOpen(parentIndex, treeDisplay)\n}\n\nfunction applyFilter(cellValue: any, filter: FilterState, column: TableColumn): boolean {\n\tconst filterType = resolveFilterType(column)\n\tconst value = filter.value\n\n\tif (!value && filterType !== 'dateRange' && filterType !== 'checkbox') return true\n\n\tswitch (filterType) {\n\t\tcase 'text': {\n\t\t\tconst searchableText = column.linkDoctype\n\t\t\t\t? linkSearchableText(cellValue)\n\t\t\t\t: typeof cellValue === 'object' && cellValue !== null\n\t\t\t\t\t? Object.values(cellValue).join(' ')\n\t\t\t\t\t: String(cellValue || '')\n\t\t\treturn searchableText.toLowerCase().includes(String(value).toLowerCase())\n\t\t}\n\n\t\tcase 'number': {\n\t\t\tconst numValue = toComparableNumber(cellValue)\n\t\t\tconst filterNum = Number(value)\n\t\t\treturn !isNaN(numValue) && !isNaN(filterNum) && numValue === filterNum\n\t\t}\n\n\t\tcase 'select':\n\t\t\treturn cellValue === value\n\n\t\tcase 'checkbox':\n\t\t\t// For checkbox filter, if checked (true), show only truthy values\n\t\t\t// If unchecked (false/undefined), show all values\n\t\t\tif (value === true) {\n\t\t\t\treturn !!cellValue\n\t\t\t}\n\t\t\treturn true\n\n\t\tcase 'date': {\n\t\t\t// Handle both timestamp numbers and date strings\n\t\t\tlet cellDate: Date\n\t\t\tif (typeof cellValue === 'number') {\n\t\t\t\t// Apply the same year transformation as in the format function\n\t\t\t\tconst originalDate = new Date(cellValue)\n\t\t\t\tconst currentYear = new Date().getFullYear()\n\t\t\t\tcellDate = new Date(currentYear, originalDate.getMonth(), originalDate.getDate())\n\t\t\t} else {\n\t\t\t\tcellDate = new Date(String(cellValue))\n\t\t\t}\n\t\t\tconst filterDate = new Date(String(value))\n\t\t\treturn cellDate.toDateString() === filterDate.toDateString()\n\t\t}\n\n\t\tcase 'dateRange': {\n\t\t\tconst startValue = filter.startValue\n\t\t\tconst endValue = filter.endValue\n\t\t\tif (!startValue && !endValue) return true\n\n\t\t\t// Handle both timestamp numbers and date strings\n\t\t\tlet cellDateRange: Date\n\t\t\tif (typeof cellValue === 'number') {\n\t\t\t\t// Apply the same year transformation as in the format function\n\t\t\t\tconst originalDate = new Date(cellValue)\n\t\t\t\tconst currentYear = new Date().getFullYear()\n\t\t\t\tcellDateRange = new Date(currentYear, originalDate.getMonth(), originalDate.getDate())\n\t\t\t} else {\n\t\t\t\tcellDateRange = new Date(String(cellValue))\n\t\t\t}\n\t\t\tif (startValue && cellDateRange < new Date(String(startValue))) return false\n\t\t\tif (endValue && cellDateRange > new Date(String(endValue))) return false\n\n\t\t\treturn true\n\t\t}\n\n\t\tdefault:\n\t\t\treturn true\n\t}\n}\n\n/**\n * Compute the CSS indentation for a tree-table cell. Pure helper (captures no store state);\n * imported directly by cell components rather than exposed on the store's public return.\n * @internal\n */\nexport function getIndent(colIndex: number, indentLevel?: number): string {\n\tif (indentLevel && colIndex === 0 && indentLevel > 0) {\n\t\treturn `${indentLevel}ch`\n\t} else {\n\t\treturn 'inherit'\n\t}\n}\n\n/**\n * Create a table store\n * @param initData - Initial data for the table store\n * @returns table store instance\n * @public\n */\nexport const createTableStore = (initData: {\n\tcolumns: TableColumn[]\n\trows: TableRow[]\n\tid?: string\n\tconfig?: TableConfig\n\tmodal?: TableModal\n\tlinkResolver?: ((doctype: string, id: string) => Promise<string | undefined>) | null\n}) => {\n\tconst id = initData.id || generateHash()\n\tconst linkResolver = initData.linkResolver ?? null\n\tconst createStore = defineStore(`table-${id}`, () => {\n\t\tconst createDisplayObject = () => {\n\t\t\tconst defaultDisplay: TableDisplay[] = [Object.assign({}, { rowModified: false })]\n\n\t\t\t// TODO: (typing) is this type correct for the parent set?\n\t\t\tconst parents = new Set<string | number>()\n\t\t\tfor (let rowIndex = 0; rowIndex < rows.value.length; rowIndex++) {\n\t\t\t\tconst row = rows.value[rowIndex]\n\t\t\t\tif (row.parent !== null && row.parent !== undefined) {\n\t\t\t\t\tparents.add(row.parent)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Helper function to check if a row has gantt data\n\t\t\tconst hasGanttData = (rowIndex: number): boolean => {\n\t\t\t\treturn rows.value[rowIndex]?.gantt !== undefined\n\t\t\t}\n\n\t\t\t// Helper function to check if any descendant has gantt data\n\t\t\tconst hasGanttDescendant = (rowIndex: number): boolean => {\n\t\t\t\tfor (let i = 0; i < rows.value.length; i++) {\n\t\t\t\t\tif (rows.value[i].parent === rowIndex) {\n\t\t\t\t\t\tif (hasGanttData(i) || hasGanttDescendant(i)) {\n\t\t\t\t\t\t\treturn true\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\t// Helper function to determine if children should be open based on expansion mode\n\t\t\tconst shouldChildrenBeOpen = (rowIndex: number): boolean => {\n\t\t\t\tconst currentConfig = config.value\n\t\t\t\tconst expansionMode =\n\t\t\t\t\tcurrentConfig.view === 'tree' || currentConfig.view === 'tree-gantt'\n\t\t\t\t\t\t? currentConfig.defaultTreeExpansion\n\t\t\t\t\t\t: undefined\n\n\t\t\t\tif (!expansionMode) return true // Default behavior - start expanded (leaf mode)\n\n\t\t\t\tswitch (expansionMode) {\n\t\t\t\t\tcase 'root':\n\t\t\t\t\t\treturn false // Only root nodes are visible, all children start collapsed\n\t\t\t\t\tcase 'branch':\n\t\t\t\t\t\t// Only expand if this node leads to gantt nodes OR if this node itself has gantt data AND has gantt children\n\t\t\t\t\t\treturn hasGanttDescendant(rowIndex)\n\t\t\t\t\tcase 'leaf':\n\t\t\t\t\t\treturn true // All nodes should be expanded\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn true // Default to expanded if unknown mode\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (let rowIndex = 0; rowIndex < rows.value.length; rowIndex++) {\n\t\t\t\tconst row = rows.value[rowIndex]\n\t\t\t\tconst isRootNode = row.parent === null || row.parent === undefined\n\t\t\t\tconst isParentNode = parents.has(rowIndex)\n\n\t\t\t\tdefaultDisplay[rowIndex] = {\n\t\t\t\t\tchildrenOpen: shouldChildrenBeOpen(rowIndex),\n\t\t\t\t\texpanded: false,\n\t\t\t\t\tindent: row.indent || 0,\n\t\t\t\t\tisParent: isParentNode,\n\t\t\t\t\tisRoot: isRootNode,\n\t\t\t\t\trowModified: false,\n\t\t\t\t\topen: isRootNode, // This will be recalculated later for non-root nodes\n\t\t\t\t\tparent: row.parent,\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn defaultDisplay\n\t\t}\n\n\t\t// state\n\t\tconst columns = ref(initData.columns)\n\t\tconst rows = ref(initData.rows)\n\t\tconst config = ref<TableConfig>(initData.config || {})\n\n\t\t// Track row modifications and expand states separately from the computed display\n\t\tconst rowModifications = ref<Record<number, boolean>>({})\n\t\tconst rowExpandStates = ref<Record<number, { childrenOpen?: boolean; expanded?: boolean }>>({})\n\n\t\tconst table = computed(() => {\n\t\t\tconst tableData: Record<string, any> = {}\n\t\t\tfor (const [colIndex, column] of columns.value.entries()) {\n\t\t\t\tfor (const [rowIndex, row] of rows.value.entries()) {\n\t\t\t\t\ttableData[`${colIndex}:${rowIndex}`] = row[column.name]\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn tableData\n\t\t})\n\n\t\tconst display = computed({\n\t\t\tget: () => {\n\t\t\t\tconst baseDisplay = createDisplayObject()\n\n\t\t\t\t// Apply persistent modifications and expand states\n\t\t\t\tfor (let i = 0; i < baseDisplay.length; i++) {\n\t\t\t\t\tif (rowModifications.value[i]) {\n\t\t\t\t\t\tbaseDisplay[i].rowModified = rowModifications.value[i]\n\t\t\t\t\t}\n\t\t\t\t\tif (rowExpandStates.value[i]) {\n\t\t\t\t\t\tif (rowExpandStates.value[i].childrenOpen !== undefined) {\n\t\t\t\t\t\t\tbaseDisplay[i].childrenOpen = rowExpandStates.value[i].childrenOpen!\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (rowExpandStates.value[i].expanded !== undefined) {\n\t\t\t\t\t\t\tbaseDisplay[i].expanded = rowExpandStates.value[i].expanded!\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Calculate 'open' property for tree view based on parent's childrenOpen state\n\t\t\t\tif (isTreeView.value) {\n\t\t\t\t\t// Helper function to check if all ancestors are open\n\n\t\t\t\t\tfor (let i = 0; i < baseDisplay.length; i++) {\n\t\t\t\t\t\tconst row = baseDisplay[i]\n\t\t\t\t\t\tif (!row.isRoot) {\n\t\t\t\t\t\t\tbaseDisplay[i].open = isNodeOpen(i, baseDisplay)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn baseDisplay\n\t\t\t},\n\t\t\tset: (newDisplay: TableDisplay[]) => {\n\t\t\t\t// Only update if the new display is different from the current one; also avoids recursive updates\n\t\t\t\tif (JSON.stringify(newDisplay) !== JSON.stringify(display.value)) {\n\t\t\t\t\tdisplay.value = newDisplay\n\t\t\t\t}\n\t\t\t},\n\t\t})\n\n\t\tconst modal = ref<TableModal>(initData.modal || { visible: false })\n\t\tconst updates = ref<Record<string, string>>({})\n\t\tconst ganttBars = ref<GanttBarInfo[]>([])\n\t\tconst connectionHandles = ref<ConnectionHandle[]>([])\n\t\tconst connectionPaths = ref<ConnectionPath[]>([])\n\t\tconst sortState = ref<{ column: number | null; direction: 'asc' | 'desc' | null }>({\n\t\t\tcolumn: null,\n\t\t\tdirection: null,\n\t\t})\n\t\tconst filterState = ref<FilterStateRecord>({})\n\n\t\t// getters\n\t\tconst hasPinnedColumns = computed(() => columns.value.some(col => col.pinned))\n\t\tconst isGanttView = computed(() => config.value.view === 'gantt' || config.value.view === 'tree-gantt')\n\t\tconst isTreeView = computed(() => config.value.view === 'tree' || config.value.view === 'tree-gantt')\n\t\tconst isDependencyGraphEnabled = computed(() => {\n\t\t\tconst currentConfig = config.value\n\t\t\treturn currentConfig.view === 'gantt' || currentConfig.view === 'tree-gantt'\n\t\t\t\t? currentConfig.dependencyGraph !== false\n\t\t\t\t: true\n\t\t})\n\n\t\tconst numberedRowWidth = computed(() => {\n\t\t\tconst indent = Math.ceil(rows.value.length / 100 + 1)\n\t\t\treturn `${indent}ch`\n\t\t})\n\n\t\tconst zeroColumn = computed(() =>\n\t\t\tconfig.value.view ? ['list', 'tree', 'tree-gantt', 'list-expansion'].includes(config.value.view) : false\n\t\t)\n\n\t\tconst filteredRows = computed(() => {\n\t\t\tlet filtered: Array<TableRow & { originalIndex: number }> = rows.value.map((row, originalIndex) => ({\n\t\t\t\t...row,\n\t\t\t\toriginalIndex,\n\t\t\t}))\n\n\t\t\t// Apply filters\n\t\t\tObject.entries(filterState.value).forEach(([colIndexStr, filter]) => {\n\t\t\t\tconst colIndex = parseInt(colIndexStr)\n\t\t\t\tconst column = columns.value[colIndex]\n\n\t\t\t\tif (!column) return\n\n\t\t\t\t// Skip if filter has no value (except for dateRange and checkbox which can have different value structures)\n\t\t\t\tconst hasFilterValue =\n\t\t\t\t\tfilter.value ||\n\t\t\t\t\tfilter.startValue ||\n\t\t\t\t\tfilter.endValue ||\n\t\t\t\t\t(resolveFilterType(column) === 'checkbox' && filter.value !== undefined)\n\n\t\t\t\tif (!hasFilterValue) return\n\n\t\t\t\tfiltered = filtered.filter(row => {\n\t\t\t\t\tconst cellValue = row[column.name]\n\t\t\t\t\treturn applyFilter(cellValue, filter, column)\n\t\t\t\t})\n\t\t\t})\n\n\t\t\t// Apply sorting if active\n\t\t\tif (sortState.value.column !== null && sortState.value.direction) {\n\t\t\t\tconst column = columns.value[sortState.value.column]\n\t\t\t\tconst direction = sortState.value.direction\n\n\t\t\t\tfiltered.sort((a, b) => {\n\t\t\t\t\tlet aVal = a[column.name]\n\t\t\t\t\tlet bVal = b[column.name]\n\n\t\t\t\t\tif (aVal === null || aVal === undefined) aVal = ''\n\t\t\t\t\tif (bVal === null || bVal === undefined) bVal = ''\n\n\t\t\t\t\tconst aNum = toComparableNumber(aVal)\n\t\t\t\t\tconst bNum = toComparableNumber(bVal)\n\t\t\t\t\tconst isNumeric = !isNaN(aNum) && !isNaN(bNum) && aVal !== '' && bVal !== ''\n\n\t\t\t\t\tif (isNumeric) {\n\t\t\t\t\t\treturn direction === 'asc' ? aNum - bNum : bNum - aNum\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst aStr = String(aVal).toLowerCase()\n\t\t\t\t\t\tconst bStr = String(bVal).toLowerCase()\n\t\t\t\t\t\treturn direction === 'asc' ? aStr.localeCompare(bStr) : bStr.localeCompare(aStr)\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t}\n\n\t\t\treturn filtered\n\t\t})\n\n\t\t// actions\n\t\tconst getCellData = (colIndex: number, rowIndex: number): any => table.value[`${colIndex}:${rowIndex}`]\n\t\tconst setCellData = (colIndex: number, rowIndex: number, value: any) => {\n\t\t\tconst index = `${colIndex}:${rowIndex}`\n\t\t\tconst col = columns.value[colIndex]\n\n\t\t\tif (table.value[index] !== value) {\n\t\t\t\trowModifications.value[rowIndex] = true\n\t\t\t}\n\n\t\t\ttable.value[index] = value\n\t\t\t// Create a new row object to ensure reactivity\n\t\t\trows.value[rowIndex] = {\n\t\t\t\t...rows.value[rowIndex],\n\t\t\t\t[col.name]: value,\n\t\t\t}\n\t\t}\n\n\t\tconst updateRows = (newRows: TableRow[]) => {\n\t\t\trows.value = newRows\n\t\t}\n\n\t\tconst setCellText = (colIndex: number, rowIndex: number, value: string) => {\n\t\t\tconst index = `${colIndex}:${rowIndex}`\n\n\t\t\tif (table.value[index] !== value) {\n\t\t\t\trowModifications.value[rowIndex] = true\n\t\t\t\tupdates.value[index] = value\n\t\t\t}\n\t\t}\n\n\t\tconst getHeaderCellStyle = (column: TableColumn): CSSProperties => {\n\t\t\tconst isLastCol = columns.value.indexOf(column) === columns.value.length - 1\n\n\t\t\t// if the table is full width, the last column should not be resizable;\n\t\t\t// ref: https://github.com/agritheory/stonecrop/pull/196#issuecomment-2503762641\n\n\t\t\tconst isResizable = config.value.fullWidth ? column.resizable && !isLastCol : column.resizable\n\n\t\t\treturn {\n\t\t\t\twidth: column.width || '40ch',\n\t\t\t\ttextAlign: column.align || 'center',\n\t\t\t\t...(isResizable && {\n\t\t\t\t\tresize: 'horizontal',\n\t\t\t\t\toverflow: 'hidden',\n\t\t\t\t\twhiteSpace: 'nowrap',\n\t\t\t\t}),\n\t\t\t}\n\t\t}\n\n\t\tconst resizeColumn = (colIndex: number, newWidth: number) => {\n\t\t\tif (colIndex < 0 || colIndex >= columns.value.length) return\n\n\t\t\tconst minWidth = 40\n\t\t\tconst finalWidth = Math.max(newWidth, minWidth)\n\n\t\t\tcolumns.value[colIndex] = {\n\t\t\t\t...columns.value[colIndex],\n\t\t\t\twidth: `${finalWidth}px`,\n\t\t\t}\n\t\t}\n\n\t\tconst isRowGantt = (rowIndex: number) => {\n\t\t\tconst row = rows.value[rowIndex]\n\t\t\treturn isGanttView.value && row.gantt !== undefined\n\t\t}\n\n\t\tconst isRowVisible = (rowIndex: number) => {\n\t\t\treturn !isTreeView.value || display.value[rowIndex].isRoot || display.value[rowIndex].open\n\t\t}\n\n\t\tconst getRowExpandSymbol = (rowIndex: number) => {\n\t\t\tif (!isTreeView.value && config.value.view !== 'list-expansion') {\n\t\t\t\treturn ''\n\t\t\t}\n\n\t\t\tif (isTreeView.value && (display.value[rowIndex].isRoot || display.value[rowIndex].isParent)) {\n\t\t\t\treturn display.value[rowIndex].childrenOpen ? '▼' : '►'\n\t\t\t}\n\n\t\t\tif (config.value.view === 'list-expansion') {\n\t\t\t\treturn display.value[rowIndex].expanded ? '▼' : '►'\n\t\t\t}\n\n\t\t\treturn ''\n\t\t}\n\n\t\tconst toggleRowExpand = (rowIndex: number) => {\n\t\t\tif (isTreeView.value) {\n\t\t\t\tconst currentState = rowExpandStates.value[rowIndex] || {}\n\t\t\t\tconst currentChildrenOpen = currentState.childrenOpen ?? display.value[rowIndex].childrenOpen\n\t\t\t\tconst newChildrenOpen = !currentChildrenOpen\n\n\t\t\t\trowExpandStates.value[rowIndex] = {\n\t\t\t\t\t...currentState,\n\t\t\t\t\tchildrenOpen: newChildrenOpen,\n\t\t\t\t}\n\n\t\t\t\t// If we're closing, recursively close all descendant nodes\n\t\t\t\tif (!newChildrenOpen) {\n\t\t\t\t\tcloseDescendants(rowIndex)\n\t\t\t\t}\n\t\t\t} else if (config.value.view === 'list-expansion') {\n\t\t\t\tconst currentState = rowExpandStates.value[rowIndex] || {}\n\t\t\t\tconst currentExpanded = currentState.expanded ?? display.value[rowIndex].expanded\n\t\t\t\trowExpandStates.value[rowIndex] = {\n\t\t\t\t\t...currentState,\n\t\t\t\t\texpanded: !currentExpanded,\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst closeDescendants = (parentRowIndex: number) => {\n\t\t\tfor (let index = 0; index < rows.value.length; index++) {\n\t\t\t\tif (display.value[index].parent === parentRowIndex) {\n\t\t\t\t\tconst childState = rowExpandStates.value[index] || {}\n\t\t\t\t\trowExpandStates.value[index] = {\n\t\t\t\t\t\t...childState,\n\t\t\t\t\t\tchildrenOpen: false,\n\t\t\t\t\t}\n\t\t\t\t\t// Recursively close this child's descendants\n\t\t\t\t\tcloseDescendants(index)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst getCellDisplayValue = (colIndex: number, rowIndex: number) => {\n\t\t\tconst cellData = getCellData(colIndex, rowIndex)\n\t\t\treturn getFormattedValue(colIndex, rowIndex, cellData)\n\t\t}\n\n\t\tconst getFormattedValue = (colIndex: number, rowIndex: number, value: any) => {\n\t\t\tconst column = columns.value[colIndex]\n\t\t\tconst row = rows.value[rowIndex]\n\t\t\tconst format = column.format\n\n\t\t\tif (!format) {\n\t\t\t\t// Default cell formatting comes from the component's category; anything without an\n\t\t\t\t// opinion (including an unknown component) renders the raw value.\n\t\t\t\tconst category = componentCategory(column.component)\n\t\t\t\tif (category === 'boolean') return value ? '✓' : '✗'\n\t\t\t\tif (category === 'date') return value != null ? new Date(String(value)).toLocaleDateString() : value\n\t\t\t\tif (category === 'datetime') return value != null ? new Date(String(value)).toLocaleString() : value\n\t\t\t\tif (category === 'quantity') return formatQuantity(value)\n\t\t\t\tif (category === 'currency') return formatCurrency(value)\n\t\t\t\treturn value\n\t\t\t}\n\n\t\t\tif (typeof format === 'function') {\n\t\t\t\treturn format(value, { table: table.value, row, column })\n\t\t\t} else if (typeof format === 'string') {\n\t\t\t\t// parse format function from string. The alias keeps the declaration on one line so the\n\t\t\t\t// disable directive below stays attached to the Function call it covers.\n\t\t\t\ttype DeserializedFormat = (value: any, context?: CellContext) => string | BadgeDescriptor\n\t\t\t\t// oxlint-disable-next-line @typescript-eslint/no-implied-eval\n\t\t\t\tconst formatFn: DeserializedFormat = Function(`\"use strict\";return (${format})`)()\n\t\t\t\treturn formatFn(value, { table: table.value, row, column })\n\t\t\t}\n\n\t\t\treturn value\n\t\t}\n\n\t\tconst closeModal = (event: MouseEvent) => {\n\t\t\tif (!(event.target instanceof Node)) {\n\t\t\t\t// if the target is not a node, it's probably a custom click event to Document or Window\n\t\t\t\t// err on the side of closing the modal in that case\n\t\t\t\tif (modal.value.visible) modal.value.visible = false\n\t\t\t} else if (!modal.value.parent?.contains(event.target)) {\n\t\t\t\tif (modal.value.visible) modal.value.visible = false\n\t\t\t}\n\t\t}\n\n\t\tconst updateGanttBar = (event: GanttDragEvent) => {\n\t\t\t// update the local gantt bar cache\n\t\t\tconst ganttBar = rows.value[event.rowIndex]?.gantt\n\t\t\tif (ganttBar) {\n\t\t\t\tif (event.type === 'resize') {\n\t\t\t\t\tif (event.edge === 'start') {\n\t\t\t\t\t\tganttBar.startIndex = event.newStart\n\t\t\t\t\t\tganttBar.endIndex = event.end\n\t\t\t\t\t\tganttBar.colspan = ganttBar.endIndex - ganttBar.startIndex\n\t\t\t\t\t} else if (event.edge === 'end') {\n\t\t\t\t\t\tganttBar.startIndex = event.start\n\t\t\t\t\t\tganttBar.endIndex = event.newEnd\n\t\t\t\t\t\tganttBar.colspan = ganttBar.endIndex - ganttBar.startIndex\n\t\t\t\t\t}\n\t\t\t\t} else if (event.type === 'bar') {\n\t\t\t\t\tganttBar.startIndex = event.newStart\n\t\t\t\t\tganttBar.endIndex = event.newEnd\n\t\t\t\t\tganttBar.colspan = ganttBar.endIndex - ganttBar.startIndex\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst registerGanttBar = (barInfo: GanttBarInfo) => {\n\t\t\tconst existingIndex = ganttBars.value.findIndex(bar => bar.id === barInfo.id)\n\t\t\tif (existingIndex >= 0) {\n\t\t\t\t// @ts-expect-error TODO: for some reason, the IDE is expecting an unref'd value\n\t\t\t\tganttBars.value[existingIndex] = barInfo\n\t\t\t} else {\n\t\t\t\t// @ts-expect-error TODO: for some reason, the IDE is expecting an unref'd value\n\t\t\t\tganttBars.value.push(barInfo)\n\t\t\t}\n\t\t}\n\n\t\tconst unregisterGanttBar = (barId: string) => {\n\t\t\tconst index = ganttBars.value.findIndex(bar => bar.id === barId)\n\t\t\tif (index >= 0) {\n\t\t\t\tganttBars.value.splice(index, 1)\n\t\t\t}\n\t\t}\n\n\t\tconst registerConnectionHandle = (handleInfo: ConnectionHandle) => {\n\t\t\tconst existingIndex = connectionHandles.value.findIndex(handle => handle.id === handleInfo.id)\n\t\t\tif (existingIndex >= 0) {\n\t\t\t\t// @ts-expect-error TODO: for some reason, the IDE is expecting an unref'd value\n\t\t\t\tconnectionHandles.value[existingIndex] = handleInfo\n\t\t\t} else {\n\t\t\t\t// @ts-expect-error TODO: for some reason, the IDE is expecting an unref'd value\n\t\t\t\tconnectionHandles.value.push(handleInfo)\n\t\t\t}\n\t\t}\n\n\t\tconst unregisterConnectionHandle = (handleId: string) => {\n\t\t\tconst index = connectionHandles.value.findIndex(handle => handle.id === handleId)\n\t\t\tif (index >= 0) {\n\t\t\t\tconnectionHandles.value.splice(index, 1)\n\t\t\t}\n\t\t}\n\n\t\tconst createConnection = (\n\t\t\tfromHandleId: string,\n\t\t\ttoHandleId: string,\n\t\t\toptions?: { style?: ConnectionPath['style']; label?: string }\n\t\t) => {\n\t\t\tconst fromHandle = connectionHandles.value.find(h => h.id === fromHandleId)\n\t\t\tconst toHandle = connectionHandles.value.find(h => h.id === toHandleId)\n\n\t\t\tif (!fromHandle || !toHandle) {\n\t\t\t\tconsole.warn('Cannot create connection: handle not found')\n\t\t\t\treturn null\n\t\t\t}\n\n\t\t\tconst connection: ConnectionPath = {\n\t\t\t\tid: `connection-${fromHandleId}-${toHandleId}`,\n\t\t\t\tfrom: {\n\t\t\t\t\tbarId: fromHandle.barId,\n\t\t\t\t\tside: fromHandle.side,\n\t\t\t\t},\n\t\t\t\tto: {\n\t\t\t\t\tbarId: toHandle.barId,\n\t\t\t\t\tside: toHandle.side,\n\t\t\t\t},\n\t\t\t\tstyle: options?.style,\n\t\t\t\tlabel: options?.label,\n\t\t\t}\n\n\t\t\tconnectionPaths.value.push(connection)\n\t\t\treturn connection\n\t\t}\n\n\t\tconst deleteConnection = (connectionId: string) => {\n\t\t\tconst index = connectionPaths.value.findIndex(conn => conn.id === connectionId)\n\t\t\tif (index >= 0) {\n\t\t\t\tconnectionPaths.value.splice(index, 1)\n\t\t\t\treturn true\n\t\t\t}\n\t\t\treturn false\n\t\t}\n\n\t\tconst getConnectionsForBar = (barId: string) => {\n\t\t\treturn connectionPaths.value.filter(conn => conn.from.barId === barId || conn.to.barId === barId)\n\t\t}\n\n\t\tconst getHandlesForBar = (barId: string) => {\n\t\t\treturn connectionHandles.value.filter(handle => handle.barId === barId)\n\t\t}\n\n\t\tconst sortByColumn = (colIndex: number) => {\n\t\t\tconst column = columns.value[colIndex]\n\t\t\tif (column.sortable === false) return\n\n\t\t\tlet newDirection: 'asc' | 'desc'\n\t\t\tif (sortState.value.column === colIndex) {\n\t\t\t\tif (sortState.value.direction === 'asc') {\n\t\t\t\t\tnewDirection = 'desc'\n\t\t\t\t} else {\n\t\t\t\t\tnewDirection = 'asc'\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tnewDirection = 'asc'\n\t\t\t}\n\n\t\t\tsortState.value.column = colIndex\n\t\t\tsortState.value.direction = newDirection\n\n\t\t\t// Note: The actual sorting is now handled in the filteredRows computed property\n\t\t\t// This ensures that sorting works on filtered data without modifying the original rows\n\t\t}\n\n\t\tconst setFilter = (colIndex: number, filter: FilterState) => {\n\t\t\tif (!filter.value && !filter.startValue && !filter.endValue) {\n\t\t\t\t// Remove filter if empty\n\t\t\t\tdelete filterState.value[colIndex]\n\t\t\t} else {\n\t\t\t\tfilterState.value[colIndex] = filter\n\t\t\t}\n\t\t}\n\n\t\tconst clearFilter = (colIndex: number) => {\n\t\t\tdelete filterState.value[colIndex]\n\t\t}\n\n\t\t// Row action methods\n\n\t\t/**\n\t\t * Add a new row to the table.\n\t\t * @param rowData - Optional partial row data to initialize the new row with\n\t\t * @param position - Where to insert the row: 'start', 'end', or a specific index\n\t\t * @returns The index of the newly added row\n\t\t */\n\t\tconst addRow = (rowData?: Partial<TableRow>, position: 'start' | 'end' | number = 'end'): number => {\n\t\t\t// Create a new row with default empty values for each column\n\t\t\tconst newRow: TableRow = {}\n\t\t\tfor (const column of columns.value) {\n\t\t\t\tnewRow[column.name] = ''\n\t\t\t}\n\n\t\t\t// Merge in any provided row data\n\t\t\tif (rowData) {\n\t\t\t\tObject.assign(newRow, rowData)\n\t\t\t}\n\n\t\t\tlet insertIndex: number\n\t\t\tif (position === 'start') {\n\t\t\t\tinsertIndex = 0\n\t\t\t\trows.value.unshift(newRow)\n\t\t\t} else if (position === 'end') {\n\t\t\t\tinsertIndex = rows.value.length\n\t\t\t\trows.value.push(newRow)\n\t\t\t} else {\n\t\t\t\tinsertIndex = Math.max(0, Math.min(position, rows.value.length))\n\t\t\t\trows.value.splice(insertIndex, 0, newRow)\n\t\t\t}\n\n\t\t\treturn insertIndex\n\t\t}\n\n\t\t/**\n\t\t * Delete a row from the table.\n\t\t * @param rowIndex - The index of the row to delete\n\t\t * @returns The deleted row, or null if the index was invalid\n\t\t */\n\t\tconst deleteRow = (rowIndex: number): TableRow | null => {\n\t\t\tif (rowIndex < 0 || rowIndex >= rows.value.length) {\n\t\t\t\treturn null\n\t\t\t}\n\n\t\t\tconst [deletedRow] = rows.value.splice(rowIndex, 1)\n\n\t\t\t// Clean up row modifications tracking for the deleted row\n\t\t\tdelete rowModifications.value[rowIndex]\n\t\t\tdelete rowExpandStates.value[rowIndex]\n\n\t\t\t// Shift modification/expand state indices for rows after the deleted one\n\t\t\tconst newModifications: Record<number, boolean> = {}\n\t\t\tconst newExpandStates: Record<number, { childrenOpen?: boolean; expanded?: boolean }> = {}\n\n\t\t\tfor (const [key, value] of Object.entries(rowModifications.value)) {\n\t\t\t\tconst idx = parseInt(key)\n\t\t\t\tif (idx > rowIndex) {\n\t\t\t\t\tnewModifications[idx - 1] = value\n\t\t\t\t} else {\n\t\t\t\t\tnewModifications[idx] = value\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (const [key, value] of Object.entries(rowExpandStates.value)) {\n\t\t\t\tconst idx = parseInt(key)\n\t\t\t\tif (idx > rowIndex) {\n\t\t\t\t\tnewExpandStates[idx - 1] = value\n\t\t\t\t} else {\n\t\t\t\t\tnewExpandStates[idx] = value\n\t\t\t\t}\n\t\t\t}\n\n\t\t\trowModifications.value = newModifications\n\t\t\trowExpandStates.value = newExpandStates\n\n\t\t\treturn deletedRow\n\t\t}\n\n\t\t/**\n\t\t * Duplicate a row in the table.\n\t\t * @param rowIndex - The index of the row to duplicate\n\t\t * @returns The index of the new duplicated row, or -1 if the index was invalid\n\t\t */\n\t\tconst duplicateRow = (rowIndex: number): number => {\n\t\t\tif (rowIndex < 0 || rowIndex >= rows.value.length) {\n\t\t\t\treturn -1\n\t\t\t}\n\n\t\t\t// Deep clone the row data\n\t\t\tconst originalRow = rows.value[rowIndex]\n\t\t\tconst duplicatedRow: TableRow = JSON.parse(JSON.stringify(originalRow))\n\n\t\t\t// Insert the duplicated row after the original\n\t\t\tconst newIndex = rowIndex + 1\n\t\t\trows.value.splice(newIndex, 0, duplicatedRow)\n\n\t\t\treturn newIndex\n\t\t}\n\n\t\t/**\n\t\t * Insert a new row above the specified row.\n\t\t * @param rowIndex - The index of the row to insert above\n\t\t * @param rowData - Optional partial row data to initialize the new row with\n\t\t * @returns The index of the newly inserted row\n\t\t */\n\t\tconst insertRowAbove = (rowIndex: number, rowData?: Partial<TableRow>): number => {\n\t\t\tconst insertIndex = Math.max(0, rowIndex)\n\t\t\treturn addRow(rowData, insertIndex)\n\t\t}\n\n\t\t/**\n\t\t * Insert a new row below the specified row.\n\t\t * @param rowIndex - The index of the row to insert below\n\t\t * @param rowData - Optional partial row data to initialize the new row with\n\t\t * @returns The index of the newly inserted row\n\t\t */\n\t\tconst insertRowBelow = (rowIndex: number, rowData?: Partial<TableRow>): number => {\n\t\t\tconst insertIndex = Math.min(rowIndex + 1, rows.value.length)\n\t\t\treturn addRow(rowData, insertIndex)\n\t\t}\n\n\t\t/**\n\t\t * Move a row from one position to another.\n\t\t * @param fromIndex - The current index of the row to move\n\t\t * @param toIndex - The target index to move the row to\n\t\t * @returns true if the move was successful, false otherwise\n\t\t */\n\t\tconst moveRow = (fromIndex: number, toIndex: number): boolean => {\n\t\t\t// Validate indices\n\t\t\tif (\n\t\t\t\tfromIndex < 0 ||\n\t\t\t\tfromIndex >= rows.value.length ||\n\t\t\t\ttoIndex < 0 ||\n\t\t\t\ttoIndex >= rows.value.length ||\n\t\t\t\tfromIndex === toIndex\n\t\t\t) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\t// Remove the row from its current position\n\t\t\tconst [movedRow] = rows.value.splice(fromIndex, 1)\n\n\t\t\t// Insert at the new position\n\t\t\trows.value.splice(toIndex, 0, movedRow)\n\n\t\t\t// Update row modification and expand state indices\n\t\t\tconst newModifications: Record<number, boolean> = {}\n\t\t\tconst newExpandStates: Record<number, { childrenOpen?: boolean; expanded?: boolean }> = {}\n\n\t\t\tfor (const [key, value] of Object.entries(rowModifications.value)) {\n\t\t\t\tconst idx = parseInt(key)\n\t\t\t\tlet newIdx = idx\n\n\t\t\t\tif (idx === fromIndex) {\n\t\t\t\t\t// The moved row\n\t\t\t\t\tnewIdx = toIndex\n\t\t\t\t} else if (fromIndex < toIndex) {\n\t\t\t\t\t// Moving down: rows between fromIndex and toIndex shift up\n\t\t\t\t\tif (idx > fromIndex && idx <= toIndex) {\n\t\t\t\t\t\tnewIdx = idx - 1\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Moving up: rows between toIndex and fromIndex shift down\n\t\t\t\t\tif (idx >= toIndex && idx < fromIndex) {\n\t\t\t\t\t\tnewIdx = idx + 1\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tnewModifications[newIdx] = value\n\t\t\t}\n\n\t\t\tfor (const [key, value] of Object.entries(rowExpandStates.value)) {\n\t\t\t\tconst idx = parseInt(key)\n\t\t\t\tlet newIdx = idx\n\n\t\t\t\tif (idx === fromIndex) {\n\t\t\t\t\tnewIdx = toIndex\n\t\t\t\t} else if (fromIndex < toIndex) {\n\t\t\t\t\tif (idx > fromIndex && idx <= toIndex) {\n\t\t\t\t\t\tnewIdx = idx - 1\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif (idx >= toIndex && idx < fromIndex) {\n\t\t\t\t\t\tnewIdx = idx + 1\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tnewExpandStates[newIdx] = value\n\t\t\t}\n\n\t\t\trowModifications.value = newModifications\n\t\t\trowExpandStates.value = newExpandStates\n\n\t\t\treturn true\n\t\t}\n\n\t\treturn {\n\t\t\t// state\n\t\t\tcolumns,\n\t\t\tconfig,\n\t\t\tconnectionHandles,\n\t\t\tconnectionPaths,\n\t\t\tdisplay,\n\t\t\tfilterState,\n\t\t\tganttBars,\n\t\t\tmodal,\n\t\t\trows,\n\t\t\tsortState,\n\t\t\ttable,\n\t\t\tupdates,\n\n\t\t\t// getters\n\t\t\tfilteredRows,\n\t\t\thasPinnedColumns,\n\t\t\tisGanttView,\n\t\t\tisTreeView,\n\t\t\tisDependencyGraphEnabled,\n\t\t\tnumberedRowWidth,\n\t\t\tzeroColumn,\n\n\t\t\t// resolver\n\t\t\tlinkResolver,\n\n\t\t\t// actions\n\t\t\taddRow,\n\t\t\tclearFilter,\n\t\t\tcloseModal,\n\t\t\tcreateConnection,\n\t\t\tdeleteConnection,\n\t\t\tdeleteRow,\n\t\t\tduplicateRow,\n\t\t\tgetCellData,\n\t\t\tgetCellDisplayValue,\n\t\t\tgetConnectionsForBar,\n\t\t\tgetFormattedValue,\n\t\t\tgetHandlesForBar,\n\t\t\tgetHeaderCellStyle,\n\t\t\tgetRowExpandSymbol,\n\t\t\tinsertRowAbove,\n\t\t\tinsertRowBelow,\n\t\t\tisRowGantt,\n\t\t\tisRowVisible,\n\t\t\tmoveRow,\n\t\t\tregisterConnectionHandle,\n\t\t\tregisterGanttBar,\n\t\t\tresizeColumn,\n\t\t\tsetCellData,\n\t\t\tsetCellText,\n\t\t\tsetFilter,\n\t\t\tsortByColumn,\n\t\t\ttoggleRowExpand,\n\t\t\tunregisterConnectionHandle,\n\t\t\tunregisterGanttBar,\n\t\t\tupdateGanttBar,\n\t\t\tupdateRows,\n\t\t}\n\t})\n\n\treturn createStore()\n}\n","<template>\n\t<td\n\t\tref=\"cell\"\n\t\t:data-colindex=\"colIndex\"\n\t\t:data-rowindex=\"rowIndex\"\n\t\t:data-editable=\"column.edit\"\n\t\t:contenteditable=\"isContentEditable\"\n\t\t:tabindex=\"tabIndex\"\n\t\t:spellcheck=\"false\"\n\t\t:style=\"cellStyle\"\n\t\tclass=\"atable-cell\"\n\t\t:class=\"cellClasses\"\n\t\t@focus=\"onFocus\"\n\t\t@paste=\"updateCellData\"\n\t\t@input=\"debouncedUpdateCellData\"\n\t\t@click=\"onCellClick\">\n\t\t<component :is=\"column.cellComponent\" v-if=\"column.cellComponent\" v-bind=\"cellComponentBindings\" />\n\t\t<component :is=\"'ABadge'\" v-else-if=\"badgeFromFormat\" v-bind=\"badgeFromFormat\" presentation=\"cell-fill\" />\n\t\t<component :is=\"'ABadge'\" v-else-if=\"badgeFromOptions\" v-bind=\"badgeFromOptions\" />\n\t\t<span v-else-if=\"isHtmlValue\" v-html=\"renderedValue\" />\n\t\t<span v-else>{{ renderedValue }}</span>\n\t</td>\n</template>\n\n<script setup lang=\"ts\">\nimport { KeypressHandlers, defaultKeypressHandlers, useKeyboardNav } from '@stonecrop/utilities'\nimport { isBadgeDescriptor, hasBadgeOptions } from '@stonecrop/schema'\nimport { useDebounceFn, useElementBounding } from '@vueuse/core'\nimport { computed, type CSSProperties, onMounted, ref, useTemplateRef, nextTick } from 'vue'\n\nimport { createTableStore, getIndent } from '../stores/table'\nimport { isHtmlString } from '../utils'\n\nconst {\n\tcolIndex,\n\trowIndex,\n\tstore,\n\taddNavigation = true,\n\ttabIndex = 0,\n\tpinned = false,\n\tdebounce = 300,\n} = defineProps<{\n\tcolIndex: number\n\trowIndex: number\n\tstore: ReturnType<typeof createTableStore>\n\taddNavigation?: boolean | KeypressHandlers\n\ttabIndex?: number\n\tpinned?: boolean\n\tdebounce?: number\n}>()\n\nconst cellRef = useTemplateRef<HTMLTableCellElement>('cell')\n\n// keep a shallow copy of the original cell value for comparison\nconst originalData = store.getCellData(colIndex, rowIndex)\nconst currentData = ref('')\nconst cellModified = ref(false)\n\nconst column = store.columns[colIndex]\nconst row = store.rows[rowIndex]\n\nconst textAlign = column.align || 'center'\nconst cellWidth = column.width || '40ch'\n\nconst displayValue = computed(() => store.getCellDisplayValue(colIndex, rowIndex))\n\n// Resolved display text for Link columns with bare string IDs.\n// null = not yet resolved or not applicable; non-null overrides displayValue.\nconst resolvedText = ref<string | null>(null)\n\nonMounted(() => {\n\tif (!column.linkDoctype) return\n\tconst raw = store.getCellData(colIndex, rowIndex)\n\n\t// Server returns link fields as { id, displayText } objects.\n\tif (raw !== null && raw !== undefined && typeof raw === 'object') {\n\t\tconst obj = raw as Record<string, unknown>\n\t\tconst display = obj.displayText ?? obj.id\n\t\tif (typeof display === 'string' || typeof display === 'number') {\n\t\t\tresolvedText.value = String(display)\n\t\t}\n\t\treturn\n\t}\n\n\t// Bare string ID — call the resolver if available.\n\tconst resolver = store.linkResolver\n\tif (!resolver || typeof raw !== 'string' || raw === '') return\n\tvoid resolver(column.linkDoctype, raw).then(text => {\n\t\tif (text != null) resolvedText.value = text\n\t\treturn text\n\t})\n})\n\nconst renderedValue = computed(() => resolvedText.value ?? displayValue.value)\n\nconst badgeFromFormat = computed(() => {\n\tif (column.cellComponent) return undefined\n\tconst value = renderedValue.value\n\treturn isBadgeDescriptor(value) ? value : undefined\n})\n\nconst badgeFromOptions = computed(() => {\n\tif (column.cellComponent || badgeFromFormat.value) return undefined\n\tif (!hasBadgeOptions(column.options)) return undefined\n\treturn {\n\t\tvalue: store.getCellData(colIndex, rowIndex),\n\t\toptions: column.options,\n\t\tpresentation: 'cell-fill' as const,\n\t}\n})\n\nconst usesBadgeDisplay = computed(\n\t() => !!column.cellComponent || badgeFromFormat.value !== undefined || hasBadgeOptions(column.options)\n)\n\nconst isContentEditable = computed(() => column.edit && !usesBadgeDisplay.value)\n\nconst cellComponentBindings = computed(() => {\n\tconst props = { ...column.cellComponentProps }\n\tif (column.cellComponent !== 'ABadge') {\n\t\treturn { ...props, value: renderedValue.value }\n\t}\n\tif (isBadgeDescriptor(renderedValue.value)) {\n\t\treturn { presentation: 'cell-fill' as const, ...props, ...renderedValue.value }\n\t}\n\t// ABadge resolves its own label, so it needs the badge map as well as the value — and the value\n\t// has to be the stored one, because badge maps are keyed on that rather than on formatted text.\n\treturn {\n\t\tpresentation: 'cell-fill' as const,\n\t\toptions: column.options,\n\t\t...props,\n\t\tvalue: store.getCellData(colIndex, rowIndex),\n\t}\n})\n\nconst isHtmlValue = computed(() => {\n\t// TODO: check if display value is a native DOM element\n\treturn typeof renderedValue.value === 'string' ? isHtmlString(renderedValue.value) : false\n})\n\nconst cellStyle = computed((): CSSProperties => {\n\treturn {\n\t\ttextAlign,\n\t\twidth: cellWidth,\n\t\tfontWeight: !cellModified.value ? 'inherit' : 'bold',\n\t\tpaddingLeft: getIndent(colIndex, store.display[rowIndex]?.indent),\n\t}\n})\n\nconst cellClasses = computed(() => {\n\treturn {\n\t\t'sticky-column': pinned,\n\t\t'cell-modified': cellModified.value,\n\t\t'atable-cell--badge-fill': usesBadgeDisplay.value,\n\t}\n})\n\nconst onCellClick = () => {\n\t// First, select all text if the cell is editable\n\tselectAllText()\n\n\t// Then handle modal display (original showModal behavior)\n\tshowModal()\n}\n\nconst showModal = () => {\n\tconst { left, bottom, width, height } = useElementBounding(cellRef)\n\n\tif (column.mask) {\n\t\t// TODO: add masking to cell values\n\t\t// column.mask(event)\n\t}\n\n\tif (column.modalComponent) {\n\t\tstore.$patch(state => {\n\t\t\tstate.modal.visible = true\n\t\t\tstate.modal.colIndex = colIndex\n\t\t\tstate.modal.rowIndex = rowIndex\n\t\t\t// Snapshot the cell's box as it was when the modal opened. These are refs, and assigning\n\t\t\t// them raw happened to work only because reactive reads unwrap refs — which also left the\n\t\t\t// stored values live, tracking the cell for as long as the modal stayed open.\n\t\t\tstate.modal.left = left.value\n\t\t\tstate.modal.bottom = bottom.value\n\t\t\tstate.modal.width = width.value\n\t\t\tstate.modal.height = height.value\n\t\t\tstate.modal.cell = cellRef.value\n\n\t\t\tif (typeof column.modalComponent === 'function') {\n\t\t\t\t// `table` is a computed, so Pinia exposes it as a getter — it is not on `$state`, which\n\t\t\t\t// is what $patch hands back. Reading it off the store is what passes a real table.\n\t\t\t\tstate.modal.component = column.modalComponent({ table: store.table, row, column })\n\t\t\t} else {\n\t\t\t\tstate.modal.component = column.modalComponent\n\t\t\t}\n\n\t\t\tstate.modal.componentProps = column.modalComponentExtraProps\n\t\t})\n\t}\n}\n\nif (addNavigation) {\n\tlet handlers = {\n\t\t...defaultKeypressHandlers,\n\t\t'keydown.f2': showModal,\n\t\t'keydown.alt.up': showModal,\n\t\t'keydown.alt.down': showModal,\n\t\t'keydown.alt.left': showModal,\n\t\t'keydown.alt.right': showModal,\n\t}\n\n\tif (typeof addNavigation === 'object') {\n\t\thandlers = {\n\t\t\t...handlers,\n\t\t\t...addNavigation,\n\t\t}\n\t}\n\n\tuseKeyboardNav([\n\t\t{\n\t\t\tselectors: cellRef,\n\t\t\thandlers: handlers,\n\t\t},\n\t])\n}\n\n// const updateData = (event: Event) => {\n// \tif (event) {\n// \t\t// custom components need to handle their own updateData, this is the default\n// \t\tif (!column.component) {\n// \t\t\tstore.setCellData(colIndex, rowIndex, cell.value.innerHTML)\n// \t\t}\n// \t\tcellModified.value = true\n// \t}\n// }\n\nconst selectAllText = () => {\n\tif (cellRef.value && column.edit) {\n\t\t// Use the Selection API to select all text content in the contenteditable cell\n\t\tconst selection = window.getSelection()\n\t\tif (selection) {\n\t\t\ttry {\n\t\t\t\tconst range = document.createRange()\n\t\t\t\tif (range.selectNodeContents) {\n\t\t\t\t\trange.selectNodeContents(cellRef.value)\n\t\t\t\t\tselection.removeAllRanges()\n\t\t\t\t\tselection.addRange(range)\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Fallback for environments where Range API is not fully supported\n\t\t\t\t// This is expected in some test environments\n\t\t\t}\n\t\t}\n\t}\n}\n\nconst onFocus = () => {\n\tif (cellRef.value) {\n\t\tcurrentData.value = cellRef.value.textContent!\n\t\t// Select all text when the cell receives focus\n\t\tselectAllText()\n\t}\n}\n\nconst saveCursorPosition = () => {\n\ttry {\n\t\tconst selection = window.getSelection()\n\t\tif (selection && selection.rangeCount > 0 && cellRef.value) {\n\t\t\tconst range = selection.getRangeAt(0)\n\t\t\t// Save the offset from the start of the cell\n\t\t\tconst preCaretRange = range.cloneRange()\n\t\t\tif (preCaretRange.selectNodeContents && preCaretRange.setEnd) {\n\t\t\t\tpreCaretRange.selectNodeContents(cellRef.value)\n\t\t\t\tpreCaretRange.setEnd(range.endContainer, range.endOffset)\n\t\t\t\treturn preCaretRange.toString().length\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// Fallback for environments where Selection API is not fully supported\n\t}\n\treturn 0\n}\n\nconst restoreCursorPosition = (position: number) => {\n\tif (!cellRef.value) return\n\n\ttry {\n\t\tconst selection = window.getSelection()\n\t\tif (!selection) return\n\n\t\tlet charIndex = 0\n\t\tconst walker = document.createTreeWalker\n\t\t\t? document.createTreeWalker(cellRef.value, NodeFilter.SHOW_TEXT, null)\n\t\t\t: null\n\n\t\tif (!walker) return\n\n\t\tlet node: Node | null\n\t\tlet range: Range | null = null\n\n\t\twhile ((node = walker.nextNode())) {\n\t\t\tconst textNode = node as Text\n\t\t\tconst nextCharIndex = charIndex + textNode.textContent.length\n\n\t\t\tif (position <= nextCharIndex) {\n\t\t\t\trange = document.createRange()\n\t\t\t\tif (range.setStart && range.setEnd) {\n\t\t\t\t\trange.setStart(textNode, position - charIndex)\n\t\t\t\t\trange.setEnd(textNode, position - charIndex)\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tcharIndex = nextCharIndex\n\t\t}\n\n\t\tif (range && selection.removeAllRanges && selection.addRange) {\n\t\t\tselection.removeAllRanges()\n\t\t\tselection.addRange(range)\n\t\t}\n\t} catch {\n\t\t// Fallback for environments where DOM APIs are not fully supported\n\t}\n}\n\nconst updateCellData = (payload: Event) => {\n\tif (!column.edit) return\n\n\tconst target = payload.target as HTMLTableCellElement\n\tif (target.textContent === currentData.value) {\n\t\treturn\n\t}\n\n\t// Save cursor position before updating\n\tconst cursorPosition = saveCursorPosition()\n\n\tcurrentData.value = target.textContent!\n\n\t// only apply changes if the cell value has changed after being mounted\n\tif (column.format) {\n\t\tcellModified.value = target.textContent !== store.getFormattedValue(colIndex, rowIndex, originalData)\n\t\t// TODO: need to setup reverse format function?\n\t\tstore.setCellText(colIndex, rowIndex, target.textContent)\n\t} else {\n\t\tcellModified.value = target.textContent !== originalData\n\t\tstore.setCellData(colIndex, rowIndex, target.textContent)\n\t}\n\n\t// Use nextTick to restore cursor position after Vue's reactive updates but before browser repaint\n\tvoid nextTick().then(() => {\n\t\treturn restoreCursorPosition(cursorPosition)\n\t})\n}\n\nconst debouncedUpdateCellData = useDebounceFn(updateCellData, debounce)\n\ndefineExpose({\n\tcurrentData,\n})\n</script>\n\n<style>\n.atable-cell {\n\tborder-radius: 0px;\n\tbox-sizing: border-box;\n\tmargin: 0px;\n\toutline: none;\n\tbox-shadow: none;\n\tcolor: var(--sc-cell-text-color);\n\toverflow: hidden;\n\tpadding-left: 0.5ch !important;\n\tpadding-right: 0.5ch;\n\tpadding-top: var(--sc-atable-row-padding);\n\tpadding-bottom: var(--sc-atable-row-padding);\n\tborder-spacing: 0px;\n\tborder-collapse: collapse;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\torder: 1;\n\twhite-space: nowrap;\n\tmax-width: 40ch;\n\tborder-top: 1px solid var(--sc-row-border-color);\n\tmargin-left: 1px;\n}\n.atable-cell a {\n\tcolor: var(--sc-cell-text-color);\n\ttext-decoration: none;\n}\n.atable-cell:focus,\n.atable-cell:focus-within {\n\tbackground-color: var(--sc-focus-cell-background);\n\toutline-width: var(--sc-atable-cell-border-width);\n\toutline-style: solid;\n\toutline-offset: calc(var(--sc-atable-cell-border-width) * -1);\n\toutline-color: var(--sc-focus-cell-outline);\n\tbox-shadow: none;\n\toverflow: hidden;\n\ttext-wrap: nowrap;\n\tbox-sizing: border-box;\n}\n.cell-modified {\n\tfont-weight: bold;\n\tfont-style: italic;\n}\n.cell-modified-highlight {\n\tbackground-color: var(--sc-cell-changed-color);\n}\n.atable-cell--badge-fill {\n\tpadding: 0 !important;\n\tmargin-left: 0;\n}\n</style>\n","<template>\n\t<td\n\t\tref=\"cell\"\n\t\t:data-colindex=\"colIndex\"\n\t\t:data-rowindex=\"rowIndex\"\n\t\t:data-editable=\"column.edit\"\n\t\t:contenteditable=\"isContentEditable\"\n\t\t:tabindex=\"tabIndex\"\n\t\t:spellcheck=\"false\"\n\t\t:style=\"cellStyle\"\n\t\tclass=\"atable-cell\"\n\t\t:class=\"cellClasses\"\n\t\t@focus=\"onFocus\"\n\t\t@paste=\"updateCellData\"\n\t\t@input=\"debouncedUpdateCellData\"\n\t\t@click=\"onCellClick\">\n\t\t<component :is=\"column.cellComponent\" v-if=\"column.cellComponent\" v-bind=\"cellComponentBindings\" />\n\t\t<component :is=\"'ABadge'\" v-else-if=\"badgeFromFormat\" v-bind=\"badgeFromFormat\" presentation=\"cell-fill\" />\n\t\t<component :is=\"'ABadge'\" v-else-if=\"badgeFromOptions\" v-bind=\"badgeFromOptions\" />\n\t\t<span v-else-if=\"isHtmlValue\" v-html=\"renderedValue\" />\n\t\t<span v-else>{{ renderedValue }}</span>\n\t</td>\n</template>\n\n<script setup lang=\"ts\">\nimport { KeypressHandlers, defaultKeypressHandlers, useKeyboardNav } from '@stonecrop/utilities'\nimport { isBadgeDescriptor, hasBadgeOptions } from '@stonecrop/schema'\nimport { useDebounceFn, useElementBounding } from '@vueuse/core'\nimport { computed, type CSSProperties, onMounted, ref, useTemplateRef, nextTick } from 'vue'\n\nimport { createTableStore, getIndent } from '../stores/table'\nimport { isHtmlString } from '../utils'\n\nconst {\n\tcolIndex,\n\trowIndex,\n\tstore,\n\taddNavigation = true,\n\ttabIndex = 0,\n\tpinned = false,\n\tdebounce = 300,\n} = defineProps<{\n\tcolIndex: number\n\trowIndex: number\n\tstore: ReturnType<typeof createTableStore>\n\taddNavigation?: boolean | KeypressHandlers\n\ttabIndex?: number\n\tpinned?: boolean\n\tdebounce?: number\n}>()\n\nconst cellRef = useTemplateRef<HTMLTableCellElement>('cell')\n\n// keep a shallow copy of the original cell value for comparison\nconst originalData = store.getCellData(colIndex, rowIndex)\nconst currentData = ref('')\nconst cellModified = ref(false)\n\nconst column = store.columns[colIndex]\nconst row = store.rows[rowIndex]\n\nconst textAlign = column.align || 'center'\nconst cellWidth = column.width || '40ch'\n\nconst displayValue = computed(() => store.getCellDisplayValue(colIndex, rowIndex))\n\n// Resolved display text for Link columns with bare string IDs.\n// null = not yet resolved or not applicable; non-null overrides displayValue.\nconst resolvedText = ref<string | null>(null)\n\nonMounted(() => {\n\tif (!column.linkDoctype) return\n\tconst raw = store.getCellData(colIndex, rowIndex)\n\n\t// Server returns link fields as { id, displayText } objects.\n\tif (raw !== null && raw !== undefined && typeof raw === 'object') {\n\t\tconst obj = raw as Record<string, unknown>\n\t\tconst display = obj.displayText ?? obj.id\n\t\tif (typeof display === 'string' || typeof display === 'number') {\n\t\t\tresolvedText.value = String(display)\n\t\t}\n\t\treturn\n\t}\n\n\t// Bare string ID — call the resolver if available.\n\tconst resolver = store.linkResolver\n\tif (!resolver || typeof raw !== 'string' || raw === '') return\n\tvoid resolver(column.linkDoctype, raw).then(text => {\n\t\tif (text != null) resolvedText.value = text\n\t\treturn text\n\t})\n})\n\nconst renderedValue = computed(() => resolvedText.value ?? displayValue.value)\n\nconst badgeFromFormat = computed(() => {\n\tif (column.cellComponent) return undefined\n\tconst value = renderedValue.value\n\treturn isBadgeDescriptor(value) ? value : undefined\n})\n\nconst badgeFromOptions = computed(() => {\n\tif (column.cellComponent || badgeFromFormat.value) return undefined\n\tif (!hasBadgeOptions(column.options)) return undefined\n\treturn {\n\t\tvalue: store.getCellData(colIndex, rowIndex),\n\t\toptions: column.options,\n\t\tpresentation: 'cell-fill' as const,\n\t}\n})\n\nconst usesBadgeDisplay = computed(\n\t() => !!column.cellComponent || badgeFromFormat.value !== undefined || hasBadgeOptions(column.options)\n)\n\nconst isContentEditable = computed(() => column.edit && !usesBadgeDisplay.value)\n\nconst cellComponentBindings = computed(() => {\n\tconst props = { ...column.cellComponentProps }\n\tif (column.cellComponent !== 'ABadge') {\n\t\treturn { ...props, value: renderedValue.value }\n\t}\n\tif (isBadgeDescriptor(renderedValue.value)) {\n\t\treturn { presentation: 'cell-fill' as const, ...props, ...renderedValue.value }\n\t}\n\t// ABadge resolves its own label, so it needs the badge map as well as the value — and the value\n\t// has to be the stored one, because badge maps are keyed on that rather than on formatted text.\n\treturn {\n\t\tpresentation: 'cell-fill' as const,\n\t\toptions: column.options,\n\t\t...props,\n\t\tvalue: store.getCellData(colIndex, rowIndex),\n\t}\n})\n\nconst isHtmlValue = computed(() => {\n\t// TODO: check if display value is a native DOM element\n\treturn typeof renderedValue.value === 'string' ? isHtmlString(renderedValue.value) : false\n})\n\nconst cellStyle = computed((): CSSProperties => {\n\treturn {\n\t\ttextAlign,\n\t\twidth: cellWidth,\n\t\tfontWeight: !cellModified.value ? 'inherit' : 'bold',\n\t\tpaddingLeft: getIndent(colIndex, store.display[rowIndex]?.indent),\n\t}\n})\n\nconst cellClasses = computed(() => {\n\treturn {\n\t\t'sticky-column': pinned,\n\t\t'cell-modified': cellModified.value,\n\t\t'atable-cell--badge-fill': usesBadgeDisplay.value,\n\t}\n})\n\nconst onCellClick = () => {\n\t// First, select all text if the cell is editable\n\tselectAllText()\n\n\t// Then handle modal display (original showModal behavior)\n\tshowModal()\n}\n\nconst showModal = () => {\n\tconst { left, bottom, width, height } = useElementBounding(cellRef)\n\n\tif (column.mask) {\n\t\t// TODO: add masking to cell values\n\t\t// column.mask(event)\n\t}\n\n\tif (column.modalComponent) {\n\t\tstore.$patch(state => {\n\t\t\tstate.modal.visible = true\n\t\t\tstate.modal.colIndex = colIndex\n\t\t\tstate.modal.rowIndex = rowIndex\n\t\t\t// Snapshot the cell's box as it was when the modal opened. These are refs, and assigning\n\t\t\t// them raw happened to work only because reactive reads unwrap refs — which also left the\n\t\t\t// stored values live, tracking the cell for as long as the modal stayed open.\n\t\t\tstate.modal.left = left.value\n\t\t\tstate.modal.bottom = bottom.value\n\t\t\tstate.modal.width = width.value\n\t\t\tstate.modal.height = height.value\n\t\t\tstate.modal.cell = cellRef.value\n\n\t\t\tif (typeof column.modalComponent === 'function') {\n\t\t\t\t// `table` is a computed, so Pinia exposes it as a getter — it is not on `$state`, which\n\t\t\t\t// is what $patch hands back. Reading it off the store is what passes a real table.\n\t\t\t\tstate.modal.component = column.modalComponent({ table: store.table, row, column })\n\t\t\t} else {\n\t\t\t\tstate.modal.component = column.modalComponent\n\t\t\t}\n\n\t\t\tstate.modal.componentProps = column.modalComponentExtraProps\n\t\t})\n\t}\n}\n\nif (addNavigation) {\n\tlet handlers = {\n\t\t...defaultKeypressHandlers,\n\t\t'keydown.f2': showModal,\n\t\t'keydown.alt.up': showModal,\n\t\t'keydown.alt.down': showModal,\n\t\t'keydown.alt.left': showModal,\n\t\t'keydown.alt.right': showModal,\n\t}\n\n\tif (typeof addNavigation === 'object') {\n\t\thandlers = {\n\t\t\t...handlers,\n\t\t\t...addNavigation,\n\t\t}\n\t}\n\n\tuseKeyboardNav([\n\t\t{\n\t\t\tselectors: cellRef,\n\t\t\thandlers: handlers,\n\t\t},\n\t])\n}\n\n// const updateData = (event: Event) => {\n// \tif (event) {\n// \t\t// custom components need to handle their own updateData, this is the default\n// \t\tif (!column.component) {\n// \t\t\tstore.setCellData(colIndex, rowIndex, cell.value.innerHTML)\n// \t\t}\n// \t\tcellModified.value = true\n// \t}\n// }\n\nconst selectAllText = () => {\n\tif (cellRef.value && column.edit) {\n\t\t// Use the Selection API to select all text content in the contenteditable cell\n\t\tconst selection = window.getSelection()\n\t\tif (selection) {\n\t\t\ttry {\n\t\t\t\tconst range = document.createRange()\n\t\t\t\tif (range.selectNodeContents) {\n\t\t\t\t\trange.selectNodeContents(cellRef.value)\n\t\t\t\t\tselection.removeAllRanges()\n\t\t\t\t\tselection.addRange(range)\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Fallback for environments where Range API is not fully supported\n\t\t\t\t// This is expected in some test environments\n\t\t\t}\n\t\t}\n\t}\n}\n\nconst onFocus = () => {\n\tif (cellRef.value) {\n\t\tcurrentData.value = cellRef.value.textContent!\n\t\t// Select all text when the cell receives focus\n\t\tselectAllText()\n\t}\n}\n\nconst saveCursorPosition = () => {\n\ttry {\n\t\tconst selection = window.getSelection()\n\t\tif (selection && selection.rangeCount > 0 && cellRef.value) {\n\t\t\tconst range = selection.getRangeAt(0)\n\t\t\t// Save the offset from the start of the cell\n\t\t\tconst preCaretRange = range.cloneRange()\n\t\t\tif (preCaretRange.selectNodeContents && preCaretRange.setEnd) {\n\t\t\t\tpreCaretRange.selectNodeContents(cellRef.value)\n\t\t\t\tpreCaretRange.setEnd(range.endContainer, range.endOffset)\n\t\t\t\treturn preCaretRange.toString().length\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// Fallback for environments where Selection API is not fully supported\n\t}\n\treturn 0\n}\n\nconst restoreCursorPosition = (position: number) => {\n\tif (!cellRef.value) return\n\n\ttry {\n\t\tconst selection = window.getSelection()\n\t\tif (!selection) return\n\n\t\tlet charIndex = 0\n\t\tconst walker = document.createTreeWalker\n\t\t\t? document.createTreeWalker(cellRef.value, NodeFilter.SHOW_TEXT, null)\n\t\t\t: null\n\n\t\tif (!walker) return\n\n\t\tlet node: Node | null\n\t\tlet range: Range | null = null\n\n\t\twhile ((node = walker.nextNode())) {\n\t\t\tconst textNode = node as Text\n\t\t\tconst nextCharIndex = charIndex + textNode.textContent.length\n\n\t\t\tif (position <= nextCharIndex) {\n\t\t\t\trange = document.createRange()\n\t\t\t\tif (range.setStart && range.setEnd) {\n\t\t\t\t\trange.setStart(textNode, position - charIndex)\n\t\t\t\t\trange.setEnd(textNode, position - charIndex)\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tcharIndex = nextCharIndex\n\t\t}\n\n\t\tif (range && selection.removeAllRanges && selection.addRange) {\n\t\t\tselection.removeAllRanges()\n\t\t\tselection.addRange(range)\n\t\t}\n\t} catch {\n\t\t// Fallback for environments where DOM APIs are not fully supported\n\t}\n}\n\nconst updateCellData = (payload: Event) => {\n\tif (!column.edit) return\n\n\tconst target = payload.target as HTMLTableCellElement\n\tif (target.textContent === currentData.value) {\n\t\treturn\n\t}\n\n\t// Save cursor position before updating\n\tconst cursorPosition = saveCursorPosition()\n\n\tcurrentData.value = target.textContent!\n\n\t// only apply changes if the cell value has changed after being mounted\n\tif (column.format) {\n\t\tcellModified.value = target.textContent !== store.getFormattedValue(colIndex, rowIndex, originalData)\n\t\t// TODO: need to setup reverse format function?\n\t\tstore.setCellText(colIndex, rowIndex, target.textContent)\n\t} else {\n\t\tcellModified.value = target.textContent !== originalData\n\t\tstore.setCellData(colIndex, rowIndex, target.textContent)\n\t}\n\n\t// Use nextTick to restore cursor position after Vue's reactive updates but before browser repaint\n\tvoid nextTick().then(() => {\n\t\treturn restoreCursorPosition(cursorPosition)\n\t})\n}\n\nconst debouncedUpdateCellData = useDebounceFn(updateCellData, debounce)\n\ndefineExpose({\n\tcurrentData,\n})\n</script>\n\n<style>\n.atable-cell {\n\tborder-radius: 0px;\n\tbox-sizing: border-box;\n\tmargin: 0px;\n\toutline: none;\n\tbox-shadow: none;\n\tcolor: var(--sc-cell-text-color);\n\toverflow: hidden;\n\tpadding-left: 0.5ch !important;\n\tpadding-right: 0.5ch;\n\tpadding-top: var(--sc-atable-row-padding);\n\tpadding-bottom: var(--sc-atable-row-padding);\n\tborder-spacing: 0px;\n\tborder-collapse: collapse;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\torder: 1;\n\twhite-space: nowrap;\n\tmax-width: 40ch;\n\tborder-top: 1px solid var(--sc-row-border-color);\n\tmargin-left: 1px;\n}\n.atable-cell a {\n\tcolor: var(--sc-cell-text-color);\n\ttext-decoration: none;\n}\n.atable-cell:focus,\n.atable-cell:focus-within {\n\tbackground-color: var(--sc-focus-cell-background);\n\toutline-width: var(--sc-atable-cell-border-width);\n\toutline-style: solid;\n\toutline-offset: calc(var(--sc-atable-cell-border-width) * -1);\n\toutline-color: var(--sc-focus-cell-outline);\n\tbox-shadow: none;\n\toverflow: hidden;\n\ttext-wrap: nowrap;\n\tbox-sizing: border-box;\n}\n.cell-modified {\n\tfont-weight: bold;\n\tfont-style: italic;\n}\n.cell-modified-highlight {\n\tbackground-color: var(--sc-cell-changed-color);\n}\n.atable-cell--badge-fill {\n\tpadding: 0 !important;\n\tmargin-left: 0;\n}\n</style>\n","<template>\n\t<td class=\"aganttcell\" :colspan=\"colspan\">\n\t\t<div ref=\"container\" class=\"gantt-container\">\n\t\t\t<!-- Draggable gantt bar -->\n\t\t\t<div\n\t\t\t\tref=\"bar\"\n\t\t\t\t:data-rowindex=\"rowIndex\"\n\t\t\t\t:data-colindex=\"colIndex\"\n\t\t\t\tclass=\"gantt-bar\"\n\t\t\t\t:class=\"{ 'is-dragging': isAnyDragging }\"\n\t\t\t\t:style=\"barStyle\"\n\t\t\t\t@mouseenter=\"showConnectionHandles\"\n\t\t\t\t@mouseleave=\"hideConnectionHandles\">\n\t\t\t\t<!-- Connection handles for linking bars - only show if dependency graph is enabled -->\n\t\t\t\t<div\n\t\t\t\t\tv-if=\"store.isDependencyGraphEnabled\"\n\t\t\t\t\tref=\"leftConnectionHandle\"\n\t\t\t\t\tclass=\"connection-handle left-connection-handle\"\n\t\t\t\t\t:class=\"{ visible: isLeftConnectionVisible, 'is-dragging': isLeftConnectionDragging }\"\n\t\t\t\t\t@mousedown.stop=\"startConnectionDrag('left', $event)\">\n\t\t\t\t\t<div class=\"connection-dot\"></div>\n\t\t\t\t</div>\n\n\t\t\t\t<div\n\t\t\t\t\tv-if=\"store.isDependencyGraphEnabled\"\n\t\t\t\t\tref=\"rightConnectionHandle\"\n\t\t\t\t\tclass=\"connection-handle right-connection-handle\"\n\t\t\t\t\t:class=\"{ visible: isRightConnectionVisible, 'is-dragging': isRightConnectionDragging }\"\n\t\t\t\t\t@mousedown.stop=\"startConnectionDrag('right', $event)\">\n\t\t\t\t\t<div class=\"connection-dot\"></div>\n\t\t\t\t</div>\n\n\t\t\t\t<!-- Resize handles for changing bar length -->\n\t\t\t\t<div ref=\"leftResizeHandle\" class=\"resize-handle left-resize-handle\" :class=\"{ 'is-dragging': isLeftResizing }\">\n\t\t\t\t\t<div class=\"handle-grip\"></div>\n\t\t\t\t\t<div class=\"vertical-indicator left-indicator\"></div>\n\t\t\t\t</div>\n\n\t\t\t\t<label v-if=\"label\" class=\"gantt-label\">{{ label }}</label>\n\n\t\t\t\t<div\n\t\t\t\t\tref=\"rightResizeHandle\"\n\t\t\t\t\tclass=\"resize-handle right-resize-handle\"\n\t\t\t\t\t:class=\"{ 'is-dragging': isRightResizing }\">\n\t\t\t\t\t<div class=\"handle-grip\"></div>\n\t\t\t\t\t<div class=\"vertical-indicator right-indicator\"></div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<!-- Connection drag preview line - only show if dependency graph is enabled -->\n\t\t<svg v-if=\"store.isDependencyGraphEnabled && showDragPreview\" :style=\"connectionDragStyle\">\n\t\t\t<line\n\t\t\t\t:x1=\"dragPreview.startX\"\n\t\t\t\t:y1=\"dragPreview.startY\"\n\t\t\t\t:x2=\"dragPreview.endX\"\n\t\t\t\t:y2=\"dragPreview.endY\"\n\t\t\t\tstroke=\"#2196f3\"\n\t\t\t\tstroke-width=\"2\"\n\t\t\t\tstroke-dasharray=\"5,5\" />\n\t\t</svg>\n\t</td>\n</template>\n\n<script setup lang=\"ts\">\nimport { useDraggable, useElementBounding } from '@vueuse/core'\nimport { ref, computed, onMounted, onUnmounted, useTemplateRef, type StyleValue } from 'vue'\n\nimport { createTableStore } from '../stores/table'\nimport type { ConnectionPath } from '../types'\n\nconst {\n\tstore,\n\tcolumnsCount,\n\trowIndex,\n\tcolIndex,\n\tstart = 0,\n\tend = 0,\n\tcolspan = 1,\n\tlabel = '',\n\tcolor = '#cccccc',\n} = defineProps<{\n\tstore: ReturnType<typeof createTableStore>\n\tcolumnsCount: number\n\trowIndex: number\n\tcolIndex: number\n\tstart?: number\n\tend?: number\n\tcolspan?: number\n\tlabel?: string\n\tcolor?: string\n}>()\n\nconst emit = defineEmits<{\n\t'connection:create': [connection: ConnectionPath]\n}>()\n\n// Core refs and state\nconst barColor = ref(color.length >= 6 ? color : '#cccccc')\nconst barId = `gantt-bar-row-${rowIndex}-col-${colIndex}`\n\n// Template refs\nconst containerRef = useTemplateRef<HTMLDivElement>('container')\nconst barRef = useTemplateRef<HTMLDivElement>('bar')\nconst leftResizeHandleRef = useTemplateRef<HTMLDivElement>('leftResizeHandle')\nconst rightResizeHandleRef = useTemplateRef<HTMLDivElement>('rightResizeHandle')\nconst leftConnectionHandleRef = useTemplateRef<HTMLDivElement>('leftConnectionHandle')\nconst rightConnectionHandleRef = useTemplateRef<HTMLDivElement>('rightConnectionHandle')\n\n// Position tracking\nconst { width: totalBarWidth } = useElementBounding(containerRef)\nconst { left: barLeft, right: barRight } = useElementBounding(barRef)\n\n// Bar positioning\nconst currentStart = ref(start)\nconst currentEnd = ref(end || currentStart.value + colspan)\n\n// Drag states\nconst isLeftConnectionVisible = ref(false)\nconst isRightConnectionVisible = ref(false)\nconst isLeftConnectionDragging = ref(false)\nconst isRightConnectionDragging = ref(false)\nconst showDragPreview = ref(false)\nconst dragPreview = ref({ startX: 0, startY: 0, endX: 0, endY: 0 })\n\n// Computed properties\nconst isAnyDragging = computed(() => isBarDragging.value || isLeftResizing.value || isRightResizing.value)\n\nconst pixelsPerColumn = computed(() => (colspan > 0 ? totalBarWidth.value / colspan : 0))\n\nconst barStyle = computed((): StyleValue => {\n\tconst startPercent = (currentStart.value / colspan) * 100\n\tconst endPercent = (currentEnd.value / colspan) * 100\n\treturn {\n\t\tleft: `${startPercent}%`,\n\t\twidth: `${endPercent - startPercent}%`,\n\t\tbackgroundColor: barColor.value,\n\t}\n})\n\nconst connectionDragStyle = computed((): StyleValue => ({\n\tposition: 'fixed',\n\ttop: 0,\n\tleft: 0,\n\twidth: '100vw',\n\theight: '100vh',\n\tpointerEvents: 'none',\n\tzIndex: 1000,\n}))\n\n// Drag setup data\nconst dragStartData = ref({ startX: 0, startPos: 0 })\n\n// Left resize handle dragging\nconst { isDragging: isLeftResizing } = useDraggable(leftResizeHandleRef, {\n\taxis: 'x',\n\tonStart: () => setupDragStart(barLeft.value, currentStart.value),\n\tonMove: ({ x }) => handleLeftResize(x),\n\tonEnd: ({ x }) => finishLeftResize(x),\n})\n\n// Right resize handle dragging\nconst { isDragging: isRightResizing } = useDraggable(rightResizeHandleRef, {\n\taxis: 'x',\n\tonStart: () => setupDragStart(barRight.value, currentEnd.value),\n\tonMove: ({ x }) => handleRightResize(x),\n\tonEnd: ({ x }) => finishRightResize(x),\n})\n\n// Bar movement dragging\nconst { isDragging: isBarDragging } = useDraggable(barRef, {\n\texact: true,\n\taxis: 'x',\n\tonStart: () => setupDragStart(barLeft.value, currentStart.value),\n\tonMove: ({ x }) => handleBarMove(x),\n\tonEnd: ({ x }) => finishBarMove(x),\n})\n\n// Lifecycle\nonMounted(() => {\n\tregisterGanttComponents()\n})\n\nonUnmounted(() => {\n\tunregisterGanttComponents()\n})\n\n// Helper functions\nfunction setupDragStart(startX: number, startPos: number) {\n\tif (barRef.value) barRef.value.style.transition = 'none'\n\tdragStartData.value = { startX, startPos }\n}\n\nfunction handleLeftResize(x: number) {\n\tif (!isLeftResizing.value || !barRef.value) return\n\n\tconst deltaX = x - dragStartData.value.startX\n\tconst deltaColumns = deltaX / pixelsPerColumn.value\n\tconst newStart = Math.max(0, Math.min(currentEnd.value - 1, dragStartData.value.startPos + deltaColumns))\n\n\tbarRef.value.style.left = `${(newStart / colspan) * 100}%`\n\tbarRef.value.style.width = `${((currentEnd.value - newStart) / colspan) * 100}%`\n}\n\nfunction finishLeftResize(x: number) {\n\tif (!barRef.value) return\n\n\tconst deltaX = x - dragStartData.value.startX\n\tconst deltaColumns = Math.round(deltaX / pixelsPerColumn.value)\n\tconst oldStart = currentStart.value\n\tconst newStart = Math.max(0, Math.min(currentEnd.value - 1, dragStartData.value.startPos + deltaColumns))\n\n\tcurrentStart.value = newStart\n\tstore.updateGanttBar({\n\t\trowIndex,\n\t\tcolIndex,\n\t\ttype: 'resize',\n\t\tedge: 'start',\n\t\toldStart,\n\t\tnewStart,\n\t\tend: currentEnd.value,\n\t\tdelta: deltaColumns,\n\t\toldColspan: currentEnd.value - oldStart,\n\t\tnewColspan: currentEnd.value - newStart,\n\t})\n}\n\nfunction handleRightResize(x: number) {\n\tif (!isRightResizing.value || !barRef.value) return\n\n\tconst deltaX = x - dragStartData.value.startX\n\tconst deltaColumns = deltaX / pixelsPerColumn.value\n\tconst newEnd = Math.max(currentStart.value + 1, Math.min(columnsCount, dragStartData.value.startPos + deltaColumns))\n\n\tbarRef.value.style.width = `${((newEnd - currentStart.value) / colspan) * 100}%`\n}\n\nfunction finishRightResize(x: number) {\n\tif (!barRef.value) return\n\n\tconst deltaX = x - dragStartData.value.startX\n\tconst deltaColumns = Math.round(deltaX / pixelsPerColumn.value)\n\tconst oldEnd = currentEnd.value\n\tconst newEnd = Math.max(currentStart.value + 1, Math.min(columnsCount, dragStartData.value.startPos + deltaColumns))\n\n\tcurrentEnd.value = newEnd\n\tstore.updateGanttBar({\n\t\trowIndex,\n\t\tcolIndex,\n\t\ttype: 'resize',\n\t\tedge: 'end',\n\t\toldEnd,\n\t\tnewEnd,\n\t\tstart: currentStart.value,\n\t\tdelta: deltaColumns,\n\t\toldColspan: oldEnd - currentStart.value,\n\t\tnewColspan: newEnd - currentStart.value,\n\t})\n}\n\nfunction handleBarMove(x: number) {\n\tif (!isBarDragging.value || !barRef.value) return\n\n\tconst deltaX = x - dragStartData.value.startX\n\tconst deltaColumns = deltaX / pixelsPerColumn.value\n\tconst barWidth = currentEnd.value - currentStart.value\n\tconst newStart = Math.max(0, Math.min(dragStartData.value.startPos + deltaColumns, columnsCount - barWidth))\n\n\tbarRef.value.style.left = `${(newStart / colspan) * 100}%`\n}\n\nfunction finishBarMove(x: number) {\n\tif (!barRef.value) return\n\n\tconst deltaX = x - dragStartData.value.startX\n\tconst deltaColumns = Math.round(deltaX / pixelsPerColumn.value)\n\tconst barWidth = currentEnd.value - currentStart.value\n\n\tconst oldStart = currentStart.value\n\tconst oldEnd = currentEnd.value\n\tlet newStart = dragStartData.value.startPos + deltaColumns\n\tlet newEnd = newStart + barWidth\n\n\t// Boundary checks\n\tif (newStart < 0) {\n\t\tnewStart = 0\n\t\tnewEnd = barWidth\n\t} else if (newEnd > columnsCount) {\n\t\tnewEnd = columnsCount\n\t\tnewStart = newEnd - barWidth\n\t}\n\n\tcurrentStart.value = newStart\n\tcurrentEnd.value = newEnd\n\n\tstore.updateGanttBar({\n\t\trowIndex,\n\t\tcolIndex,\n\t\ttype: 'bar',\n\t\toldStart,\n\t\toldEnd,\n\t\tnewStart,\n\t\tnewEnd,\n\t\tdelta: deltaColumns,\n\t\tcolspan: newEnd - newStart,\n\t})\n}\n\nfunction registerGanttComponents() {\n\tconst { x: barX, y: barY } = useElementBounding(barRef)\n\tconst { x: leftX, y: leftY } = useElementBounding(leftConnectionHandleRef)\n\tconst { x: rightX, y: rightY } = useElementBounding(rightConnectionHandleRef)\n\n\tstore.registerGanttBar({\n\t\tid: barId,\n\t\trowIndex,\n\t\tcolIndex,\n\t\tstartIndex: currentStart,\n\t\tendIndex: currentEnd,\n\t\tcolor: barColor,\n\t\tlabel,\n\t\tposition: { x: barX, y: barY },\n\t})\n\n\t// Only register connection handles if dependency graph is enabled\n\tif (store.isDependencyGraphEnabled) {\n\t\tstore.registerConnectionHandle({\n\t\t\tid: `${barId}-connection-left`,\n\t\t\trowIndex,\n\t\t\tcolIndex,\n\t\t\tside: 'left',\n\t\t\tposition: { x: leftX, y: leftY },\n\t\t\tvisible: isLeftConnectionVisible,\n\t\t\tbarId,\n\t\t})\n\n\t\tstore.registerConnectionHandle({\n\t\t\tid: `${barId}-connection-right`,\n\t\t\trowIndex,\n\t\t\tcolIndex,\n\t\t\tside: 'right',\n\t\t\tposition: { x: rightX, y: rightY },\n\t\t\tvisible: isRightConnectionVisible,\n\t\t\tbarId,\n\t\t})\n\t}\n}\n\nfunction unregisterGanttComponents() {\n\tstore.unregisterGanttBar(barId)\n\t// Only unregister connection handles if dependency graph is enabled\n\tif (store.isDependencyGraphEnabled) {\n\t\tstore.unregisterConnectionHandle(`${barId}-connection-left`)\n\t\tstore.unregisterConnectionHandle(`${barId}-connection-right`)\n\t}\n}\n\nfunction showConnectionHandles() {\n\t// Only show connection handles if dependency graph is enabled\n\tif (store.isDependencyGraphEnabled) {\n\t\tisLeftConnectionVisible.value = true\n\t\tisRightConnectionVisible.value = true\n\t}\n}\n\nfunction hideConnectionHandles() {\n\tif (!isLeftConnectionDragging.value && !isRightConnectionDragging.value) {\n\t\tisLeftConnectionVisible.value = false\n\t\tisRightConnectionVisible.value = false\n\t}\n}\n\nfunction startConnectionDrag(side: 'left' | 'right', event: MouseEvent) {\n\tevent.preventDefault()\n\tevent.stopPropagation()\n\n\tshowDragPreview.value = true\n\tif (side === 'left') {\n\t\tisLeftConnectionDragging.value = true\n\t} else {\n\t\tisRightConnectionDragging.value = true\n\t}\n\n\t// Set initial drag preview position\n\tconst handle = side === 'left' ? leftConnectionHandleRef.value : rightConnectionHandleRef.value\n\tif (handle) {\n\t\tconst handleRect = handle.getBoundingClientRect()\n\t\tconst centerX = handleRect.left + handleRect.width / 2\n\t\tconst centerY = handleRect.top + handleRect.height / 2\n\t\tdragPreview.value = { startX: centerX, startY: centerY, endX: centerX, endY: centerY }\n\t}\n\n\tconst handleMouseMove = (moveEvent: MouseEvent) => {\n\t\tdragPreview.value.endX = moveEvent.clientX\n\t\tdragPreview.value.endY = moveEvent.clientY\n\t}\n\n\tconst handleMouseUp = (upEvent: MouseEvent) => {\n\t\thandleConnectionDrop(upEvent, side)\n\t\tcleanupConnectionDrag(handleMouseMove, handleMouseUp)\n\t}\n\n\tdocument.addEventListener('mousemove', handleMouseMove)\n\tdocument.addEventListener('mouseup', handleMouseUp)\n}\n\nfunction handleConnectionDrop(upEvent: MouseEvent, sourceSide: 'left' | 'right') {\n\tconst targetElement = document.elementFromPoint(upEvent.clientX, upEvent.clientY)\n\tconst targetHandle = targetElement?.closest('.connection-handle')\n\n\tif (\n\t\ttargetHandle &&\n\t\ttargetHandle !== (sourceSide === 'left' ? leftConnectionHandleRef.value : rightConnectionHandleRef.value)\n\t) {\n\t\tconst targetBar = targetHandle.closest('.gantt-bar')\n\n\t\tif (targetBar) {\n\t\t\tconst targetRowIndex = parseInt(targetBar.getAttribute('data-rowindex') || '0')\n\t\t\tconst targetColIndex = parseInt(targetBar.getAttribute('data-colindex') || '0')\n\t\t\tconst targetSide = targetHandle.classList.contains('left-connection-handle') ? 'left' : 'right'\n\t\t\tconst targetBarId = `gantt-bar-row-${targetRowIndex}-col-${targetColIndex}`\n\n\t\t\tconst connection = store.createConnection(\n\t\t\t\t`${barId}-connection-${sourceSide}`,\n\t\t\t\t`${targetBarId}-connection-${targetSide}`\n\t\t\t)\n\n\t\t\tif (connection) {\n\t\t\t\temit('connection:create', connection)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction cleanupConnectionDrag(\n\thandleMouseMove: (event: MouseEvent) => void,\n\thandleMouseUp: (event: MouseEvent) => void\n) {\n\tshowDragPreview.value = false\n\tisLeftConnectionDragging.value = false\n\tisRightConnectionDragging.value = false\n\n\tdocument.removeEventListener('mousemove', handleMouseMove)\n\tdocument.removeEventListener('mouseup', handleMouseUp)\n\n\tif (!barRef.value?.matches(':hover')) {\n\t\thideConnectionHandles()\n\t}\n}\n\ndefineExpose({\n\tbarStyle,\n\tcleanupConnectionDrag,\n\tcurrentEnd,\n\thandleConnectionDrop,\n\tisLeftConnectionDragging,\n\tisLeftConnectionVisible,\n\tisRightConnectionDragging,\n\tisRightConnectionVisible,\n\tshowDragPreview,\n})\n</script>\n\n<style scoped>\n.aganttcell {\n\tbackground-color: #f9f9f9;\n\twidth: 100%;\n\tpadding: 0;\n\theight: 100%;\n}\n\n.gantt-container {\n\tposition: relative;\n\theight: 100%;\n\tbackground-color: #f0f0f0;\n\tborder-radius: 4px;\n\toverflow: visible;\n}\n\n.gantt-bar {\n\tposition: absolute;\n\tborder-radius: 4px;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tcursor: grab;\n\tbox-sizing: border-box;\n\tborder: 1px solid rgba(0, 0, 0, 0.5);\n\ttransition:\n\t\tleft 0.1s ease-out,\n\t\twidth 0.1s ease-out;\n\theight: 80%;\n\ttop: 50%;\n\tz-index: 0;\n\ttransform: translateY(-50%);\n}\n\n.gantt-bar:active {\n\tcursor: grabbing;\n}\n\n.gantt-bar.is-dragging {\n\tz-index: 10;\n}\n\n.gantt-label {\n\tflex: 1;\n\ttext-align: center;\n\tfont-size: 12px;\n\tcolor: #aaaaaa;\n\twhite-space: nowrap;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\tpadding: 0 8px;\n\tuser-select: none;\n}\n\n.resize-handle {\n\tposition: relative;\n\twidth: 12px;\n\theight: 100%;\n\tcursor: ew-resize;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tz-index: 0;\n\tbackground: rgba(0, 0, 0, 0.25);\n}\n\n.left-resize-handle {\n\tborder-right: 1px solid rgba(0, 0, 0, 0.5);\n}\n\n.right-resize-handle {\n\tborder-left: 1px solid rgba(0, 0, 0, 0.5);\n}\n\n.handle-grip {\n\twidth: 4px;\n\theight: 12px;\n\tborder-radius: 2px;\n\tbackground: rgba(0, 0, 0, 0.8);\n}\n\n.resize-handle:hover {\n\tbackground-color: rgba(255, 255, 255, 0.5);\n}\n\n.vertical-indicator {\n\tposition: absolute;\n\twidth: 2px;\n\topacity: 0;\n\tpointer-events: none;\n\ttransition: opacity 0.2s ease;\n\ttop: -100vh;\n\theight: 100vh;\n\tz-index: 5;\n\tbackground-color: v-bind(barColor);\n}\n\n.left-indicator {\n\tleft: 50%;\n\ttransform: translateX(-50%);\n}\n\n.right-indicator {\n\tright: 50%;\n\ttransform: translateX(50%);\n}\n\n.resize-handle.is-dragging .vertical-indicator {\n\topacity: 0.7;\n}\n\n.gantt-container::after {\n\tcontent: '';\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\tright: 0;\n\tbottom: 0;\n\tbackground-size: calc(100% / v-bind(colspan)) 100%;\n\tbackground-image: linear-gradient(to right, rgba(0, 0, 0, 0.1) 1px, transparent 1px);\n\tpointer-events: none;\n\tz-index: 1;\n}\n\n.connection-handle {\n\tposition: absolute;\n\ttop: 50%;\n\ttransform: translateY(-50%);\n\twidth: 16px;\n\theight: 16px;\n\topacity: 0;\n\ttransition: opacity 0.2s ease;\n\tcursor: crosshair;\n\tz-index: 2;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n}\n\n.connection-handle.visible {\n\topacity: 1;\n}\n\n.left-connection-handle {\n\tleft: -16px;\n}\n\n.right-connection-handle {\n\tright: -16px;\n}\n\n.connection-dot {\n\twidth: 8px;\n\theight: 8px;\n\tborder-radius: 50%;\n\tbackground-color: #2196f3;\n\tborder: 2px solid white;\n\tbox-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);\n}\n\n.connection-handle:hover .connection-dot {\n\tbackground-color: #1976d2;\n\ttransform: scale(1.2);\n}\n\n.connection-handle.is-dragging {\n\topacity: 1 !important;\n}\n\n.connection-handle.is-dragging .connection-dot {\n\tbackground-color: #1976d2;\n\ttransform: scale(1.3);\n\tbox-shadow: 0 2px 8px rgba(33, 150, 243, 0.4);\n}\n</style>\n","<template>\n\t<td class=\"aganttcell\" :colspan=\"colspan\">\n\t\t<div ref=\"container\" class=\"gantt-container\">\n\t\t\t<!-- Draggable gantt bar -->\n\t\t\t<div\n\t\t\t\tref=\"bar\"\n\t\t\t\t:data-rowindex=\"rowIndex\"\n\t\t\t\t:data-colindex=\"colIndex\"\n\t\t\t\tclass=\"gantt-bar\"\n\t\t\t\t:class=\"{ 'is-dragging': isAnyDragging }\"\n\t\t\t\t:style=\"barStyle\"\n\t\t\t\t@mouseenter=\"showConnectionHandles\"\n\t\t\t\t@mouseleave=\"hideConnectionHandles\">\n\t\t\t\t<!-- Connection handles for linking bars - only show if dependency graph is enabled -->\n\t\t\t\t<div\n\t\t\t\t\tv-if=\"store.isDependencyGraphEnabled\"\n\t\t\t\t\tref=\"leftConnectionHandle\"\n\t\t\t\t\tclass=\"connection-handle left-connection-handle\"\n\t\t\t\t\t:class=\"{ visible: isLeftConnectionVisible, 'is-dragging': isLeftConnectionDragging }\"\n\t\t\t\t\t@mousedown.stop=\"startConnectionDrag('left', $event)\">\n\t\t\t\t\t<div class=\"connection-dot\"></div>\n\t\t\t\t</div>\n\n\t\t\t\t<div\n\t\t\t\t\tv-if=\"store.isDependencyGraphEnabled\"\n\t\t\t\t\tref=\"rightConnectionHandle\"\n\t\t\t\t\tclass=\"connection-handle right-connection-handle\"\n\t\t\t\t\t:class=\"{ visible: isRightConnectionVisible, 'is-dragging': isRightConnectionDragging }\"\n\t\t\t\t\t@mousedown.stop=\"startConnectionDrag('right', $event)\">\n\t\t\t\t\t<div class=\"connection-dot\"></div>\n\t\t\t\t</div>\n\n\t\t\t\t<!-- Resize handles for changing bar length -->\n\t\t\t\t<div ref=\"leftResizeHandle\" class=\"resize-handle left-resize-handle\" :class=\"{ 'is-dragging': isLeftResizing }\">\n\t\t\t\t\t<div class=\"handle-grip\"></div>\n\t\t\t\t\t<div class=\"vertical-indicator left-indicator\"></div>\n\t\t\t\t</div>\n\n\t\t\t\t<label v-if=\"label\" class=\"gantt-label\">{{ label }}</label>\n\n\t\t\t\t<div\n\t\t\t\t\tref=\"rightResizeHandle\"\n\t\t\t\t\tclass=\"resize-handle right-resize-handle\"\n\t\t\t\t\t:class=\"{ 'is-dragging': isRightResizing }\">\n\t\t\t\t\t<div class=\"handle-grip\"></div>\n\t\t\t\t\t<div class=\"vertical-indicator right-indicator\"></div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<!-- Connection drag preview line - only show if dependency graph is enabled -->\n\t\t<svg v-if=\"store.isDependencyGraphEnabled && showDragPreview\" :style=\"connectionDragStyle\">\n\t\t\t<line\n\t\t\t\t:x1=\"dragPreview.startX\"\n\t\t\t\t:y1=\"dragPreview.startY\"\n\t\t\t\t:x2=\"dragPreview.endX\"\n\t\t\t\t:y2=\"dragPreview.endY\"\n\t\t\t\tstroke=\"#2196f3\"\n\t\t\t\tstroke-width=\"2\"\n\t\t\t\tstroke-dasharray=\"5,5\" />\n\t\t</svg>\n\t</td>\n</template>\n\n<script setup lang=\"ts\">\nimport { useDraggable, useElementBounding } from '@vueuse/core'\nimport { ref, computed, onMounted, onUnmounted, useTemplateRef, type StyleValue } from 'vue'\n\nimport { createTableStore } from '../stores/table'\nimport type { ConnectionPath } from '../types'\n\nconst {\n\tstore,\n\tcolumnsCount,\n\trowIndex,\n\tcolIndex,\n\tstart = 0,\n\tend = 0,\n\tcolspan = 1,\n\tlabel = '',\n\tcolor = '#cccccc',\n} = defineProps<{\n\tstore: ReturnType<typeof createTableStore>\n\tcolumnsCount: number\n\trowIndex: number\n\tcolIndex: number\n\tstart?: number\n\tend?: number\n\tcolspan?: number\n\tlabel?: string\n\tcolor?: string\n}>()\n\nconst emit = defineEmits<{\n\t'connection:create': [connection: ConnectionPath]\n}>()\n\n// Core refs and state\nconst barColor = ref(color.length >= 6 ? color : '#cccccc')\nconst barId = `gantt-bar-row-${rowIndex}-col-${colIndex}`\n\n// Template refs\nconst containerRef = useTemplateRef<HTMLDivElement>('container')\nconst barRef = useTemplateRef<HTMLDivElement>('bar')\nconst leftResizeHandleRef = useTemplateRef<HTMLDivElement>('leftResizeHandle')\nconst rightResizeHandleRef = useTemplateRef<HTMLDivElement>('rightResizeHandle')\nconst leftConnectionHandleRef = useTemplateRef<HTMLDivElement>('leftConnectionHandle')\nconst rightConnectionHandleRef = useTemplateRef<HTMLDivElement>('rightConnectionHandle')\n\n// Position tracking\nconst { width: totalBarWidth } = useElementBounding(containerRef)\nconst { left: barLeft, right: barRight } = useElementBounding(barRef)\n\n// Bar positioning\nconst currentStart = ref(start)\nconst currentEnd = ref(end || currentStart.value + colspan)\n\n// Drag states\nconst isLeftConnectionVisible = ref(false)\nconst isRightConnectionVisible = ref(false)\nconst isLeftConnectionDragging = ref(false)\nconst isRightConnectionDragging = ref(false)\nconst showDragPreview = ref(false)\nconst dragPreview = ref({ startX: 0, startY: 0, endX: 0, endY: 0 })\n\n// Computed properties\nconst isAnyDragging = computed(() => isBarDragging.value || isLeftResizing.value || isRightResizing.value)\n\nconst pixelsPerColumn = computed(() => (colspan > 0 ? totalBarWidth.value / colspan : 0))\n\nconst barStyle = computed((): StyleValue => {\n\tconst startPercent = (currentStart.value / colspan) * 100\n\tconst endPercent = (currentEnd.value / colspan) * 100\n\treturn {\n\t\tleft: `${startPercent}%`,\n\t\twidth: `${endPercent - startPercent}%`,\n\t\tbackgroundColor: barColor.value,\n\t}\n})\n\nconst connectionDragStyle = computed((): StyleValue => ({\n\tposition: 'fixed',\n\ttop: 0,\n\tleft: 0,\n\twidth: '100vw',\n\theight: '100vh',\n\tpointerEvents: 'none',\n\tzIndex: 1000,\n}))\n\n// Drag setup data\nconst dragStartData = ref({ startX: 0, startPos: 0 })\n\n// Left resize handle dragging\nconst { isDragging: isLeftResizing } = useDraggable(leftResizeHandleRef, {\n\taxis: 'x',\n\tonStart: () => setupDragStart(barLeft.value, currentStart.value),\n\tonMove: ({ x }) => handleLeftResize(x),\n\tonEnd: ({ x }) => finishLeftResize(x),\n})\n\n// Right resize handle dragging\nconst { isDragging: isRightResizing } = useDraggable(rightResizeHandleRef, {\n\taxis: 'x',\n\tonStart: () => setupDragStart(barRight.value, currentEnd.value),\n\tonMove: ({ x }) => handleRightResize(x),\n\tonEnd: ({ x }) => finishRightResize(x),\n})\n\n// Bar movement dragging\nconst { isDragging: isBarDragging } = useDraggable(barRef, {\n\texact: true,\n\taxis: 'x',\n\tonStart: () => setupDragStart(barLeft.value, currentStart.value),\n\tonMove: ({ x }) => handleBarMove(x),\n\tonEnd: ({ x }) => finishBarMove(x),\n})\n\n// Lifecycle\nonMounted(() => {\n\tregisterGanttComponents()\n})\n\nonUnmounted(() => {\n\tunregisterGanttComponents()\n})\n\n// Helper functions\nfunction setupDragStart(startX: number, startPos: number) {\n\tif (barRef.value) barRef.value.style.transition = 'none'\n\tdragStartData.value = { startX, startPos }\n}\n\nfunction handleLeftResize(x: number) {\n\tif (!isLeftResizing.value || !barRef.value) return\n\n\tconst deltaX = x - dragStartData.value.startX\n\tconst deltaColumns = deltaX / pixelsPerColumn.value\n\tconst newStart = Math.max(0, Math.min(currentEnd.value - 1, dragStartData.value.startPos + deltaColumns))\n\n\tbarRef.value.style.left = `${(newStart / colspan) * 100}%`\n\tbarRef.value.style.width = `${((currentEnd.value - newStart) / colspan) * 100}%`\n}\n\nfunction finishLeftResize(x: number) {\n\tif (!barRef.value) return\n\n\tconst deltaX = x - dragStartData.value.startX\n\tconst deltaColumns = Math.round(deltaX / pixelsPerColumn.value)\n\tconst oldStart = currentStart.value\n\tconst newStart = Math.max(0, Math.min(currentEnd.value - 1, dragStartData.value.startPos + deltaColumns))\n\n\tcurrentStart.value = newStart\n\tstore.updateGanttBar({\n\t\trowIndex,\n\t\tcolIndex,\n\t\ttype: 'resize',\n\t\tedge: 'start',\n\t\toldStart,\n\t\tnewStart,\n\t\tend: currentEnd.value,\n\t\tdelta: deltaColumns,\n\t\toldColspan: currentEnd.value - oldStart,\n\t\tnewColspan: currentEnd.value - newStart,\n\t})\n}\n\nfunction handleRightResize(x: number) {\n\tif (!isRightResizing.value || !barRef.value) return\n\n\tconst deltaX = x - dragStartData.value.startX\n\tconst deltaColumns = deltaX / pixelsPerColumn.value\n\tconst newEnd = Math.max(currentStart.value + 1, Math.min(columnsCount, dragStartData.value.startPos + deltaColumns))\n\n\tbarRef.value.style.width = `${((newEnd - currentStart.value) / colspan) * 100}%`\n}\n\nfunction finishRightResize(x: number) {\n\tif (!barRef.value) return\n\n\tconst deltaX = x - dragStartData.value.startX\n\tconst deltaColumns = Math.round(deltaX / pixelsPerColumn.value)\n\tconst oldEnd = currentEnd.value\n\tconst newEnd = Math.max(currentStart.value + 1, Math.min(columnsCount, dragStartData.value.startPos + deltaColumns))\n\n\tcurrentEnd.value = newEnd\n\tstore.updateGanttBar({\n\t\trowIndex,\n\t\tcolIndex,\n\t\ttype: 'resize',\n\t\tedge: 'end',\n\t\toldEnd,\n\t\tnewEnd,\n\t\tstart: currentStart.value,\n\t\tdelta: deltaColumns,\n\t\toldColspan: oldEnd - currentStart.value,\n\t\tnewColspan: newEnd - currentStart.value,\n\t})\n}\n\nfunction handleBarMove(x: number) {\n\tif (!isBarDragging.value || !barRef.value) return\n\n\tconst deltaX = x - dragStartData.value.startX\n\tconst deltaColumns = deltaX / pixelsPerColumn.value\n\tconst barWidth = currentEnd.value - currentStart.value\n\tconst newStart = Math.max(0, Math.min(dragStartData.value.startPos + deltaColumns, columnsCount - barWidth))\n\n\tbarRef.value.style.left = `${(newStart / colspan) * 100}%`\n}\n\nfunction finishBarMove(x: number) {\n\tif (!barRef.value) return\n\n\tconst deltaX = x - dragStartData.value.startX\n\tconst deltaColumns = Math.round(deltaX / pixelsPerColumn.value)\n\tconst barWidth = currentEnd.value - currentStart.value\n\n\tconst oldStart = currentStart.value\n\tconst oldEnd = currentEnd.value\n\tlet newStart = dragStartData.value.startPos + deltaColumns\n\tlet newEnd = newStart + barWidth\n\n\t// Boundary checks\n\tif (newStart < 0) {\n\t\tnewStart = 0\n\t\tnewEnd = barWidth\n\t} else if (newEnd > columnsCount) {\n\t\tnewEnd = columnsCount\n\t\tnewStart = newEnd - barWidth\n\t}\n\n\tcurrentStart.value = newStart\n\tcurrentEnd.value = newEnd\n\n\tstore.updateGanttBar({\n\t\trowIndex,\n\t\tcolIndex,\n\t\ttype: 'bar',\n\t\toldStart,\n\t\toldEnd,\n\t\tnewStart,\n\t\tnewEnd,\n\t\tdelta: deltaColumns,\n\t\tcolspan: newEnd - newStart,\n\t})\n}\n\nfunction registerGanttComponents() {\n\tconst { x: barX, y: barY } = useElementBounding(barRef)\n\tconst { x: leftX, y: leftY } = useElementBounding(leftConnectionHandleRef)\n\tconst { x: rightX, y: rightY } = useElementBounding(rightConnectionHandleRef)\n\n\tstore.registerGanttBar({\n\t\tid: barId,\n\t\trowIndex,\n\t\tcolIndex,\n\t\tstartIndex: currentStart,\n\t\tendIndex: currentEnd,\n\t\tcolor: barColor,\n\t\tlabel,\n\t\tposition: { x: barX, y: barY },\n\t})\n\n\t// Only register connection handles if dependency graph is enabled\n\tif (store.isDependencyGraphEnabled) {\n\t\tstore.registerConnectionHandle({\n\t\t\tid: `${barId}-connection-left`,\n\t\t\trowIndex,\n\t\t\tcolIndex,\n\t\t\tside: 'left',\n\t\t\tposition: { x: leftX, y: leftY },\n\t\t\tvisible: isLeftConnectionVisible,\n\t\t\tbarId,\n\t\t})\n\n\t\tstore.registerConnectionHandle({\n\t\t\tid: `${barId}-connection-right`,\n\t\t\trowIndex,\n\t\t\tcolIndex,\n\t\t\tside: 'right',\n\t\t\tposition: { x: rightX, y: rightY },\n\t\t\tvisible: isRightConnectionVisible,\n\t\t\tbarId,\n\t\t})\n\t}\n}\n\nfunction unregisterGanttComponents() {\n\tstore.unregisterGanttBar(barId)\n\t// Only unregister connection handles if dependency graph is enabled\n\tif (store.isDependencyGraphEnabled) {\n\t\tstore.unregisterConnectionHandle(`${barId}-connection-left`)\n\t\tstore.unregisterConnectionHandle(`${barId}-connection-right`)\n\t}\n}\n\nfunction showConnectionHandles() {\n\t// Only show connection handles if dependency graph is enabled\n\tif (store.isDependencyGraphEnabled) {\n\t\tisLeftConnectionVisible.value = true\n\t\tisRightConnectionVisible.value = true\n\t}\n}\n\nfunction hideConnectionHandles() {\n\tif (!isLeftConnectionDragging.value && !isRightConnectionDragging.value) {\n\t\tisLeftConnectionVisible.value = false\n\t\tisRightConnectionVisible.value = false\n\t}\n}\n\nfunction startConnectionDrag(side: 'left' | 'right', event: MouseEvent) {\n\tevent.preventDefault()\n\tevent.stopPropagation()\n\n\tshowDragPreview.value = true\n\tif (side === 'left') {\n\t\tisLeftConnectionDragging.value = true\n\t} else {\n\t\tisRightConnectionDragging.value = true\n\t}\n\n\t// Set initial drag preview position\n\tconst handle = side === 'left' ? leftConnectionHandleRef.value : rightConnectionHandleRef.value\n\tif (handle) {\n\t\tconst handleRect = handle.getBoundingClientRect()\n\t\tconst centerX = handleRect.left + handleRect.width / 2\n\t\tconst centerY = handleRect.top + handleRect.height / 2\n\t\tdragPreview.value = { startX: centerX, startY: centerY, endX: centerX, endY: centerY }\n\t}\n\n\tconst handleMouseMove = (moveEvent: MouseEvent) => {\n\t\tdragPreview.value.endX = moveEvent.clientX\n\t\tdragPreview.value.endY = moveEvent.clientY\n\t}\n\n\tconst handleMouseUp = (upEvent: MouseEvent) => {\n\t\thandleConnectionDrop(upEvent, side)\n\t\tcleanupConnectionDrag(handleMouseMove, handleMouseUp)\n\t}\n\n\tdocument.addEventListener('mousemove', handleMouseMove)\n\tdocument.addEventListener('mouseup', handleMouseUp)\n}\n\nfunction handleConnectionDrop(upEvent: MouseEvent, sourceSide: 'left' | 'right') {\n\tconst targetElement = document.elementFromPoint(upEvent.clientX, upEvent.clientY)\n\tconst targetHandle = targetElement?.closest('.connection-handle')\n\n\tif (\n\t\ttargetHandle &&\n\t\ttargetHandle !== (sourceSide === 'left' ? leftConnectionHandleRef.value : rightConnectionHandleRef.value)\n\t) {\n\t\tconst targetBar = targetHandle.closest('.gantt-bar')\n\n\t\tif (targetBar) {\n\t\t\tconst targetRowIndex = parseInt(targetBar.getAttribute('data-rowindex') || '0')\n\t\t\tconst targetColIndex = parseInt(targetBar.getAttribute('data-colindex') || '0')\n\t\t\tconst targetSide = targetHandle.classList.contains('left-connection-handle') ? 'left' : 'right'\n\t\t\tconst targetBarId = `gantt-bar-row-${targetRowIndex}-col-${targetColIndex}`\n\n\t\t\tconst connection = store.createConnection(\n\t\t\t\t`${barId}-connection-${sourceSide}`,\n\t\t\t\t`${targetBarId}-connection-${targetSide}`\n\t\t\t)\n\n\t\t\tif (connection) {\n\t\t\t\temit('connection:create', connection)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction cleanupConnectionDrag(\n\thandleMouseMove: (event: MouseEvent) => void,\n\thandleMouseUp: (event: MouseEvent) => void\n) {\n\tshowDragPreview.value = false\n\tisLeftConnectionDragging.value = false\n\tisRightConnectionDragging.value = false\n\n\tdocument.removeEventListener('mousemove', handleMouseMove)\n\tdocument.removeEventListener('mouseup', handleMouseUp)\n\n\tif (!barRef.value?.matches(':hover')) {\n\t\thideConnectionHandles()\n\t}\n}\n\ndefineExpose({\n\tbarStyle,\n\tcleanupConnectionDrag,\n\tcurrentEnd,\n\thandleConnectionDrop,\n\tisLeftConnectionDragging,\n\tisLeftConnectionVisible,\n\tisRightConnectionDragging,\n\tisRightConnectionVisible,\n\tshowDragPreview,\n})\n</script>\n\n<style scoped>\n.aganttcell {\n\tbackground-color: #f9f9f9;\n\twidth: 100%;\n\tpadding: 0;\n\theight: 100%;\n}\n\n.gantt-container {\n\tposition: relative;\n\theight: 100%;\n\tbackground-color: #f0f0f0;\n\tborder-radius: 4px;\n\toverflow: visible;\n}\n\n.gantt-bar {\n\tposition: absolute;\n\tborder-radius: 4px;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tcursor: grab;\n\tbox-sizing: border-box;\n\tborder: 1px solid rgba(0, 0, 0, 0.5);\n\ttransition:\n\t\tleft 0.1s ease-out,\n\t\twidth 0.1s ease-out;\n\theight: 80%;\n\ttop: 50%;\n\tz-index: 0;\n\ttransform: translateY(-50%);\n}\n\n.gantt-bar:active {\n\tcursor: grabbing;\n}\n\n.gantt-bar.is-dragging {\n\tz-index: 10;\n}\n\n.gantt-label {\n\tflex: 1;\n\ttext-align: center;\n\tfont-size: 12px;\n\tcolor: #aaaaaa;\n\twhite-space: nowrap;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\tpadding: 0 8px;\n\tuser-select: none;\n}\n\n.resize-handle {\n\tposition: relative;\n\twidth: 12px;\n\theight: 100%;\n\tcursor: ew-resize;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tz-index: 0;\n\tbackground: rgba(0, 0, 0, 0.25);\n}\n\n.left-resize-handle {\n\tborder-right: 1px solid rgba(0, 0, 0, 0.5);\n}\n\n.right-resize-handle {\n\tborder-left: 1px solid rgba(0, 0, 0, 0.5);\n}\n\n.handle-grip {\n\twidth: 4px;\n\theight: 12px;\n\tborder-radius: 2px;\n\tbackground: rgba(0, 0, 0, 0.8);\n}\n\n.resize-handle:hover {\n\tbackground-color: rgba(255, 255, 255, 0.5);\n}\n\n.vertical-indicator {\n\tposition: absolute;\n\twidth: 2px;\n\topacity: 0;\n\tpointer-events: none;\n\ttransition: opacity 0.2s ease;\n\ttop: -100vh;\n\theight: 100vh;\n\tz-index: 5;\n\tbackground-color: v-bind(barColor);\n}\n\n.left-indicator {\n\tleft: 50%;\n\ttransform: translateX(-50%);\n}\n\n.right-indicator {\n\tright: 50%;\n\ttransform: translateX(50%);\n}\n\n.resize-handle.is-dragging .vertical-indicator {\n\topacity: 0.7;\n}\n\n.gantt-container::after {\n\tcontent: '';\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\tright: 0;\n\tbottom: 0;\n\tbackground-size: calc(100% / v-bind(colspan)) 100%;\n\tbackground-image: linear-gradient(to right, rgba(0, 0, 0, 0.1) 1px, transparent 1px);\n\tpointer-events: none;\n\tz-index: 1;\n}\n\n.connection-handle {\n\tposition: absolute;\n\ttop: 50%;\n\ttransform: translateY(-50%);\n\twidth: 16px;\n\theight: 16px;\n\topacity: 0;\n\ttransition: opacity 0.2s ease;\n\tcursor: crosshair;\n\tz-index: 2;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n}\n\n.connection-handle.visible {\n\topacity: 1;\n}\n\n.left-connection-handle {\n\tleft: -16px;\n}\n\n.right-connection-handle {\n\tright: -16px;\n}\n\n.connection-dot {\n\twidth: 8px;\n\theight: 8px;\n\tborder-radius: 50%;\n\tbackground-color: #2196f3;\n\tborder: 2px solid white;\n\tbox-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);\n}\n\n.connection-handle:hover .connection-dot {\n\tbackground-color: #1976d2;\n\ttransform: scale(1.2);\n}\n\n.connection-handle.is-dragging {\n\topacity: 1 !important;\n}\n\n.connection-handle.is-dragging .connection-dot {\n\tbackground-color: #1976d2;\n\ttransform: scale(1.3);\n\tbox-shadow: 0 2px 8px rgba(33, 150, 243, 0.4);\n}\n</style>\n","/**\n * Icon exports for ATable row actions.\n * Icons are exported as raw SVG strings for flexibility in rendering.\n * @packageDocumentation\n */\n\nimport rawAddIcon from './stonecrop-ui-icon-add.svg?raw'\nimport rawDeleteIcon from './stonecrop-ui-icon-delete.svg?raw'\nimport rawDuplicateIcon from './stonecrop-ui-icon-duplicate.svg?raw'\nimport rawInsertAboveIcon from './stonecrop-ui-icon-insert-above.svg?raw'\nimport rawInsertBelowIcon from './stonecrop-ui-icon-insert-below.svg?raw'\nimport rawMoveIcon from './stonecrop-ui-icon-move.svg?raw'\nimport rawOpenIcon from './stonecrop-ui-icon-open.svg?raw'\n\n// Annotated rather than re-exported directly. `?raw` is a Vite import and the .svg files are inlined\n// at build time, so a declaration that infers its type from the import re-states that specifier — and\n// the emitted `dist/src/icons/index.d.ts` then names seven modules the tarball does not contain.\n/** Raw SVG for the add-row action. @public */\nconst AddIcon: string = rawAddIcon\n/** Raw SVG for the delete-row action. @public */\nconst DeleteIcon: string = rawDeleteIcon\n/** Raw SVG for the duplicate-row action. @public */\nconst DuplicateIcon: string = rawDuplicateIcon\n/** Raw SVG for the insert-above action. @public */\nconst InsertAboveIcon: string = rawInsertAboveIcon\n/** Raw SVG for the insert-below action. @public */\nconst InsertBelowIcon: string = rawInsertBelowIcon\n/** Raw SVG for the move action. @public */\nconst MoveIcon: string = rawMoveIcon\n/** Raw SVG for the open-record action. @public */\nconst OpenIcon: string = rawOpenIcon\n\n// Directional move icons are inline (no dedicated SVG asset): simple up/down chevrons.\nconst MoveUpIcon =\n\t'<svg viewBox=\"0 0 16 16\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"><path d=\"M8 13V3.5M4.5 7 8 3.5 11.5 7\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>'\nconst MoveDownIcon =\n\t'<svg viewBox=\"0 0 16 16\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"><path d=\"M8 3v9.5M4.5 9 8 12.5 11.5 9\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>'\n\nexport { AddIcon, DeleteIcon, DuplicateIcon, InsertAboveIcon, InsertBelowIcon, MoveIcon, OpenIcon }\n\n/**\n * Map of action types to their default icons.\n *\n * @public\n */\nexport const actionIcons: Record<string, string> = {\n\tadd: AddIcon,\n\tdelete: DeleteIcon,\n\tduplicate: DuplicateIcon,\n\tinsertAbove: InsertAboveIcon,\n\tinsertBelow: InsertBelowIcon,\n\tmove: MoveIcon,\n\tmoveUp: MoveUpIcon,\n\tmoveDown: MoveDownIcon,\n\topen: OpenIcon,\n}\n","<template>\n\t<td\n\t\tref=\"actionsCell\"\n\t\tclass=\"atable-row-actions\"\n\t\t:class=\"{ 'sticky-column': position === 'before-index', 'dropdown-active': dropdownOpen }\">\n\t\t<!-- Dropdown mode -->\n\t\t<div v-if=\"showDropdown\" class=\"row-actions-dropdown\">\n\t\t\t<button\n\t\t\t\tref=\"toggleButton\"\n\t\t\t\ttype=\"button\"\n\t\t\t\tclass=\"row-actions-toggle\"\n\t\t\t\t:aria-expanded=\"dropdownOpen\"\n\t\t\t\taria-haspopup=\"true\"\n\t\t\t\t@click.stop=\"toggleDropdown\">\n\t\t\t\t<span class=\"dropdown-icon\">⋮</span>\n\t\t\t</button>\n\t\t\t<div\n\t\t\t\tv-show=\"dropdownOpen\"\n\t\t\t\tclass=\"row-actions-menu\"\n\t\t\t\t:class=\"{ 'menu-flipped': dropdownFlipped }\"\n\t\t\t\t:style=\"menuStyle\"\n\t\t\t\trole=\"menu\">\n\t\t\t\t<button\n\t\t\t\t\tv-for=\"action in enabledActions\"\n\t\t\t\t\t:key=\"action.type\"\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"row-action-menu-item\"\n\t\t\t\t\trole=\"menuitem\"\n\t\t\t\t\t:disabled=\"action.disabled\"\n\t\t\t\t\t@click.stop=\"executeAction(action.type, $event)\">\n\t\t\t\t\t<span class=\"action-icon\" v-html=\"action.icon\" />\n\t\t\t\t\t<span class=\"action-label\">{{ action.label }}</span>\n\t\t\t\t</button>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<!-- Icon mode -->\n\t\t<div v-else class=\"row-actions-icons\">\n\t\t\t<button\n\t\t\t\tv-for=\"action in enabledActions\"\n\t\t\t\t:key=\"action.type\"\n\t\t\t\ttype=\"button\"\n\t\t\t\tclass=\"row-action-btn\"\n\t\t\t\t:title=\"action.label\"\n\t\t\t\t:aria-label=\"action.label\"\n\t\t\t\t:disabled=\"action.disabled\"\n\t\t\t\t@click.stop=\"executeAction(action.type, $event)\">\n\t\t\t\t<span class=\"action-icon\" v-html=\"action.icon\" />\n\t\t\t</button>\n\t\t</div>\n\t</td>\n</template>\n\n<script setup lang=\"ts\">\nimport { useResizeObserver, onClickOutside } from '@vueuse/core'\nimport { computed, ref, useTemplateRef } from 'vue'\n\nimport { actionIcons } from '../icons'\nimport { createTableStore } from '../stores/table'\nimport type { RowActionsConfig, RowActionType } from '../types'\n\nconst props = defineProps<{\n\trowIndex: number\n\tstore: ReturnType<typeof createTableStore>\n\tconfig: RowActionsConfig\n\tposition?: 'before-index' | 'after-index' | 'end'\n}>()\n\nconst emit = defineEmits<{\n\taction: [type: RowActionType, rowIndex: number, event?: MouseEvent]\n}>()\n\nconst actionsCellRef = useTemplateRef<HTMLTableCellElement>('actionsCell')\nconst toggleButtonRef = useTemplateRef<HTMLButtonElement>('toggleButton')\nconst cellWidth = ref(0)\nconst dropdownOpen = ref(false)\nconst dropdownFlipped = ref(false)\nconst menuPosition = ref({ top: 0, left: 0 })\n\n// Default labels for actions\nconst defaultLabels: Record<RowActionType, string> = {\n\tadd: 'Add Record',\n\tdelete: 'Delete Record',\n\tduplicate: 'Duplicate Record',\n\tinsertAbove: 'Insert Above',\n\tinsertBelow: 'Insert Below',\n\tmove: 'Move Record',\n\tmoveUp: 'Move Up',\n\tmoveDown: 'Move Down',\n\topen: 'Open Record',\n}\n\n// Determine which actions are enabled\nconst enabledActions = computed(() => {\n\tconst actions: Array<{ type: RowActionType; label: string; icon: string; disabled: boolean }> = []\n\tconst configActions = props.config.actions || {}\n\n\tconst actionTypes: RowActionType[] = [\n\t\t'open',\n\t\t'moveUp',\n\t\t'moveDown',\n\t\t'duplicate',\n\t\t'insertAbove',\n\t\t'insertBelow',\n\t\t'add',\n\t\t'delete',\n\t\t'move',\n\t]\n\n\tfor (const type of actionTypes) {\n\t\tconst actionConfig = configActions[type]\n\n\t\t// Skip if explicitly disabled\n\t\tif (actionConfig === false) continue\n\n\t\t// Skip if not configured and we're being explicit\n\t\tif (actionConfig === undefined) continue\n\n\t\tlet enabled = true\n\t\tlet label = defaultLabels[type]\n\t\tlet icon = actionIcons[type]\n\t\tlet disabled = false\n\n\t\tif (typeof actionConfig === 'object') {\n\t\t\tenabled = actionConfig.enabled !== false\n\t\t\tlabel = actionConfig.label || label\n\t\t\ticon = actionConfig.icon || icon\n\t\t\t// Per-row predicate; reading store state here keeps this computed reactive to row changes.\n\t\t\tif (actionConfig.disabled) disabled = actionConfig.disabled(props.rowIndex, props.store)\n\t\t}\n\n\t\tif (enabled) {\n\t\t\tactions.push({ type, label, icon, disabled })\n\t\t}\n\t}\n\n\treturn actions\n})\n\n// Determine if we should show dropdown mode\nconst showDropdown = computed(() => {\n\tif (props.config.forceDropdown) return true\n\n\tconst threshold = props.config.dropdownThreshold ?? 150\n\tif (threshold === 0) return false\n\n\treturn cellWidth.value > 0 && cellWidth.value < threshold\n})\n\n// Compute menu style for fixed positioning\nconst menuStyle = computed(() => {\n\tif (!dropdownOpen.value) return {}\n\n\tif (dropdownFlipped.value) {\n\t\treturn {\n\t\t\tposition: 'fixed' as const,\n\t\t\tbottom: `${window.innerHeight - menuPosition.value.top}px`,\n\t\t\tleft: `${menuPosition.value.left}px`,\n\t\t\ttop: 'auto',\n\t\t}\n\t}\n\treturn {\n\t\tposition: 'fixed' as const,\n\t\ttop: `${menuPosition.value.top}px`,\n\t\tleft: `${menuPosition.value.left}px`,\n\t}\n})\n\n// Track cell width for responsive behavior\nuseResizeObserver(actionsCellRef, entries => {\n\tconst entry = entries[0]\n\tif (entry) {\n\t\tcellWidth.value = entry.contentRect.width\n\t}\n})\n\n// Toggle dropdown menu\nconst toggleDropdown = () => {\n\tif (!dropdownOpen.value) {\n\t\t// Opening - check if we need to flip\n\t\tcheckDropdownPosition()\n\t}\n\tdropdownOpen.value = !dropdownOpen.value\n}\n\n// Check if dropdown should flip upward and calculate position\nconst checkDropdownPosition = () => {\n\tif (!toggleButtonRef.value) return\n\n\tconst buttonRect = toggleButtonRef.value.getBoundingClientRect()\n\tconst viewportHeight = window.innerHeight\n\tconst viewportWidth = window.innerWidth\n\tconst estimatedMenuHeight = enabledActions.value.length * 40 + 16 // ~40px per item + padding\n\tconst estimatedMenuWidth = 160 // matches min-width: 10rem\n\n\t// Check if menu would extend beyond viewport bottom\n\tconst spaceBelow = viewportHeight - buttonRect.bottom\n\tconst spaceAbove = buttonRect.top\n\n\t// Flip if not enough space below but enough space above\n\tdropdownFlipped.value = spaceBelow < estimatedMenuHeight && spaceAbove > estimatedMenuHeight\n\n\t// Horizontal: anchor the menu's left edge to the button, but right-align it to the button when\n\t// it would overflow the viewport's right edge (e.g. an end-positioned actions column).\n\tlet left = buttonRect.left\n\tif (left + estimatedMenuWidth > viewportWidth) {\n\t\tleft = Math.max(0, buttonRect.right - estimatedMenuWidth)\n\t}\n\n\t// Calculate fixed position\n\tmenuPosition.value = {\n\t\ttop: dropdownFlipped.value ? buttonRect.top : buttonRect.bottom,\n\t\tleft,\n\t}\n}\n\nonClickOutside(actionsCellRef, () => {\n\tdropdownOpen.value = false\n})\n\n// Execute an action\nconst executeAction = (actionType: RowActionType, event?: MouseEvent) => {\n\tdropdownOpen.value = false\n\n\t// Check for custom handler\n\tconst actionConfig = props.config.actions?.[actionType]\n\tif (typeof actionConfig === 'object' && actionConfig.handler) {\n\t\tconst result = actionConfig.handler(props.rowIndex, props.store)\n\t\tif (result === false) {\n\t\t\t// Handler returned false, don't proceed with default behavior\n\t\t\treturn\n\t\t}\n\t}\n\n\t// Emit the action event for parent to handle\n\temit('action', actionType, props.rowIndex, event)\n}\n</script>\n\n<style>\n.atable-row-actions {\n\twidth: 2rem;\n\tmin-width: 2rem;\n\tpadding: 0 0.25rem;\n\tvertical-align: middle;\n\twhite-space: nowrap;\n\tborder-top: 1px solid var(--sc-row-border-color);\n\tbackground: white;\n\tuser-select: none;\n\tposition: relative;\n}\n\n.atable-row-actions.dropdown-active {\n\tz-index: 101;\n}\n\n.row-actions-icons {\n\tdisplay: flex;\n\tgap: 0.25rem;\n\talign-items: center;\n\tjustify-content: center;\n}\n\n.row-action-btn {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 1.5rem;\n\theight: 1.5rem;\n\tpadding: 0.125rem;\n\tborder: none;\n\tbackground: transparent;\n\tcursor: pointer;\n\tborder-radius: 0.25rem;\n\ttransition: background-color 0.15s ease;\n}\n\n.row-action-btn:hover {\n\tbackground-color: var(--sc-gray-10);\n}\n\n.row-action-btn:focus {\n\toutline: 2px solid var(--sc-focus-cell-outline);\n\toutline-offset: 1px;\n}\n\n.row-action-btn .action-icon {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 1rem;\n\theight: 1rem;\n}\n\n.row-action-btn .action-icon svg {\n\twidth: 100%;\n\theight: 100%;\n}\n\n/* Dropdown mode styles */\n.row-actions-dropdown {\n\tposition: relative;\n\tdisplay: inline-block;\n}\n.row-actions-dropdown:has(button:focus) {\n\toutline: 2px solid var(--sc-focus-cell-outline);\n\toutline-offset: -2px;\n}\n\n.row-actions-toggle {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 1.5rem;\n\theight: 1.5rem;\n\tpadding: 0;\n\tborder: none;\n\tbackground: transparent;\n\tcursor: pointer;\n\tborder-radius: 0.25rem;\n\tfont-size: 1rem;\n\tfont-weight: bold;\n\ttransition: background-color 0.15s ease;\n}\n\n.row-actions-toggle:hover {\n\tbackground-color: var(--sc-gray-10);\n}\n\n.row-actions-toggle:focus {\n\t/* outline: 2px solid var(--sc-focus-cell-outline);\n\toutline-offset: 1px; */\n}\n\n.dropdown-icon {\n\tline-height: 1;\n}\n\n.row-actions-menu {\n\tposition: fixed;\n\tz-index: 100;\n\tmin-width: 10rem;\n\tpadding: 0.25rem 0;\n\tbackground: white;\n\tborder: 1px solid var(--sc-row-border-color);\n\tborder-left: 4px solid var(--sc-row-border-color);\n\tborder-radius: 0;\n}\n\n.row-actions-menu.menu-flipped {\n\tbox-shadow:\n\t\t0 -4px 6px -1px rgb(0 0 0 / 0.1),\n\t\t0 -2px 4px -2px rgb(0 0 0 / 0.1);\n}\n\n.row-action-menu-item {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 0.5rem;\n\twidth: 100%;\n\tpadding: 0.5rem 0.75rem;\n\tborder: none;\n\tbackground: transparent;\n\tcursor: pointer;\n\ttext-align: left;\n\tfont-size: 0.875rem;\n\ttransition: background-color 0.15s ease;\n}\n\n.row-action-menu-item:hover {\n\tbackground-color: var(--sc-gray-10);\n}\n\n.row-action-menu-item:focus {\n\toutline: none;\n\tbackground-color: var(--sc-gray-10);\n}\n\n.row-action-menu-item:disabled,\n.row-action-btn:disabled {\n\topacity: 0.4;\n\tcursor: not-allowed;\n}\n\n.row-action-menu-item:disabled:hover,\n.row-action-btn:disabled:hover {\n\tbackground-color: transparent;\n}\n\n.row-action-menu-item .action-icon {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 1rem;\n\theight: 1rem;\n\tflex-shrink: 0;\n}\n\n.row-action-menu-item .action-icon svg {\n\twidth: 100%;\n\theight: 100%;\n}\n\n.row-action-menu-item .action-label {\n\tflex: 1;\n}\n</style>\n","<template>\n\t<td\n\t\tref=\"actionsCell\"\n\t\tclass=\"atable-row-actions\"\n\t\t:class=\"{ 'sticky-column': position === 'before-index', 'dropdown-active': dropdownOpen }\">\n\t\t<!-- Dropdown mode -->\n\t\t<div v-if=\"showDropdown\" class=\"row-actions-dropdown\">\n\t\t\t<button\n\t\t\t\tref=\"toggleButton\"\n\t\t\t\ttype=\"button\"\n\t\t\t\tclass=\"row-actions-toggle\"\n\t\t\t\t:aria-expanded=\"dropdownOpen\"\n\t\t\t\taria-haspopup=\"true\"\n\t\t\t\t@click.stop=\"toggleDropdown\">\n\t\t\t\t<span class=\"dropdown-icon\">⋮</span>\n\t\t\t</button>\n\t\t\t<div\n\t\t\t\tv-show=\"dropdownOpen\"\n\t\t\t\tclass=\"row-actions-menu\"\n\t\t\t\t:class=\"{ 'menu-flipped': dropdownFlipped }\"\n\t\t\t\t:style=\"menuStyle\"\n\t\t\t\trole=\"menu\">\n\t\t\t\t<button\n\t\t\t\t\tv-for=\"action in enabledActions\"\n\t\t\t\t\t:key=\"action.type\"\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"row-action-menu-item\"\n\t\t\t\t\trole=\"menuitem\"\n\t\t\t\t\t:disabled=\"action.disabled\"\n\t\t\t\t\t@click.stop=\"executeAction(action.type, $event)\">\n\t\t\t\t\t<span class=\"action-icon\" v-html=\"action.icon\" />\n\t\t\t\t\t<span class=\"action-label\">{{ action.label }}</span>\n\t\t\t\t</button>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<!-- Icon mode -->\n\t\t<div v-else class=\"row-actions-icons\">\n\t\t\t<button\n\t\t\t\tv-for=\"action in enabledActions\"\n\t\t\t\t:key=\"action.type\"\n\t\t\t\ttype=\"button\"\n\t\t\t\tclass=\"row-action-btn\"\n\t\t\t\t:title=\"action.label\"\n\t\t\t\t:aria-label=\"action.label\"\n\t\t\t\t:disabled=\"action.disabled\"\n\t\t\t\t@click.stop=\"executeAction(action.type, $event)\">\n\t\t\t\t<span class=\"action-icon\" v-html=\"action.icon\" />\n\t\t\t</button>\n\t\t</div>\n\t</td>\n</template>\n\n<script setup lang=\"ts\">\nimport { useResizeObserver, onClickOutside } from '@vueuse/core'\nimport { computed, ref, useTemplateRef } from 'vue'\n\nimport { actionIcons } from '../icons'\nimport { createTableStore } from '../stores/table'\nimport type { RowActionsConfig, RowActionType } from '../types'\n\nconst props = defineProps<{\n\trowIndex: number\n\tstore: ReturnType<typeof createTableStore>\n\tconfig: RowActionsConfig\n\tposition?: 'before-index' | 'after-index' | 'end'\n}>()\n\nconst emit = defineEmits<{\n\taction: [type: RowActionType, rowIndex: number, event?: MouseEvent]\n}>()\n\nconst actionsCellRef = useTemplateRef<HTMLTableCellElement>('actionsCell')\nconst toggleButtonRef = useTemplateRef<HTMLButtonElement>('toggleButton')\nconst cellWidth = ref(0)\nconst dropdownOpen = ref(false)\nconst dropdownFlipped = ref(false)\nconst menuPosition = ref({ top: 0, left: 0 })\n\n// Default labels for actions\nconst defaultLabels: Record<RowActionType, string> = {\n\tadd: 'Add Record',\n\tdelete: 'Delete Record',\n\tduplicate: 'Duplicate Record',\n\tinsertAbove: 'Insert Above',\n\tinsertBelow: 'Insert Below',\n\tmove: 'Move Record',\n\tmoveUp: 'Move Up',\n\tmoveDown: 'Move Down',\n\topen: 'Open Record',\n}\n\n// Determine which actions are enabled\nconst enabledActions = computed(() => {\n\tconst actions: Array<{ type: RowActionType; label: string; icon: string; disabled: boolean }> = []\n\tconst configActions = props.config.actions || {}\n\n\tconst actionTypes: RowActionType[] = [\n\t\t'open',\n\t\t'moveUp',\n\t\t'moveDown',\n\t\t'duplicate',\n\t\t'insertAbove',\n\t\t'insertBelow',\n\t\t'add',\n\t\t'delete',\n\t\t'move',\n\t]\n\n\tfor (const type of actionTypes) {\n\t\tconst actionConfig = configActions[type]\n\n\t\t// Skip if explicitly disabled\n\t\tif (actionConfig === false) continue\n\n\t\t// Skip if not configured and we're being explicit\n\t\tif (actionConfig === undefined) continue\n\n\t\tlet enabled = true\n\t\tlet label = defaultLabels[type]\n\t\tlet icon = actionIcons[type]\n\t\tlet disabled = false\n\n\t\tif (typeof actionConfig === 'object') {\n\t\t\tenabled = actionConfig.enabled !== false\n\t\t\tlabel = actionConfig.label || label\n\t\t\ticon = actionConfig.icon || icon\n\t\t\t// Per-row predicate; reading store state here keeps this computed reactive to row changes.\n\t\t\tif (actionConfig.disabled) disabled = actionConfig.disabled(props.rowIndex, props.store)\n\t\t}\n\n\t\tif (enabled) {\n\t\t\tactions.push({ type, label, icon, disabled })\n\t\t}\n\t}\n\n\treturn actions\n})\n\n// Determine if we should show dropdown mode\nconst showDropdown = computed(() => {\n\tif (props.config.forceDropdown) return true\n\n\tconst threshold = props.config.dropdownThreshold ?? 150\n\tif (threshold === 0) return false\n\n\treturn cellWidth.value > 0 && cellWidth.value < threshold\n})\n\n// Compute menu style for fixed positioning\nconst menuStyle = computed(() => {\n\tif (!dropdownOpen.value) return {}\n\n\tif (dropdownFlipped.value) {\n\t\treturn {\n\t\t\tposition: 'fixed' as const,\n\t\t\tbottom: `${window.innerHeight - menuPosition.value.top}px`,\n\t\t\tleft: `${menuPosition.value.left}px`,\n\t\t\ttop: 'auto',\n\t\t}\n\t}\n\treturn {\n\t\tposition: 'fixed' as const,\n\t\ttop: `${menuPosition.value.top}px`,\n\t\tleft: `${menuPosition.value.left}px`,\n\t}\n})\n\n// Track cell width for responsive behavior\nuseResizeObserver(actionsCellRef, entries => {\n\tconst entry = entries[0]\n\tif (entry) {\n\t\tcellWidth.value = entry.contentRect.width\n\t}\n})\n\n// Toggle dropdown menu\nconst toggleDropdown = () => {\n\tif (!dropdownOpen.value) {\n\t\t// Opening - check if we need to flip\n\t\tcheckDropdownPosition()\n\t}\n\tdropdownOpen.value = !dropdownOpen.value\n}\n\n// Check if dropdown should flip upward and calculate position\nconst checkDropdownPosition = () => {\n\tif (!toggleButtonRef.value) return\n\n\tconst buttonRect = toggleButtonRef.value.getBoundingClientRect()\n\tconst viewportHeight = window.innerHeight\n\tconst viewportWidth = window.innerWidth\n\tconst estimatedMenuHeight = enabledActions.value.length * 40 + 16 // ~40px per item + padding\n\tconst estimatedMenuWidth = 160 // matches min-width: 10rem\n\n\t// Check if menu would extend beyond viewport bottom\n\tconst spaceBelow = viewportHeight - buttonRect.bottom\n\tconst spaceAbove = buttonRect.top\n\n\t// Flip if not enough space below but enough space above\n\tdropdownFlipped.value = spaceBelow < estimatedMenuHeight && spaceAbove > estimatedMenuHeight\n\n\t// Horizontal: anchor the menu's left edge to the button, but right-align it to the button when\n\t// it would overflow the viewport's right edge (e.g. an end-positioned actions column).\n\tlet left = buttonRect.left\n\tif (left + estimatedMenuWidth > viewportWidth) {\n\t\tleft = Math.max(0, buttonRect.right - estimatedMenuWidth)\n\t}\n\n\t// Calculate fixed position\n\tmenuPosition.value = {\n\t\ttop: dropdownFlipped.value ? buttonRect.top : buttonRect.bottom,\n\t\tleft,\n\t}\n}\n\nonClickOutside(actionsCellRef, () => {\n\tdropdownOpen.value = false\n})\n\n// Execute an action\nconst executeAction = (actionType: RowActionType, event?: MouseEvent) => {\n\tdropdownOpen.value = false\n\n\t// Check for custom handler\n\tconst actionConfig = props.config.actions?.[actionType]\n\tif (typeof actionConfig === 'object' && actionConfig.handler) {\n\t\tconst result = actionConfig.handler(props.rowIndex, props.store)\n\t\tif (result === false) {\n\t\t\t// Handler returned false, don't proceed with default behavior\n\t\t\treturn\n\t\t}\n\t}\n\n\t// Emit the action event for parent to handle\n\temit('action', actionType, props.rowIndex, event)\n}\n</script>\n\n<style>\n.atable-row-actions {\n\twidth: 2rem;\n\tmin-width: 2rem;\n\tpadding: 0 0.25rem;\n\tvertical-align: middle;\n\twhite-space: nowrap;\n\tborder-top: 1px solid var(--sc-row-border-color);\n\tbackground: white;\n\tuser-select: none;\n\tposition: relative;\n}\n\n.atable-row-actions.dropdown-active {\n\tz-index: 101;\n}\n\n.row-actions-icons {\n\tdisplay: flex;\n\tgap: 0.25rem;\n\talign-items: center;\n\tjustify-content: center;\n}\n\n.row-action-btn {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 1.5rem;\n\theight: 1.5rem;\n\tpadding: 0.125rem;\n\tborder: none;\n\tbackground: transparent;\n\tcursor: pointer;\n\tborder-radius: 0.25rem;\n\ttransition: background-color 0.15s ease;\n}\n\n.row-action-btn:hover {\n\tbackground-color: var(--sc-gray-10);\n}\n\n.row-action-btn:focus {\n\toutline: 2px solid var(--sc-focus-cell-outline);\n\toutline-offset: 1px;\n}\n\n.row-action-btn .action-icon {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 1rem;\n\theight: 1rem;\n}\n\n.row-action-btn .action-icon svg {\n\twidth: 100%;\n\theight: 100%;\n}\n\n/* Dropdown mode styles */\n.row-actions-dropdown {\n\tposition: relative;\n\tdisplay: inline-block;\n}\n.row-actions-dropdown:has(button:focus) {\n\toutline: 2px solid var(--sc-focus-cell-outline);\n\toutline-offset: -2px;\n}\n\n.row-actions-toggle {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 1.5rem;\n\theight: 1.5rem;\n\tpadding: 0;\n\tborder: none;\n\tbackground: transparent;\n\tcursor: pointer;\n\tborder-radius: 0.25rem;\n\tfont-size: 1rem;\n\tfont-weight: bold;\n\ttransition: background-color 0.15s ease;\n}\n\n.row-actions-toggle:hover {\n\tbackground-color: var(--sc-gray-10);\n}\n\n.row-actions-toggle:focus {\n\t/* outline: 2px solid var(--sc-focus-cell-outline);\n\toutline-offset: 1px; */\n}\n\n.dropdown-icon {\n\tline-height: 1;\n}\n\n.row-actions-menu {\n\tposition: fixed;\n\tz-index: 100;\n\tmin-width: 10rem;\n\tpadding: 0.25rem 0;\n\tbackground: white;\n\tborder: 1px solid var(--sc-row-border-color);\n\tborder-left: 4px solid var(--sc-row-border-color);\n\tborder-radius: 0;\n}\n\n.row-actions-menu.menu-flipped {\n\tbox-shadow:\n\t\t0 -4px 6px -1px rgb(0 0 0 / 0.1),\n\t\t0 -2px 4px -2px rgb(0 0 0 / 0.1);\n}\n\n.row-action-menu-item {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 0.5rem;\n\twidth: 100%;\n\tpadding: 0.5rem 0.75rem;\n\tborder: none;\n\tbackground: transparent;\n\tcursor: pointer;\n\ttext-align: left;\n\tfont-size: 0.875rem;\n\ttransition: background-color 0.15s ease;\n}\n\n.row-action-menu-item:hover {\n\tbackground-color: var(--sc-gray-10);\n}\n\n.row-action-menu-item:focus {\n\toutline: none;\n\tbackground-color: var(--sc-gray-10);\n}\n\n.row-action-menu-item:disabled,\n.row-action-btn:disabled {\n\topacity: 0.4;\n\tcursor: not-allowed;\n}\n\n.row-action-menu-item:disabled:hover,\n.row-action-btn:disabled:hover {\n\tbackground-color: transparent;\n}\n\n.row-action-menu-item .action-icon {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 1rem;\n\theight: 1rem;\n\tflex-shrink: 0;\n}\n\n.row-action-menu-item .action-icon svg {\n\twidth: 100%;\n\theight: 100%;\n}\n\n.row-action-menu-item .action-label {\n\tflex: 1;\n}\n</style>\n","<template>\n\t<tr\n\t\tv-show=\"isRowVisible\"\n\t\tv-bind=\"$attrs\"\n\t\tref=\"rowEl\"\n\t\t:tabindex=\"tabIndex\"\n\t\tclass=\"atable-row\"\n\t\t:class=\"{ 'atable-row-clickable': isClickable }\"\n\t\t@click=\"onRowClick\">\n\t\t<!-- Row actions before index (default position) -->\n\t\t<ARowActions\n\t\t\tv-if=\"showRowActions && actionsPosition === 'before-index'\"\n\t\t\t:row-index=\"rowIndex\"\n\t\t\t:store=\"store\"\n\t\t\t:config=\"rowActionsConfig\"\n\t\t\t:position=\"actionsPosition\"\n\t\t\t@action=\"onRowAction\" />\n\n\t\t<!-- render numbered/tree view index; skip render for uncounted lists -->\n\t\t<slot v-if=\"store.config.view !== 'uncounted'\" name=\"index\">\n\t\t\t<td\n\t\t\t\tv-if=\"store.config.view === 'list'\"\n\t\t\t\t:tabIndex=\"-1\"\n\t\t\t\tclass=\"list-index\"\n\t\t\t\t:class=\"store.hasPinnedColumns ? 'sticky-index' : ''\">\n\t\t\t\t{{ rowIndex + 1 }}\n\t\t\t</td>\n\t\t\t<td\n\t\t\t\tv-else-if=\"store.isTreeView\"\n\t\t\t\t:tabIndex=\"-1\"\n\t\t\t\tclass=\"tree-index\"\n\t\t\t\t:class=\"store.hasPinnedColumns ? 'sticky-index' : ''\"\n\t\t\t\t@click=\"store.toggleRowExpand(rowIndex)\">\n\t\t\t\t{{ rowExpandSymbol }}\n\t\t\t</td>\n\t\t\t<td\n\t\t\t\tv-else-if=\"store.config.view === 'list-expansion'\"\n\t\t\t\t:tabIndex=\"-1\"\n\t\t\t\tclass=\"expansion-index\"\n\t\t\t\t:class=\"store.hasPinnedColumns ? 'sticky-index' : ''\"\n\t\t\t\t@click=\"store.toggleRowExpand(rowIndex)\">\n\t\t\t\t{{ rowExpandSymbol }}\n\t\t\t</td>\n\t\t</slot>\n\n\t\t<!-- Row actions after index -->\n\t\t<ARowActions\n\t\t\tv-if=\"showRowActions && actionsPosition === 'after-index'\"\n\t\t\t:row-index=\"rowIndex\"\n\t\t\t:store=\"store\"\n\t\t\t:config=\"rowActionsConfig\"\n\t\t\t:position=\"actionsPosition\"\n\t\t\t@action=\"onRowAction\" />\n\n\t\t<!-- render cell content -->\n\t\t<slot></slot>\n\n\t\t<!-- Row actions at end -->\n\t\t<ARowActions\n\t\t\tv-if=\"showRowActions && actionsPosition === 'end'\"\n\t\t\t:row-index=\"rowIndex\"\n\t\t\t:store=\"store\"\n\t\t\t:config=\"rowActionsConfig\"\n\t\t\t:position=\"actionsPosition\"\n\t\t\t@action=\"onRowAction\" />\n\t</tr>\n\n\t<!-- list-expansion content panel: a second row spanning the whole width -->\n\t<tr v-if=\"isExpanded\" :tabindex=\"tabIndex\" class=\"atable-expanded-row\">\n\t\t<td :tabIndex=\"-1\" :colspan=\"expandedColspan\" class=\"atable-expanded-content\">\n\t\t\t<slot name=\"content\" :row=\"store.rows[rowIndex]\" :row-index=\"rowIndex\" :store=\"store\" />\n\t\t</td>\n\t</tr>\n</template>\n\n<script setup lang=\"ts\">\nimport { type KeypressHandlers, useKeyboardNav, defaultKeypressHandlers } from '@stonecrop/utilities'\nimport { computed, useTemplateRef } from 'vue'\n\nimport ARowActions from './ARowActions.vue'\nimport { createTableStore } from '../stores/table'\nimport type { RowActionsConfig, RowActionType } from '../types'\n\nconst {\n\trowIndex,\n\tstore,\n\ttabIndex = -1,\n\taddNavigation = false, // default to allowing cell navigation\n} = defineProps<{\n\trowIndex: number\n\tstore: ReturnType<typeof createTableStore>\n\ttabIndex?: number\n\taddNavigation?: boolean | KeypressHandlers\n}>()\n\nconst emit = defineEmits<{\n\t'row:action': [type: RowActionType, rowIndex: number, event?: MouseEvent]\n\t'row:click': [rowIndex: number, event: MouseEvent]\n}>()\n\nconst rowRef = useTemplateRef<HTMLTableRowElement>('rowEl')\n\nconst isRowVisible = computed(() => store.isRowVisible(rowIndex))\nconst rowExpandSymbol = computed(() => store.getRowExpandSymbol(rowIndex))\nconst isClickable = computed(() => store.config.clickable ?? false)\n\n// Row actions configuration\nconst rowActionsConfig = computed((): RowActionsConfig => {\n\treturn store.config.rowActions || { enabled: false }\n})\n\nconst showRowActions = computed(() => {\n\treturn rowActionsConfig.value.enabled\n})\n\nconst actionsPosition = computed(() => {\n\treturn rowActionsConfig.value.position || 'before-index'\n})\n\n// list-expansion: this row owns an expandable content panel (a second <tr>).\nconst isExpanded = computed(() => store.config.view === 'list-expansion' && Boolean(store.display[rowIndex]?.expanded))\n\n// The content panel spans every column the main row occupies: data columns + the\n// index/chevron column (absent only in uncounted) + the row-actions column when enabled.\nconst expandedColspan = computed(() => {\n\tconst indexCol = store.config.view === 'uncounted' ? 0 : 1\n\tconst actionsCol = showRowActions.value ? 1 : 0\n\treturn store.columns.length + indexCol + actionsCol\n})\n\nconst onRowAction = (actionType: RowActionType, index: number, event?: MouseEvent) => {\n\temit('row:action', actionType, index, event)\n}\n\nconst onRowClick = (event: MouseEvent) => {\n\t// Ignore clicks on the row actions cell or an expand/collapse chevron (tree or list-expansion),\n\t// so toggling a chevron never doubles as a row-click navigation.\n\tconst target = event.target as HTMLElement\n\tif (target.closest('.atable-row-actions') || target.closest('.tree-index') || target.closest('.expansion-index'))\n\t\treturn\n\temit('row:click', rowIndex, event)\n}\n\n// A list-expansion row always binds Ctrl+G to toggle its own panel while opt-in\n// cell navigation stays gated on `addNavigation` (default off), so other view\n// types are unchanged.\nconst isListExpansion = store.config.view === 'list-expansion'\n\nif (addNavigation || isListExpansion) {\n\tlet handlers: KeypressHandlers = {}\n\n\tif (addNavigation === true) {\n\t\thandlers = { ...defaultKeypressHandlers }\n\t} else if (typeof addNavigation === 'object') {\n\t\thandlers = { ...defaultKeypressHandlers, ...addNavigation }\n\t}\n\n\tif (isListExpansion && !handlers['keydown.control.g']) {\n\t\thandlers['keydown.control.g'] = (event: KeyboardEvent) => {\n\t\t\tevent.stopPropagation()\n\t\t\tevent.preventDefault()\n\t\t\tstore.toggleRowExpand(rowIndex)\n\t\t}\n\t}\n\n\tuseKeyboardNav([\n\t\t{\n\t\t\tselectors: rowRef,\n\t\t\thandlers: handlers,\n\t\t},\n\t])\n}\n</script>\n\n<style>\n.atable-row {\n\tbackground-color: white;\n}\n\n.atable-row-clickable {\n\tcursor: pointer;\n}\n\n.atable-row-clickable:hover > td {\n\tbackground-color: var(--sc-row-hover-color);\n}\n\n.atable-row:last-child > td {\n\tborder-bottom: 1px solid var(--sc-row-border-color);\n}\n\n.atable-row > td:first-child {\n\tborder-left: 4px solid var(--sc-row-border-color);\n}\n\n.atable-row > td:last-child {\n\tborder-right: 1px solid var(--sc-row-border-color);\n}\n\n.list-index {\n\tcolor: var(--sc-header-text-color);\n\tfont-weight: bold;\n\tpadding-left: var(--sc-atable-row-padding);\n\tpadding-right: 0.5em;\n\ttext-align: left;\n\tuser-select: none;\n\t/* width: 7ch; */\n\tborder-top: 1px solid var(--sc-row-border-color);\n\ttext-overflow: ellipsis;\n\toverflow: hidden;\n\tbox-sizing: border-box;\n\tpadding-top: var(--sc-atable-row-padding);\n\tpadding-bottom: var(--sc-atable-row-padding);\n}\n\n.tree-index,\n.expansion-index {\n\tcolor: var(--sc-header-text-color);\n\tfont-weight: bold;\n\ttext-align: center;\n\tuser-select: none;\n\twidth: 2ch;\n\tbox-sizing: border-box;\n\tcursor: pointer;\n\tpadding-top: var(--sc-atable-row-padding);\n\tpadding-bottom: var(--sc-atable-row-padding);\n}\n\n.atable-expanded-row {\n\tborder-left: 2px solid var(--sc-row-border-color);\n}\n\n.atable-expanded-content {\n\tborder-top: 1px solid var(--sc-row-border-color);\n\tpadding: 1.5rem;\n}\n/* sticky cells in modified rows should be a solid color to properly hide non-sticky cells */\n.atable-row:has(td.cell-modified) > td.sticky-column,\n.atable-row:has(td.cell-modified) > th.sticky-column,\n.atable-row:has(td.cell-modified) > td.sticky-index,\n.atable-row:has(td.cell-modified) > th.sticky-index {\n\tbackground: var(--sc-cell-changed-color);\n}\n</style>\n<style scoped>\n.atable-row.changed-row-gradient:has(td.cell-modified) {\n\t--cell-color-start: color-mix(in srgb, var(--sc-cell-changed-color), #fff 20%);\n\t--cell-color-end: color-mix(in srgb, var(--sc-cell-changed-color), #fff 60%);\n\tbackground: linear-gradient(90deg, var(--cell-color-start), var(--cell-color-end));\n}\n</style>\n","<template>\n\t<tr\n\t\tv-show=\"isRowVisible\"\n\t\tv-bind=\"$attrs\"\n\t\tref=\"rowEl\"\n\t\t:tabindex=\"tabIndex\"\n\t\tclass=\"atable-row\"\n\t\t:class=\"{ 'atable-row-clickable': isClickable }\"\n\t\t@click=\"onRowClick\">\n\t\t<!-- Row actions before index (default position) -->\n\t\t<ARowActions\n\t\t\tv-if=\"showRowActions && actionsPosition === 'before-index'\"\n\t\t\t:row-index=\"rowIndex\"\n\t\t\t:store=\"store\"\n\t\t\t:config=\"rowActionsConfig\"\n\t\t\t:position=\"actionsPosition\"\n\t\t\t@action=\"onRowAction\" />\n\n\t\t<!-- render numbered/tree view index; skip render for uncounted lists -->\n\t\t<slot v-if=\"store.config.view !== 'uncounted'\" name=\"index\">\n\t\t\t<td\n\t\t\t\tv-if=\"store.config.view === 'list'\"\n\t\t\t\t:tabIndex=\"-1\"\n\t\t\t\tclass=\"list-index\"\n\t\t\t\t:class=\"store.hasPinnedColumns ? 'sticky-index' : ''\">\n\t\t\t\t{{ rowIndex + 1 }}\n\t\t\t</td>\n\t\t\t<td\n\t\t\t\tv-else-if=\"store.isTreeView\"\n\t\t\t\t:tabIndex=\"-1\"\n\t\t\t\tclass=\"tree-index\"\n\t\t\t\t:class=\"store.hasPinnedColumns ? 'sticky-index' : ''\"\n\t\t\t\t@click=\"store.toggleRowExpand(rowIndex)\">\n\t\t\t\t{{ rowExpandSymbol }}\n\t\t\t</td>\n\t\t\t<td\n\t\t\t\tv-else-if=\"store.config.view === 'list-expansion'\"\n\t\t\t\t:tabIndex=\"-1\"\n\t\t\t\tclass=\"expansion-index\"\n\t\t\t\t:class=\"store.hasPinnedColumns ? 'sticky-index' : ''\"\n\t\t\t\t@click=\"store.toggleRowExpand(rowIndex)\">\n\t\t\t\t{{ rowExpandSymbol }}\n\t\t\t</td>\n\t\t</slot>\n\n\t\t<!-- Row actions after index -->\n\t\t<ARowActions\n\t\t\tv-if=\"showRowActions && actionsPosition === 'after-index'\"\n\t\t\t:row-index=\"rowIndex\"\n\t\t\t:store=\"store\"\n\t\t\t:config=\"rowActionsConfig\"\n\t\t\t:position=\"actionsPosition\"\n\t\t\t@action=\"onRowAction\" />\n\n\t\t<!-- render cell content -->\n\t\t<slot></slot>\n\n\t\t<!-- Row actions at end -->\n\t\t<ARowActions\n\t\t\tv-if=\"showRowActions && actionsPosition === 'end'\"\n\t\t\t:row-index=\"rowIndex\"\n\t\t\t:store=\"store\"\n\t\t\t:config=\"rowActionsConfig\"\n\t\t\t:position=\"actionsPosition\"\n\t\t\t@action=\"onRowAction\" />\n\t</tr>\n\n\t<!-- list-expansion content panel: a second row spanning the whole width -->\n\t<tr v-if=\"isExpanded\" :tabindex=\"tabIndex\" class=\"atable-expanded-row\">\n\t\t<td :tabIndex=\"-1\" :colspan=\"expandedColspan\" class=\"atable-expanded-content\">\n\t\t\t<slot name=\"content\" :row=\"store.rows[rowIndex]\" :row-index=\"rowIndex\" :store=\"store\" />\n\t\t</td>\n\t</tr>\n</template>\n\n<script setup lang=\"ts\">\nimport { type KeypressHandlers, useKeyboardNav, defaultKeypressHandlers } from '@stonecrop/utilities'\nimport { computed, useTemplateRef } from 'vue'\n\nimport ARowActions from './ARowActions.vue'\nimport { createTableStore } from '../stores/table'\nimport type { RowActionsConfig, RowActionType } from '../types'\n\nconst {\n\trowIndex,\n\tstore,\n\ttabIndex = -1,\n\taddNavigation = false, // default to allowing cell navigation\n} = defineProps<{\n\trowIndex: number\n\tstore: ReturnType<typeof createTableStore>\n\ttabIndex?: number\n\taddNavigation?: boolean | KeypressHandlers\n}>()\n\nconst emit = defineEmits<{\n\t'row:action': [type: RowActionType, rowIndex: number, event?: MouseEvent]\n\t'row:click': [rowIndex: number, event: MouseEvent]\n}>()\n\nconst rowRef = useTemplateRef<HTMLTableRowElement>('rowEl')\n\nconst isRowVisible = computed(() => store.isRowVisible(rowIndex))\nconst rowExpandSymbol = computed(() => store.getRowExpandSymbol(rowIndex))\nconst isClickable = computed(() => store.config.clickable ?? false)\n\n// Row actions configuration\nconst rowActionsConfig = computed((): RowActionsConfig => {\n\treturn store.config.rowActions || { enabled: false }\n})\n\nconst showRowActions = computed(() => {\n\treturn rowActionsConfig.value.enabled\n})\n\nconst actionsPosition = computed(() => {\n\treturn rowActionsConfig.value.position || 'before-index'\n})\n\n// list-expansion: this row owns an expandable content panel (a second <tr>).\nconst isExpanded = computed(() => store.config.view === 'list-expansion' && Boolean(store.display[rowIndex]?.expanded))\n\n// The content panel spans every column the main row occupies: data columns + the\n// index/chevron column (absent only in uncounted) + the row-actions column when enabled.\nconst expandedColspan = computed(() => {\n\tconst indexCol = store.config.view === 'uncounted' ? 0 : 1\n\tconst actionsCol = showRowActions.value ? 1 : 0\n\treturn store.columns.length + indexCol + actionsCol\n})\n\nconst onRowAction = (actionType: RowActionType, index: number, event?: MouseEvent) => {\n\temit('row:action', actionType, index, event)\n}\n\nconst onRowClick = (event: MouseEvent) => {\n\t// Ignore clicks on the row actions cell or an expand/collapse chevron (tree or list-expansion),\n\t// so toggling a chevron never doubles as a row-click navigation.\n\tconst target = event.target as HTMLElement\n\tif (target.closest('.atable-row-actions') || target.closest('.tree-index') || target.closest('.expansion-index'))\n\t\treturn\n\temit('row:click', rowIndex, event)\n}\n\n// A list-expansion row always binds Ctrl+G to toggle its own panel while opt-in\n// cell navigation stays gated on `addNavigation` (default off), so other view\n// types are unchanged.\nconst isListExpansion = store.config.view === 'list-expansion'\n\nif (addNavigation || isListExpansion) {\n\tlet handlers: KeypressHandlers = {}\n\n\tif (addNavigation === true) {\n\t\thandlers = { ...defaultKeypressHandlers }\n\t} else if (typeof addNavigation === 'object') {\n\t\thandlers = { ...defaultKeypressHandlers, ...addNavigation }\n\t}\n\n\tif (isListExpansion && !handlers['keydown.control.g']) {\n\t\thandlers['keydown.control.g'] = (event: KeyboardEvent) => {\n\t\t\tevent.stopPropagation()\n\t\t\tevent.preventDefault()\n\t\t\tstore.toggleRowExpand(rowIndex)\n\t\t}\n\t}\n\n\tuseKeyboardNav([\n\t\t{\n\t\t\tselectors: rowRef,\n\t\t\thandlers: handlers,\n\t\t},\n\t])\n}\n</script>\n\n<style>\n.atable-row {\n\tbackground-color: white;\n}\n\n.atable-row-clickable {\n\tcursor: pointer;\n}\n\n.atable-row-clickable:hover > td {\n\tbackground-color: var(--sc-row-hover-color);\n}\n\n.atable-row:last-child > td {\n\tborder-bottom: 1px solid var(--sc-row-border-color);\n}\n\n.atable-row > td:first-child {\n\tborder-left: 4px solid var(--sc-row-border-color);\n}\n\n.atable-row > td:last-child {\n\tborder-right: 1px solid var(--sc-row-border-color);\n}\n\n.list-index {\n\tcolor: var(--sc-header-text-color);\n\tfont-weight: bold;\n\tpadding-left: var(--sc-atable-row-padding);\n\tpadding-right: 0.5em;\n\ttext-align: left;\n\tuser-select: none;\n\t/* width: 7ch; */\n\tborder-top: 1px solid var(--sc-row-border-color);\n\ttext-overflow: ellipsis;\n\toverflow: hidden;\n\tbox-sizing: border-box;\n\tpadding-top: var(--sc-atable-row-padding);\n\tpadding-bottom: var(--sc-atable-row-padding);\n}\n\n.tree-index,\n.expansion-index {\n\tcolor: var(--sc-header-text-color);\n\tfont-weight: bold;\n\ttext-align: center;\n\tuser-select: none;\n\twidth: 2ch;\n\tbox-sizing: border-box;\n\tcursor: pointer;\n\tpadding-top: var(--sc-atable-row-padding);\n\tpadding-bottom: var(--sc-atable-row-padding);\n}\n\n.atable-expanded-row {\n\tborder-left: 2px solid var(--sc-row-border-color);\n}\n\n.atable-expanded-content {\n\tborder-top: 1px solid var(--sc-row-border-color);\n\tpadding: 1.5rem;\n}\n/* sticky cells in modified rows should be a solid color to properly hide non-sticky cells */\n.atable-row:has(td.cell-modified) > td.sticky-column,\n.atable-row:has(td.cell-modified) > th.sticky-column,\n.atable-row:has(td.cell-modified) > td.sticky-index,\n.atable-row:has(td.cell-modified) > th.sticky-index {\n\tbackground: var(--sc-cell-changed-color);\n}\n</style>\n<style scoped>\n.atable-row.changed-row-gradient:has(td.cell-modified) {\n\t--cell-color-start: color-mix(in srgb, var(--sc-cell-changed-color), #fff 20%);\n\t--cell-color-end: color-mix(in srgb, var(--sc-cell-changed-color), #fff 60%);\n\tbackground: linear-gradient(90deg, var(--cell-color-start), var(--cell-color-end));\n}\n</style>\n","<template>\n\t<div class=\"gantt-connection-overlay\">\n\t\t<svg\n\t\t\tclass=\"connection-svg\"\n\t\t\t:style=\"{\n\t\t\t\tposition: 'absolute',\n\t\t\t\ttop: 0,\n\t\t\t\tleft: 0,\n\t\t\t\twidth: '100%',\n\t\t\t\theight: '100%',\n\t\t\t\tpointerEvents: 'none',\n\t\t\t\tzIndex: 1,\n\t\t\t}\">\n\t\t\t<defs>\n\t\t\t\t<!-- Define arrowhead marker for connections -->\n\t\t\t\t<path id=\"arrowhead\" d=\"M 0 -7 L 20 0 L 0 7Z\" stroke=\"black\" stroke-width=\"1\" fill=\"currentColor\"></path>\n\t\t\t\t<marker\n\t\t\t\t\tid=\"arrowhead-marker\"\n\t\t\t\t\tmarkerWidth=\"10\"\n\t\t\t\t\tmarkerHeight=\"7\"\n\t\t\t\t\trefX=\"5\"\n\t\t\t\t\trefY=\"3.5\"\n\t\t\t\t\torient=\"auto\"\n\t\t\t\t\tmarkerUnits=\"strokeWidth\">\n\t\t\t\t\t<polygon points=\"0 0, 10 3.5, 0 7\" fill=\"currentColor\" />\n\t\t\t\t</marker>\n\t\t\t</defs>\n\n\t\t\t<!-- Invisible wider path for easier double-click interaction -->\n\t\t\t<path\n\t\t\t\tv-for=\"connection in visibleConnections\"\n\t\t\t\t:key=\"`${connection.id}-hitbox`\"\n\t\t\t\t:d=\"getPathData(connection)\"\n\t\t\t\tstroke=\"transparent\"\n\t\t\t\t:stroke-width=\"(connection.style?.width || 2) + 10\"\n\t\t\t\tfill=\"none\"\n\t\t\t\tclass=\"connection-hitbox\"\n\t\t\t\t@dblclick=\"handleConnectionDelete(connection)\" />\n\n\t\t\t<!-- Visible connection path -->\n\t\t\t<path\n\t\t\t\tv-for=\"connection in visibleConnections\"\n\t\t\t\t:id=\"connection.id\"\n\t\t\t\t:key=\"connection.id\"\n\t\t\t\t:d=\"getPathData(connection)\"\n\t\t\t\t:stroke=\"connection.style?.color || '#666'\"\n\t\t\t\t:stroke-width=\"connection.style?.width || 2\"\n\t\t\t\tfill=\"none\"\n\t\t\t\tmarker-mid=\"url(#arrowhead-marker)\"\n\t\t\t\tclass=\"connection-path animated-path\"\n\t\t\t\t@dblclick=\"handleConnectionDelete(connection)\" />\n\t\t</svg>\n\t</div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nimport { createTableStore } from '../stores/table'\nimport type { ConnectionPath } from '../types'\n\nconst { store } = defineProps<{\n\tstore: ReturnType<typeof createTableStore>\n}>()\n\nconst emit = defineEmits<{\n\t'connection:delete': [connection: ConnectionPath]\n}>()\n\nconst BEZIER_CURVE_FACTOR = 0.25 // Control point offset factor for bezier curves\nconst CONNECTION_HANDLE_SIZE = 16 // Width of the connection handles; this should match the handle size in the AGanttCell component\n\nconst visibleConnections = computed(() => {\n\treturn store.connectionPaths.filter(connection => {\n\t\tconst fromBar = store.ganttBars.find(bar => bar.id === connection.from.barId)\n\t\tconst toBar = store.ganttBars.find(bar => bar.id === connection.to.barId)\n\t\treturn fromBar && toBar\n\t})\n})\n\nconst getPathData = (connection: ConnectionPath) => {\n\tconst fromHandle = store.connectionHandles.find(\n\t\thandle => handle.barId === connection.from.barId && handle.side === connection.from.side\n\t)\n\tconst toHandle = store.connectionHandles.find(\n\t\thandle => handle.barId === connection.to.barId && handle.side === connection.to.side\n\t)\n\n\tif (!fromHandle || !toHandle) return ''\n\n\tconst fromX = fromHandle.position.x + CONNECTION_HANDLE_SIZE / 2 // Center of the handle\n\tconst fromY = fromHandle.position.y + CONNECTION_HANDLE_SIZE / 2\n\tconst toX = toHandle.position.x + CONNECTION_HANDLE_SIZE / 2\n\tconst toY = toHandle.position.y + CONNECTION_HANDLE_SIZE / 2\n\n\t// Calculate control points for smooth bezier curve\n\tconst deltaX = Math.abs(toX - fromX)\n\tconst controlPointOffset = Math.max(deltaX * BEZIER_CURVE_FACTOR, 50) // Minimum offset for better curves\n\tconst cp1X = fromX + (connection.from.side === 'left' ? -controlPointOffset : controlPointOffset)\n\tconst cp2X = toX + (connection.to.side === 'left' ? -controlPointOffset : controlPointOffset)\n\n\t// Use cubic bezier curve for smooth connections\n\n\t//calculate the mid point of the curve\n\tconst m0 = { x: 0.5 * fromX + 0.5 * cp1X, y: 0.5 * fromY + 0.5 * fromY }\n\tconst m1 = { x: 0.5 * cp1X + 0.5 * cp2X, y: 0.5 * fromY + 0.5 * toY }\n\tconst m2 = { x: 0.5 * cp2X + 0.5 * toX, y: 0.5 * toY + 0.5 * toY }\n\tconst m3 = { x: 0.5 * m0.x + 0.5 * m1.x, y: 0.5 * m0.y + 0.5 * m1.y }\n\tconst m4 = { x: 0.5 * m1.x + 0.5 * m2.x, y: 0.5 * m1.y + 0.5 * m2.y }\n\tconst midpoint = { x: 0.5 * m3.x + 0.5 * m4.x, y: 0.5 * m3.y + 0.5 * m4.y }\n\n\t// Calculate the bezier curve using two arcs\n\treturn `M ${fromX} ${fromY} Q ${cp1X} ${fromY}, ${midpoint.x} ${midpoint.y} Q ${cp2X} ${toY}, ${toX} ${toY}`\n}\n\nconst handleConnectionDelete = (connection: ConnectionPath) => {\n\tif (store.deleteConnection(connection.id)) {\n\t\temit('connection:delete', connection)\n\t}\n}\n</script>\n\n<style scoped>\n.gantt-connection-overlay {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\twidth: 100%;\n\theight: 100%;\n\tpointer-events: none;\n\tz-index: 15;\n}\n\n.connection-path {\n\ttransition: stroke-width 0.2s ease;\n\tpointer-events: auto;\n\tcursor: pointer;\n\tstroke-dasharray: 5px;\n\tstroke: var(--sc-cell-text-color);\n}\n#arrowhead-marker polygon {\n\tfill: var(--sc-cell-text-color);\n}\n.animated-path {\n\tanimation: animated-dash infinite 1.5s linear;\n}\n\n.connection-path:hover {\n\tstroke-width: 3px;\n}\n\n.connection-hitbox {\n\tpointer-events: auto;\n\tcursor: pointer;\n}\n@keyframes animated-dash {\n\t0% {\n\t\tstroke-dashoffset: 0px;\n\t}\n\t100% {\n\t\tstroke-dashoffset: -10px;\n\t}\n}\n</style>\n","<template>\n\t<div class=\"gantt-connection-overlay\">\n\t\t<svg\n\t\t\tclass=\"connection-svg\"\n\t\t\t:style=\"{\n\t\t\t\tposition: 'absolute',\n\t\t\t\ttop: 0,\n\t\t\t\tleft: 0,\n\t\t\t\twidth: '100%',\n\t\t\t\theight: '100%',\n\t\t\t\tpointerEvents: 'none',\n\t\t\t\tzIndex: 1,\n\t\t\t}\">\n\t\t\t<defs>\n\t\t\t\t<!-- Define arrowhead marker for connections -->\n\t\t\t\t<path id=\"arrowhead\" d=\"M 0 -7 L 20 0 L 0 7Z\" stroke=\"black\" stroke-width=\"1\" fill=\"currentColor\"></path>\n\t\t\t\t<marker\n\t\t\t\t\tid=\"arrowhead-marker\"\n\t\t\t\t\tmarkerWidth=\"10\"\n\t\t\t\t\tmarkerHeight=\"7\"\n\t\t\t\t\trefX=\"5\"\n\t\t\t\t\trefY=\"3.5\"\n\t\t\t\t\torient=\"auto\"\n\t\t\t\t\tmarkerUnits=\"strokeWidth\">\n\t\t\t\t\t<polygon points=\"0 0, 10 3.5, 0 7\" fill=\"currentColor\" />\n\t\t\t\t</marker>\n\t\t\t</defs>\n\n\t\t\t<!-- Invisible wider path for easier double-click interaction -->\n\t\t\t<path\n\t\t\t\tv-for=\"connection in visibleConnections\"\n\t\t\t\t:key=\"`${connection.id}-hitbox`\"\n\t\t\t\t:d=\"getPathData(connection)\"\n\t\t\t\tstroke=\"transparent\"\n\t\t\t\t:stroke-width=\"(connection.style?.width || 2) + 10\"\n\t\t\t\tfill=\"none\"\n\t\t\t\tclass=\"connection-hitbox\"\n\t\t\t\t@dblclick=\"handleConnectionDelete(connection)\" />\n\n\t\t\t<!-- Visible connection path -->\n\t\t\t<path\n\t\t\t\tv-for=\"connection in visibleConnections\"\n\t\t\t\t:id=\"connection.id\"\n\t\t\t\t:key=\"connection.id\"\n\t\t\t\t:d=\"getPathData(connection)\"\n\t\t\t\t:stroke=\"connection.style?.color || '#666'\"\n\t\t\t\t:stroke-width=\"connection.style?.width || 2\"\n\t\t\t\tfill=\"none\"\n\t\t\t\tmarker-mid=\"url(#arrowhead-marker)\"\n\t\t\t\tclass=\"connection-path animated-path\"\n\t\t\t\t@dblclick=\"handleConnectionDelete(connection)\" />\n\t\t</svg>\n\t</div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nimport { createTableStore } from '../stores/table'\nimport type { ConnectionPath } from '../types'\n\nconst { store } = defineProps<{\n\tstore: ReturnType<typeof createTableStore>\n}>()\n\nconst emit = defineEmits<{\n\t'connection:delete': [connection: ConnectionPath]\n}>()\n\nconst BEZIER_CURVE_FACTOR = 0.25 // Control point offset factor for bezier curves\nconst CONNECTION_HANDLE_SIZE = 16 // Width of the connection handles; this should match the handle size in the AGanttCell component\n\nconst visibleConnections = computed(() => {\n\treturn store.connectionPaths.filter(connection => {\n\t\tconst fromBar = store.ganttBars.find(bar => bar.id === connection.from.barId)\n\t\tconst toBar = store.ganttBars.find(bar => bar.id === connection.to.barId)\n\t\treturn fromBar && toBar\n\t})\n})\n\nconst getPathData = (connection: ConnectionPath) => {\n\tconst fromHandle = store.connectionHandles.find(\n\t\thandle => handle.barId === connection.from.barId && handle.side === connection.from.side\n\t)\n\tconst toHandle = store.connectionHandles.find(\n\t\thandle => handle.barId === connection.to.barId && handle.side === connection.to.side\n\t)\n\n\tif (!fromHandle || !toHandle) return ''\n\n\tconst fromX = fromHandle.position.x + CONNECTION_HANDLE_SIZE / 2 // Center of the handle\n\tconst fromY = fromHandle.position.y + CONNECTION_HANDLE_SIZE / 2\n\tconst toX = toHandle.position.x + CONNECTION_HANDLE_SIZE / 2\n\tconst toY = toHandle.position.y + CONNECTION_HANDLE_SIZE / 2\n\n\t// Calculate control points for smooth bezier curve\n\tconst deltaX = Math.abs(toX - fromX)\n\tconst controlPointOffset = Math.max(deltaX * BEZIER_CURVE_FACTOR, 50) // Minimum offset for better curves\n\tconst cp1X = fromX + (connection.from.side === 'left' ? -controlPointOffset : controlPointOffset)\n\tconst cp2X = toX + (connection.to.side === 'left' ? -controlPointOffset : controlPointOffset)\n\n\t// Use cubic bezier curve for smooth connections\n\n\t//calculate the mid point of the curve\n\tconst m0 = { x: 0.5 * fromX + 0.5 * cp1X, y: 0.5 * fromY + 0.5 * fromY }\n\tconst m1 = { x: 0.5 * cp1X + 0.5 * cp2X, y: 0.5 * fromY + 0.5 * toY }\n\tconst m2 = { x: 0.5 * cp2X + 0.5 * toX, y: 0.5 * toY + 0.5 * toY }\n\tconst m3 = { x: 0.5 * m0.x + 0.5 * m1.x, y: 0.5 * m0.y + 0.5 * m1.y }\n\tconst m4 = { x: 0.5 * m1.x + 0.5 * m2.x, y: 0.5 * m1.y + 0.5 * m2.y }\n\tconst midpoint = { x: 0.5 * m3.x + 0.5 * m4.x, y: 0.5 * m3.y + 0.5 * m4.y }\n\n\t// Calculate the bezier curve using two arcs\n\treturn `M ${fromX} ${fromY} Q ${cp1X} ${fromY}, ${midpoint.x} ${midpoint.y} Q ${cp2X} ${toY}, ${toX} ${toY}`\n}\n\nconst handleConnectionDelete = (connection: ConnectionPath) => {\n\tif (store.deleteConnection(connection.id)) {\n\t\temit('connection:delete', connection)\n\t}\n}\n</script>\n\n<style scoped>\n.gantt-connection-overlay {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\twidth: 100%;\n\theight: 100%;\n\tpointer-events: none;\n\tz-index: 15;\n}\n\n.connection-path {\n\ttransition: stroke-width 0.2s ease;\n\tpointer-events: auto;\n\tcursor: pointer;\n\tstroke-dasharray: 5px;\n\tstroke: var(--sc-cell-text-color);\n}\n#arrowhead-marker polygon {\n\tfill: var(--sc-cell-text-color);\n}\n.animated-path {\n\tanimation: animated-dash infinite 1.5s linear;\n}\n\n.connection-path:hover {\n\tstroke-width: 3px;\n}\n\n.connection-hitbox {\n\tpointer-events: auto;\n\tcursor: pointer;\n}\n@keyframes animated-dash {\n\t0% {\n\t\tstroke-dashoffset: 0px;\n\t}\n\t100% {\n\t\tstroke-dashoffset: -10px;\n\t}\n}\n</style>\n","<template>\n\t<div class=\"column-filter\">\n\t\t<input\n\t\t\tv-if=\"resolvedFilterType === 'text'\"\n\t\t\tv-model=\"filterValue\"\n\t\t\ttype=\"text\"\n\t\t\tclass=\"filter-input\"\n\t\t\t@input=\"updateFilter(filterValue)\" />\n\n\t\t<input\n\t\t\tv-else-if=\"resolvedFilterType === 'number'\"\n\t\t\tv-model=\"filterValue\"\n\t\t\ttype=\"number\"\n\t\t\tclass=\"filter-input\"\n\t\t\t@input=\"updateFilter(filterValue)\" />\n\n\t\t<label v-else-if=\"resolvedFilterType === 'checkbox'\" class=\"checkbox-filter\">\n\t\t\t<input v-model=\"filterValue\" type=\"checkbox\" class=\"filter-checkbox\" @change=\"updateFilter(filterValue)\" />\n\t\t\t<span>{{ column.label }}</span>\n\t\t</label>\n\n\t\t<select\n\t\t\tv-else-if=\"resolvedFilterType === 'select'\"\n\t\t\tv-model=\"filterValue\"\n\t\t\tclass=\"filter-select\"\n\t\t\t@change=\"updateFilter(filterValue)\">\n\t\t\t<option value=\"\">All</option>\n\t\t\t<option v-for=\"option in getSelectOptions(column)\" :key=\"option.value || option\" :value=\"option.value || option\">\n\t\t\t\t{{ option.label || option }}\n\t\t\t</option>\n\t\t</select>\n\n\t\t<input\n\t\t\tv-else-if=\"resolvedFilterType === 'date'\"\n\t\t\tv-model=\"filterValue\"\n\t\t\ttype=\"date\"\n\t\t\tclass=\"filter-input\"\n\t\t\t@change=\"updateFilter(filterValue)\" />\n\n\t\t<div v-else-if=\"resolvedFilterType === 'dateRange'\" class=\"date-range-filter\">\n\t\t\t<input\n\t\t\t\tv-model=\"dateFilter.startValue\"\n\t\t\t\ttype=\"date\"\n\t\t\t\tclass=\"filter-input\"\n\t\t\t\t@change=\"updateDateRangeFilter('start', dateFilter.startValue)\" />\n\t\t\t<span class=\"date-separator\">-</span>\n\t\t\t<input\n\t\t\t\tv-model=\"dateFilter.endValue\"\n\t\t\t\ttype=\"date\"\n\t\t\t\tclass=\"filter-input\"\n\t\t\t\t@change=\"updateDateRangeFilter('end', dateFilter.endValue)\" />\n\t\t</div>\n\n\t\t<component\n\t\t\t:is=\"column.filterComponent\"\n\t\t\tv-else-if=\"resolvedFilterType === 'component' && column.filterComponent\"\n\t\t\t:value=\"filterValue\"\n\t\t\t:column=\"column\"\n\t\t\t:col-index=\"colIndex\"\n\t\t\t:store=\"store\"\n\t\t\t@update:value=\"updateFilter($event)\" />\n\n\t\t<button v-if=\"hasActiveFilter\" class=\"clear-btn\" title=\"Clear\" @click=\"clearFilter\">×</button>\n\t</div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, reactive, computed } from 'vue'\n\nimport { createTableStore } from '../stores/table'\nimport { resolveFilterType } from '../resolveFilterType'\nimport type { TableColumn } from '../types'\n\nconst { column, colIndex, store } = defineProps<{\n\tcolumn: TableColumn\n\tcolIndex: number\n\tstore: ReturnType<typeof createTableStore>\n}>()\n\nconst filterValue = ref<any>('')\nconst dateFilter = reactive({\n\tstartValue: '',\n\tendValue: '',\n})\n\nconst resolvedFilterType = computed(() => resolveFilterType(column))\n\nconst getSelectOptions = (col: TableColumn): any[] => {\n\tif (col.filterOptions) return col.filterOptions\n\n\t// Auto-generate options from data\n\tconst uniqueValues = new Set<any>()\n\tstore.rows.forEach(row => {\n\t\tconst value = row[col.name]\n\t\tif (value !== null && value !== undefined && value !== '') {\n\t\t\tuniqueValues.add(value)\n\t\t}\n\t})\n\n\treturn Array.from(uniqueValues).map(value => ({\n\t\tvalue: value,\n\t\tlabel: String(value),\n\t}))\n}\n\nconst hasActiveFilter = computed(() => {\n\treturn !!(filterValue.value || dateFilter.startValue || dateFilter.endValue)\n})\n\n// Filter actions\nconst updateFilter = (value: any) => {\n\tif (!value && resolvedFilterType.value !== 'checkbox') {\n\t\tstore.clearFilter(colIndex)\n\t\tfilterValue.value = ''\n\t} else {\n\t\tfilterValue.value = value\n\t\tstore.setFilter(colIndex, { value })\n\t}\n}\n\nconst updateDateRangeFilter = (rangeType: 'start' | 'end', value: any) => {\n\tif (rangeType === 'start') {\n\t\tdateFilter.startValue = value\n\t} else {\n\t\tdateFilter.endValue = value\n\t}\n\n\tif (!dateFilter.startValue && !dateFilter.endValue) {\n\t\tstore.clearFilter(colIndex)\n\t} else {\n\t\tstore.setFilter(colIndex, {\n\t\t\tvalue: null,\n\t\t\tstartValue: dateFilter.startValue,\n\t\t\tendValue: dateFilter.endValue,\n\t\t})\n\t}\n}\n\nconst clearFilter = () => {\n\tfilterValue.value = ''\n\tdateFilter.startValue = ''\n\tdateFilter.endValue = ''\n\tstore.clearFilter(colIndex)\n}\n</script>\n\n<style scoped>\n.column-filter {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 0.25rem;\n\twidth: 100%;\n}\n\n.filter-input,\n.filter-select {\n\tbackground-color: var(--sc-form-background) !important;\n\tpadding: 0.15rem 0.2rem;\n\tborder: 1px solid var(--sc-form-border);\n\tborder-radius: 3px;\n\tfont-size: 0.875rem;\n\tcolor: var(--sc-cell-text-color);\n\twidth: 100%;\n\tbox-sizing: border-box;\n}\n\n.filter-input:focus,\n.filter-select:focus {\n\toutline: none;\n\tborder-color: var(--sc-input-active-border-color);\n}\n\n.checkbox-filter {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 0.25rem;\n\tfont-size: 0.875rem;\n\tcolor: var(--sc-cell-text-color);\n\tcursor: pointer;\n}\n\n.filter-checkbox {\n\tmargin: 0;\n}\n\n.date-range-filter {\n\tdisplay: flex;\n\tgap: 0.25rem;\n\talign-items: center;\n\twidth: 100%;\n}\n\n.date-range-filter .filter-input {\n\tflex: 1;\n\tmin-width: 0;\n}\n\n.date-separator {\n\tcolor: var(--sc-gray-50);\n\tfont-weight: 500;\n\tpadding: 0 0.25rem;\n\tflex-shrink: 0;\n}\n\n.clear-btn {\n\tbackground: var(--sc-gray-10);\n\tborder: 1px solid var(--sc-form-border);\n\tborder-radius: 3px;\n\tcolor: var(--sc-gray-70);\n\tcursor: pointer;\n\tfont-size: 1rem;\n\tpadding: 0.15rem 0.4rem;\n\tline-height: 1;\n\tflex-shrink: 0;\n}\n</style>\n","<template>\n\t<div class=\"column-filter\">\n\t\t<input\n\t\t\tv-if=\"resolvedFilterType === 'text'\"\n\t\t\tv-model=\"filterValue\"\n\t\t\ttype=\"text\"\n\t\t\tclass=\"filter-input\"\n\t\t\t@input=\"updateFilter(filterValue)\" />\n\n\t\t<input\n\t\t\tv-else-if=\"resolvedFilterType === 'number'\"\n\t\t\tv-model=\"filterValue\"\n\t\t\ttype=\"number\"\n\t\t\tclass=\"filter-input\"\n\t\t\t@input=\"updateFilter(filterValue)\" />\n\n\t\t<label v-else-if=\"resolvedFilterType === 'checkbox'\" class=\"checkbox-filter\">\n\t\t\t<input v-model=\"filterValue\" type=\"checkbox\" class=\"filter-checkbox\" @change=\"updateFilter(filterValue)\" />\n\t\t\t<span>{{ column.label }}</span>\n\t\t</label>\n\n\t\t<select\n\t\t\tv-else-if=\"resolvedFilterType === 'select'\"\n\t\t\tv-model=\"filterValue\"\n\t\t\tclass=\"filter-select\"\n\t\t\t@change=\"updateFilter(filterValue)\">\n\t\t\t<option value=\"\">All</option>\n\t\t\t<option v-for=\"option in getSelectOptions(column)\" :key=\"option.value || option\" :value=\"option.value || option\">\n\t\t\t\t{{ option.label || option }}\n\t\t\t</option>\n\t\t</select>\n\n\t\t<input\n\t\t\tv-else-if=\"resolvedFilterType === 'date'\"\n\t\t\tv-model=\"filterValue\"\n\t\t\ttype=\"date\"\n\t\t\tclass=\"filter-input\"\n\t\t\t@change=\"updateFilter(filterValue)\" />\n\n\t\t<div v-else-if=\"resolvedFilterType === 'dateRange'\" class=\"date-range-filter\">\n\t\t\t<input\n\t\t\t\tv-model=\"dateFilter.startValue\"\n\t\t\t\ttype=\"date\"\n\t\t\t\tclass=\"filter-input\"\n\t\t\t\t@change=\"updateDateRangeFilter('start', dateFilter.startValue)\" />\n\t\t\t<span class=\"date-separator\">-</span>\n\t\t\t<input\n\t\t\t\tv-model=\"dateFilter.endValue\"\n\t\t\t\ttype=\"date\"\n\t\t\t\tclass=\"filter-input\"\n\t\t\t\t@change=\"updateDateRangeFilter('end', dateFilter.endValue)\" />\n\t\t</div>\n\n\t\t<component\n\t\t\t:is=\"column.filterComponent\"\n\t\t\tv-else-if=\"resolvedFilterType === 'component' && column.filterComponent\"\n\t\t\t:value=\"filterValue\"\n\t\t\t:column=\"column\"\n\t\t\t:col-index=\"colIndex\"\n\t\t\t:store=\"store\"\n\t\t\t@update:value=\"updateFilter($event)\" />\n\n\t\t<button v-if=\"hasActiveFilter\" class=\"clear-btn\" title=\"Clear\" @click=\"clearFilter\">×</button>\n\t</div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, reactive, computed } from 'vue'\n\nimport { createTableStore } from '../stores/table'\nimport { resolveFilterType } from '../resolveFilterType'\nimport type { TableColumn } from '../types'\n\nconst { column, colIndex, store } = defineProps<{\n\tcolumn: TableColumn\n\tcolIndex: number\n\tstore: ReturnType<typeof createTableStore>\n}>()\n\nconst filterValue = ref<any>('')\nconst dateFilter = reactive({\n\tstartValue: '',\n\tendValue: '',\n})\n\nconst resolvedFilterType = computed(() => resolveFilterType(column))\n\nconst getSelectOptions = (col: TableColumn): any[] => {\n\tif (col.filterOptions) return col.filterOptions\n\n\t// Auto-generate options from data\n\tconst uniqueValues = new Set<any>()\n\tstore.rows.forEach(row => {\n\t\tconst value = row[col.name]\n\t\tif (value !== null && value !== undefined && value !== '') {\n\t\t\tuniqueValues.add(value)\n\t\t}\n\t})\n\n\treturn Array.from(uniqueValues).map(value => ({\n\t\tvalue: value,\n\t\tlabel: String(value),\n\t}))\n}\n\nconst hasActiveFilter = computed(() => {\n\treturn !!(filterValue.value || dateFilter.startValue || dateFilter.endValue)\n})\n\n// Filter actions\nconst updateFilter = (value: any) => {\n\tif (!value && resolvedFilterType.value !== 'checkbox') {\n\t\tstore.clearFilter(colIndex)\n\t\tfilterValue.value = ''\n\t} else {\n\t\tfilterValue.value = value\n\t\tstore.setFilter(colIndex, { value })\n\t}\n}\n\nconst updateDateRangeFilter = (rangeType: 'start' | 'end', value: any) => {\n\tif (rangeType === 'start') {\n\t\tdateFilter.startValue = value\n\t} else {\n\t\tdateFilter.endValue = value\n\t}\n\n\tif (!dateFilter.startValue && !dateFilter.endValue) {\n\t\tstore.clearFilter(colIndex)\n\t} else {\n\t\tstore.setFilter(colIndex, {\n\t\t\tvalue: null,\n\t\t\tstartValue: dateFilter.startValue,\n\t\t\tendValue: dateFilter.endValue,\n\t\t})\n\t}\n}\n\nconst clearFilter = () => {\n\tfilterValue.value = ''\n\tdateFilter.startValue = ''\n\tdateFilter.endValue = ''\n\tstore.clearFilter(colIndex)\n}\n</script>\n\n<style scoped>\n.column-filter {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 0.25rem;\n\twidth: 100%;\n}\n\n.filter-input,\n.filter-select {\n\tbackground-color: var(--sc-form-background) !important;\n\tpadding: 0.15rem 0.2rem;\n\tborder: 1px solid var(--sc-form-border);\n\tborder-radius: 3px;\n\tfont-size: 0.875rem;\n\tcolor: var(--sc-cell-text-color);\n\twidth: 100%;\n\tbox-sizing: border-box;\n}\n\n.filter-input:focus,\n.filter-select:focus {\n\toutline: none;\n\tborder-color: var(--sc-input-active-border-color);\n}\n\n.checkbox-filter {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 0.25rem;\n\tfont-size: 0.875rem;\n\tcolor: var(--sc-cell-text-color);\n\tcursor: pointer;\n}\n\n.filter-checkbox {\n\tmargin: 0;\n}\n\n.date-range-filter {\n\tdisplay: flex;\n\tgap: 0.25rem;\n\talign-items: center;\n\twidth: 100%;\n}\n\n.date-range-filter .filter-input {\n\tflex: 1;\n\tmin-width: 0;\n}\n\n.date-separator {\n\tcolor: var(--sc-gray-50);\n\tfont-weight: 500;\n\tpadding: 0 0.25rem;\n\tflex-shrink: 0;\n}\n\n.clear-btn {\n\tbackground: var(--sc-gray-10);\n\tborder: 1px solid var(--sc-form-border);\n\tborder-radius: 3px;\n\tcolor: var(--sc-gray-70);\n\tcursor: pointer;\n\tfont-size: 1rem;\n\tpadding: 0.15rem 0.4rem;\n\tline-height: 1;\n\tflex-shrink: 0;\n}\n</style>\n","<template>\n\t<thead v-if=\"columns.length\">\n\t\t<!-- Header row -->\n\t\t<tr class=\"atable-header-row\" tabindex=\"-1\">\n\t\t\t<!-- Row actions header cell (before-index position) -->\n\t\t\t<th\n\t\t\t\tv-if=\"showRowActionsHeader && rowActionsPosition === 'before-index'\"\n\t\t\t\tclass=\"row-actions-header\"\n\t\t\t\t:class=\"{ 'sticky-column': rowActionsPosition === 'before-index' }\" />\n\t\t\t<th\n\t\t\t\tv-if=\"store.zeroColumn\"\n\t\t\t\tid=\"header-index\"\n\t\t\t\t:class=\"[\n\t\t\t\t\tstore.hasPinnedColumns ? 'sticky-index' : '',\n\t\t\t\t\tstore.isTreeView ? 'tree-index' : '',\n\t\t\t\t\tstore.config.view === 'list-expansion' ? 'list-expansion-index' : '',\n\t\t\t\t]\"\n\t\t\t\tclass=\"list-index\" />\n\t\t\t<!-- Row actions header cell (after-index position) -->\n\t\t\t<th v-if=\"showRowActionsHeader && rowActionsPosition === 'after-index'\" class=\"row-actions-header\" />\n\t\t\t<th\n\t\t\t\tv-for=\"(column, colKey) in columns\"\n\t\t\t\t:key=\"column.name\"\n\t\t\t\tv-resize-observer=\"onResize\"\n\t\t\t\t:data-colindex=\"colKey\"\n\t\t\t\ttabindex=\"-1\"\n\t\t\t\t:style=\"store.getHeaderCellStyle(column)\"\n\t\t\t\t:class=\"`${column.pinned ? 'sticky-column' : ''} ${column.sortable === false ? '' : 'cursor-pointer'}`\"\n\t\t\t\t@click=\"column.sortable !== false ? handleSort(colKey) : undefined\">\n\t\t\t\t<slot>{{ column.label || String.fromCharCode(colKey + 97).toUpperCase() }}</slot>\n\t\t\t</th>\n\t\t\t<!-- Row actions header cell (end position) -->\n\t\t\t<th v-if=\"showRowActionsHeader && rowActionsPosition === 'end'\" class=\"row-actions-header\" />\n\t\t</tr>\n\t\t<!-- Filters row -->\n\t\t<tr v-if=\"filterableColumns.length > 0\" class=\"atable-filters-row\">\n\t\t\t<!-- Row actions filter cell (before-index position) -->\n\t\t\t<th\n\t\t\t\tv-if=\"showRowActionsHeader && rowActionsPosition === 'before-index'\"\n\t\t\t\tclass=\"row-actions-header\"\n\t\t\t\t:class=\"{ 'sticky-column': rowActionsPosition === 'before-index' }\" />\n\t\t\t<th\n\t\t\t\tv-if=\"store.zeroColumn\"\n\t\t\t\t:class=\"[\n\t\t\t\t\tstore.hasPinnedColumns ? 'sticky-index' : '',\n\t\t\t\t\tstore.isTreeView ? 'tree-index' : '',\n\t\t\t\t\tstore.config.view === 'list-expansion' ? 'list-expansion-index' : '',\n\t\t\t\t]\"\n\t\t\t\tclass=\"list-index\" />\n\t\t\t<!-- Row actions filter cell (after-index position) -->\n\t\t\t<th v-if=\"showRowActionsHeader && rowActionsPosition === 'after-index'\" class=\"row-actions-header\" />\n\t\t\t<th\n\t\t\t\tv-for=\"(column, colKey) in columns\"\n\t\t\t\t:key=\"`filter-${column.name}`\"\n\t\t\t\t:class=\"`${column.pinned ? 'sticky-column' : ''}`\"\n\t\t\t\t:style=\"store.getHeaderCellStyle(column)\">\n\t\t\t\t<ATableColumnFilter v-if=\"column.filterable\" :column=\"column\" :col-index=\"colKey\" :store=\"store\" />\n\t\t\t</th>\n\t\t\t<!-- Row actions filter cell (end position) -->\n\t\t\t<th v-if=\"showRowActionsHeader && rowActionsPosition === 'end'\" class=\"row-actions-header\" />\n\t\t</tr>\n\t</thead>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { vResizeObserver } from '@vueuse/components'\nimport ATableColumnFilter from './ATableColumnFilter.vue'\nimport { createTableStore } from '../stores/table'\nimport type { TableColumn } from '../types'\n\nconst { columns, store } = defineProps<{\n\tcolumns: TableColumn[]\n\tstore: ReturnType<typeof createTableStore>\n}>()\n\nconst filterableColumns = computed(() => columns.filter(column => column.filterable))\n\n// Row actions header support — explicit return type resolves Pinia's inference chain\nconst showRowActionsHeader = computed(() => store.config.rowActions?.enabled ?? false)\nconst rowActionsPosition = computed(() => store.config.rowActions?.position ?? 'before-index')\n\nconst handleSort = (colIndex: number) => store.sortByColumn(colIndex)\n\nconst onResize = (entries: ReadonlyArray<ResizeObserverEntry>) => {\n\tfor (const entry of entries) {\n\t\tif (entry.borderBoxSize.length === 0) continue\n\t\tconst observedCell = entry.borderBoxSize[0]\n\t\tconst observedWidth = observedCell.inlineSize\n\t\tconst colIndex = Number((entry.target as HTMLElement).dataset.colindex)\n\t\tconst currentWidth = store.columns[colIndex]?.width\n\n\t\tif (typeof currentWidth === 'number' && currentWidth !== observedWidth) {\n\t\t\tstore.resizeColumn(colIndex, observedWidth)\n\t\t}\n\t}\n}\n</script>\n\n<style>\n.atable-header-row th {\n\tpadding-left: 0.5ch !important;\n\tfont-weight: 700;\n\tmin-width: 3ch;\n\tpadding-top: var(--sc-atable-row-padding);\n\tpadding-bottom: var(--sc-atable-row-padding);\n\tbox-sizing: border-box;\n\tcolor: var(--sc-header-text-color);\n\tposition: relative;\n}\n#header-index {\n\tpadding-left: var(--sc-atable-row-padding);\n\tbox-sizing: border-box;\n\tborder-top: none;\n}\n.tree-index {\n\tpadding-right: 0;\n}\nth {\n\torder: 1;\n}\n.list-expansion-index {\n\twidth: 2ch;\n\tmargin-left: 5px;\n}\n\n.cursor-pointer {\n\tcursor: pointer;\n}\n\n.atable-filters-row th {\n\tpadding: 0.25rem 0.5ch;\n\tvertical-align: top;\n}\n\n.row-actions-header {\n\twidth: 2rem;\n\tmin-width: 2rem;\n\tpadding: 0 0.25rem;\n}\n</style>\n","<template>\n\t<thead v-if=\"columns.length\">\n\t\t<!-- Header row -->\n\t\t<tr class=\"atable-header-row\" tabindex=\"-1\">\n\t\t\t<!-- Row actions header cell (before-index position) -->\n\t\t\t<th\n\t\t\t\tv-if=\"showRowActionsHeader && rowActionsPosition === 'before-index'\"\n\t\t\t\tclass=\"row-actions-header\"\n\t\t\t\t:class=\"{ 'sticky-column': rowActionsPosition === 'before-index' }\" />\n\t\t\t<th\n\t\t\t\tv-if=\"store.zeroColumn\"\n\t\t\t\tid=\"header-index\"\n\t\t\t\t:class=\"[\n\t\t\t\t\tstore.hasPinnedColumns ? 'sticky-index' : '',\n\t\t\t\t\tstore.isTreeView ? 'tree-index' : '',\n\t\t\t\t\tstore.config.view === 'list-expansion' ? 'list-expansion-index' : '',\n\t\t\t\t]\"\n\t\t\t\tclass=\"list-index\" />\n\t\t\t<!-- Row actions header cell (after-index position) -->\n\t\t\t<th v-if=\"showRowActionsHeader && rowActionsPosition === 'after-index'\" class=\"row-actions-header\" />\n\t\t\t<th\n\t\t\t\tv-for=\"(column, colKey) in columns\"\n\t\t\t\t:key=\"column.name\"\n\t\t\t\tv-resize-observer=\"onResize\"\n\t\t\t\t:data-colindex=\"colKey\"\n\t\t\t\ttabindex=\"-1\"\n\t\t\t\t:style=\"store.getHeaderCellStyle(column)\"\n\t\t\t\t:class=\"`${column.pinned ? 'sticky-column' : ''} ${column.sortable === false ? '' : 'cursor-pointer'}`\"\n\t\t\t\t@click=\"column.sortable !== false ? handleSort(colKey) : undefined\">\n\t\t\t\t<slot>{{ column.label || String.fromCharCode(colKey + 97).toUpperCase() }}</slot>\n\t\t\t</th>\n\t\t\t<!-- Row actions header cell (end position) -->\n\t\t\t<th v-if=\"showRowActionsHeader && rowActionsPosition === 'end'\" class=\"row-actions-header\" />\n\t\t</tr>\n\t\t<!-- Filters row -->\n\t\t<tr v-if=\"filterableColumns.length > 0\" class=\"atable-filters-row\">\n\t\t\t<!-- Row actions filter cell (before-index position) -->\n\t\t\t<th\n\t\t\t\tv-if=\"showRowActionsHeader && rowActionsPosition === 'before-index'\"\n\t\t\t\tclass=\"row-actions-header\"\n\t\t\t\t:class=\"{ 'sticky-column': rowActionsPosition === 'before-index' }\" />\n\t\t\t<th\n\t\t\t\tv-if=\"store.zeroColumn\"\n\t\t\t\t:class=\"[\n\t\t\t\t\tstore.hasPinnedColumns ? 'sticky-index' : '',\n\t\t\t\t\tstore.isTreeView ? 'tree-index' : '',\n\t\t\t\t\tstore.config.view === 'list-expansion' ? 'list-expansion-index' : '',\n\t\t\t\t]\"\n\t\t\t\tclass=\"list-index\" />\n\t\t\t<!-- Row actions filter cell (after-index position) -->\n\t\t\t<th v-if=\"showRowActionsHeader && rowActionsPosition === 'after-index'\" class=\"row-actions-header\" />\n\t\t\t<th\n\t\t\t\tv-for=\"(column, colKey) in columns\"\n\t\t\t\t:key=\"`filter-${column.name}`\"\n\t\t\t\t:class=\"`${column.pinned ? 'sticky-column' : ''}`\"\n\t\t\t\t:style=\"store.getHeaderCellStyle(column)\">\n\t\t\t\t<ATableColumnFilter v-if=\"column.filterable\" :column=\"column\" :col-index=\"colKey\" :store=\"store\" />\n\t\t\t</th>\n\t\t\t<!-- Row actions filter cell (end position) -->\n\t\t\t<th v-if=\"showRowActionsHeader && rowActionsPosition === 'end'\" class=\"row-actions-header\" />\n\t\t</tr>\n\t</thead>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { vResizeObserver } from '@vueuse/components'\nimport ATableColumnFilter from './ATableColumnFilter.vue'\nimport { createTableStore } from '../stores/table'\nimport type { TableColumn } from '../types'\n\nconst { columns, store } = defineProps<{\n\tcolumns: TableColumn[]\n\tstore: ReturnType<typeof createTableStore>\n}>()\n\nconst filterableColumns = computed(() => columns.filter(column => column.filterable))\n\n// Row actions header support — explicit return type resolves Pinia's inference chain\nconst showRowActionsHeader = computed(() => store.config.rowActions?.enabled ?? false)\nconst rowActionsPosition = computed(() => store.config.rowActions?.position ?? 'before-index')\n\nconst handleSort = (colIndex: number) => store.sortByColumn(colIndex)\n\nconst onResize = (entries: ReadonlyArray<ResizeObserverEntry>) => {\n\tfor (const entry of entries) {\n\t\tif (entry.borderBoxSize.length === 0) continue\n\t\tconst observedCell = entry.borderBoxSize[0]\n\t\tconst observedWidth = observedCell.inlineSize\n\t\tconst colIndex = Number((entry.target as HTMLElement).dataset.colindex)\n\t\tconst currentWidth = store.columns[colIndex]?.width\n\n\t\tif (typeof currentWidth === 'number' && currentWidth !== observedWidth) {\n\t\t\tstore.resizeColumn(colIndex, observedWidth)\n\t\t}\n\t}\n}\n</script>\n\n<style>\n.atable-header-row th {\n\tpadding-left: 0.5ch !important;\n\tfont-weight: 700;\n\tmin-width: 3ch;\n\tpadding-top: var(--sc-atable-row-padding);\n\tpadding-bottom: var(--sc-atable-row-padding);\n\tbox-sizing: border-box;\n\tcolor: var(--sc-header-text-color);\n\tposition: relative;\n}\n#header-index {\n\tpadding-left: var(--sc-atable-row-padding);\n\tbox-sizing: border-box;\n\tborder-top: none;\n}\n.tree-index {\n\tpadding-right: 0;\n}\nth {\n\torder: 1;\n}\n.list-expansion-index {\n\twidth: 2ch;\n\tmargin-left: 5px;\n}\n\n.cursor-pointer {\n\tcursor: pointer;\n}\n\n.atable-filters-row th {\n\tpadding: 0.25rem 0.5ch;\n\tvertical-align: top;\n}\n\n.row-actions-header {\n\twidth: 2rem;\n\tmin-width: 2rem;\n\tpadding: 0 0.25rem;\n}\n</style>\n","<template>\n\t<div ref=\"amodal\" class=\"amodal\" tabindex=\"-1\" :style=\"amodalStyles\" @click.stop @input.stop>\n\t\t<slot />\n\t</div>\n</template>\n\n<script setup lang=\"ts\">\nimport { useElementBounding } from '@vueuse/core'\nimport { useTemplateRef, computed, type StyleValue } from 'vue'\n\nimport { createTableStore } from '../stores/table'\n\nconst { store } = defineProps<{ store: ReturnType<typeof createTableStore> }>()\n\nconst amodalRef = useTemplateRef('amodal')\nconst { width: modalWidth, height: modalHeight } = useElementBounding(amodalRef)\n\nconst amodalStyles = computed((): StyleValue => {\n\tif (!(store.modal.height && store.modal.width && store.modal.left && store.modal.bottom)) return {}\n\n\tconst table = store.modal.cell?.closest('table')\n\tif (!table) return {}\n\n\tconst maxHeight = table.offsetHeight || 0\n\tconst maxWidth = table.offsetWidth || 0\n\n\t// Get the Y position of the cell clicked by getting the cumulative height of prior rows + the header (if present)\n\tlet modalY = store.modal.cell?.offsetTop || 0\n\tconst headerHeight = table.querySelector('thead')?.offsetHeight || 0\n\tmodalY += headerHeight\n\t// if the modal will overflow the bottom of the table, remove modal and cell heights from the Y position\n\tmodalY = modalY + modalHeight.value < maxHeight ? modalY : modalY - (modalHeight.value + store.modal.height)\n\n\t// Get the X position of the cell clicked by getting the cumulative width of prior cells within the row\n\tlet modalX = store.modal.cell?.offsetLeft || 0\n\t// if the modal will overflow the right of the table, remove modal and cell widths from the X position\n\tmodalX = modalX + modalWidth.value <= maxWidth ? modalX : modalX - (modalWidth.value - store.modal.width)\n\n\treturn {\n\t\tleft: `${modalX}px`,\n\t\ttop: `${modalY}px`,\n\t}\n})\n</script>\n\n<style>\n.amodal {\n\tposition: absolute;\n\tbackground-color: var(--sc-row-color-zebra-dark);\n\tz-index: 200;\n}\n</style>\n","<template>\n\t<div ref=\"amodal\" class=\"amodal\" tabindex=\"-1\" :style=\"amodalStyles\" @click.stop @input.stop>\n\t\t<slot />\n\t</div>\n</template>\n\n<script setup lang=\"ts\">\nimport { useElementBounding } from '@vueuse/core'\nimport { useTemplateRef, computed, type StyleValue } from 'vue'\n\nimport { createTableStore } from '../stores/table'\n\nconst { store } = defineProps<{ store: ReturnType<typeof createTableStore> }>()\n\nconst amodalRef = useTemplateRef('amodal')\nconst { width: modalWidth, height: modalHeight } = useElementBounding(amodalRef)\n\nconst amodalStyles = computed((): StyleValue => {\n\tif (!(store.modal.height && store.modal.width && store.modal.left && store.modal.bottom)) return {}\n\n\tconst table = store.modal.cell?.closest('table')\n\tif (!table) return {}\n\n\tconst maxHeight = table.offsetHeight || 0\n\tconst maxWidth = table.offsetWidth || 0\n\n\t// Get the Y position of the cell clicked by getting the cumulative height of prior rows + the header (if present)\n\tlet modalY = store.modal.cell?.offsetTop || 0\n\tconst headerHeight = table.querySelector('thead')?.offsetHeight || 0\n\tmodalY += headerHeight\n\t// if the modal will overflow the bottom of the table, remove modal and cell heights from the Y position\n\tmodalY = modalY + modalHeight.value < maxHeight ? modalY : modalY - (modalHeight.value + store.modal.height)\n\n\t// Get the X position of the cell clicked by getting the cumulative width of prior cells within the row\n\tlet modalX = store.modal.cell?.offsetLeft || 0\n\t// if the modal will overflow the right of the table, remove modal and cell widths from the X position\n\tmodalX = modalX + modalWidth.value <= maxWidth ? modalX : modalX - (modalWidth.value - store.modal.width)\n\n\treturn {\n\t\tleft: `${modalX}px`,\n\t\ttop: `${modalY}px`,\n\t}\n})\n</script>\n\n<style>\n.amodal {\n\tposition: absolute;\n\tbackground-color: var(--sc-row-color-zebra-dark);\n\tz-index: 200;\n}\n</style>\n","<template>\n\t<tfoot v-if=\"showFooter\" class=\"atable-pagination\">\n\t\t<tr>\n\t\t\t<td :colspan=\"columnCount\">\n\t\t\t\t<p v-if=\"hasMore\" class=\"truncation-note\">This is a partial list — more records exist on the server.</p>\n\t\t\t\t<p v-else-if=\"showCompleteNote\" class=\"completion-note\">All {{ loadedCount }} records loaded.</p>\n\t\t\t\t<div v-if=\"showControls\" class=\"atable-pagination-controls\">\n\t\t\t\t\t<button type=\"button\" class=\"atable-pagination-btn\" :disabled=\"!hasPrev || loading\" @click=\"prev\">\n\t\t\t\t\t\tPrevious\n\t\t\t\t\t</button>\n\t\t\t\t\t<button type=\"button\" class=\"atable-pagination-btn\" :disabled=\"!hasNext || loading\" @click=\"onNext\">\n\t\t\t\t\t\t{{ hasMore && !hasLocalNext ? 'Load more' : 'Next' }}\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t</td>\n\t\t</tr>\n\t</tfoot>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nconst props = defineProps<{\n\tcolumnCount: number\n\tshowFooter: boolean\n\thasMore: boolean\n\thasPrev: boolean\n\thasNext: boolean\n\thasLocalNext: boolean\n\thasEverHadMore: boolean\n\tloadedCount: number\n\tloading: boolean\n\tnext: () => Promise<void>\n\tprev: () => void\n}>()\n\nconst showCompleteNote = computed(() => !props.hasMore && props.hasEverHadMore)\nconst showControls = computed(() => props.hasMore || props.hasPrev)\n\nconst onNext = () => {\n\tvoid props.next()\n}\n</script>\n\n<style scoped>\n.atable-pagination td {\n\tpadding: 0.75rem 0.5ch;\n\tborder-top: 1px solid var(--sc-row-border-color);\n}\n\n.truncation-note,\n.completion-note {\n\tmargin: 0 0 0.5rem;\n\tfont-size: var(--sc-table-font-size);\n\tcolor: var(--sc-gray-60);\n}\n\n.completion-note {\n\tmargin-bottom: 0;\n}\n\n.atable-pagination-controls {\n\tdisplay: flex;\n\tgap: 0.5rem;\n}\n\n.atable-pagination-btn {\n\tappearance: none;\n\t-webkit-appearance: none;\n\tbox-sizing: border-box;\n\tpadding: 0.5rem 1rem;\n\tbackground: var(--sc-btn-color);\n\tcolor: var(--sc-btn-label-color);\n\tborder: 1px solid var(--sc-btn-border);\n\tborder-radius: var(--sc-border-radius);\n\tcursor: pointer;\n\tfont-family: var(--sc-font-family);\n\tfont-size: var(--sc-table-font-size);\n\tfont-weight: 400;\n\tline-height: 1.2;\n\ttransition: background-color 0.15s ease;\n}\n\n.atable-pagination-btn:hover:not(:disabled) {\n\tbackground: var(--sc-btn-hover);\n}\n\n.atable-pagination-btn:focus-visible {\n\toutline: 2px solid var(--sc-input-active-border-color);\n\toutline-offset: 1px;\n}\n\n.atable-pagination-btn:disabled {\n\tcursor: not-allowed;\n\tbackground: var(--sc-gray-5);\n\tcolor: var(--sc-gray-50);\n\tborder-color: var(--sc-gray-20);\n\topacity: 1;\n}\n</style>\n","<template>\n\t<tfoot v-if=\"showFooter\" class=\"atable-pagination\">\n\t\t<tr>\n\t\t\t<td :colspan=\"columnCount\">\n\t\t\t\t<p v-if=\"hasMore\" class=\"truncation-note\">This is a partial list — more records exist on the server.</p>\n\t\t\t\t<p v-else-if=\"showCompleteNote\" class=\"completion-note\">All {{ loadedCount }} records loaded.</p>\n\t\t\t\t<div v-if=\"showControls\" class=\"atable-pagination-controls\">\n\t\t\t\t\t<button type=\"button\" class=\"atable-pagination-btn\" :disabled=\"!hasPrev || loading\" @click=\"prev\">\n\t\t\t\t\t\tPrevious\n\t\t\t\t\t</button>\n\t\t\t\t\t<button type=\"button\" class=\"atable-pagination-btn\" :disabled=\"!hasNext || loading\" @click=\"onNext\">\n\t\t\t\t\t\t{{ hasMore && !hasLocalNext ? 'Load more' : 'Next' }}\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t</td>\n\t\t</tr>\n\t</tfoot>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nconst props = defineProps<{\n\tcolumnCount: number\n\tshowFooter: boolean\n\thasMore: boolean\n\thasPrev: boolean\n\thasNext: boolean\n\thasLocalNext: boolean\n\thasEverHadMore: boolean\n\tloadedCount: number\n\tloading: boolean\n\tnext: () => Promise<void>\n\tprev: () => void\n}>()\n\nconst showCompleteNote = computed(() => !props.hasMore && props.hasEverHadMore)\nconst showControls = computed(() => props.hasMore || props.hasPrev)\n\nconst onNext = () => {\n\tvoid props.next()\n}\n</script>\n\n<style scoped>\n.atable-pagination td {\n\tpadding: 0.75rem 0.5ch;\n\tborder-top: 1px solid var(--sc-row-border-color);\n}\n\n.truncation-note,\n.completion-note {\n\tmargin: 0 0 0.5rem;\n\tfont-size: var(--sc-table-font-size);\n\tcolor: var(--sc-gray-60);\n}\n\n.completion-note {\n\tmargin-bottom: 0;\n}\n\n.atable-pagination-controls {\n\tdisplay: flex;\n\tgap: 0.5rem;\n}\n\n.atable-pagination-btn {\n\tappearance: none;\n\t-webkit-appearance: none;\n\tbox-sizing: border-box;\n\tpadding: 0.5rem 1rem;\n\tbackground: var(--sc-btn-color);\n\tcolor: var(--sc-btn-label-color);\n\tborder: 1px solid var(--sc-btn-border);\n\tborder-radius: var(--sc-border-radius);\n\tcursor: pointer;\n\tfont-family: var(--sc-font-family);\n\tfont-size: var(--sc-table-font-size);\n\tfont-weight: 400;\n\tline-height: 1.2;\n\ttransition: background-color 0.15s ease;\n}\n\n.atable-pagination-btn:hover:not(:disabled) {\n\tbackground: var(--sc-btn-hover);\n}\n\n.atable-pagination-btn:focus-visible {\n\toutline: 2px solid var(--sc-input-active-border-color);\n\toutline-offset: 1px;\n}\n\n.atable-pagination-btn:disabled {\n\tcursor: not-allowed;\n\tbackground: var(--sc-gray-5);\n\tcolor: var(--sc-gray-50);\n\tborder-color: var(--sc-gray-20);\n\topacity: 1;\n}\n</style>\n","import type { GetRecordsOptions, GetRecordsResult } from '@stonecrop/schema'\nimport { computed, nextTick, ref, toValue, watch, type MaybeRefOrGetter, type Ref } from 'vue'\n\nimport type { TableRow } from '../types'\n\n/**\n * A table row after filter/sort, with its index in the held row list.\n * @public\n */\nexport type FilteredTableRow = TableRow & { originalIndex: number }\n\n/**\n * Options for {@link useTablePagination}.\n * @public\n */\nexport interface UseTablePaginationOptions {\n\t/** Rows after filter and sort — pagination is a window over this list, not part of filtering. */\n\trows: MaybeRefOrGetter<FilteredTableRow[]>\n\t/** When set, slice the held rows into windows of this size. Omit to show the whole held list. */\n\tpageSize?: MaybeRefOrGetter<number | undefined>\n\t/** Fetch the next server page. Typed from schema so ATable need not import Stonecrop. */\n\tgetRecords?: (options?: GetRecordsOptions) => Promise<GetRecordsResult>\n\t/** When this changes, refetch from offset 0. */\n\tsourceKey?: MaybeRefOrGetter<string | undefined>\n}\n\n/**\n * Pagination state and controls returned by {@link useTablePagination}.\n * @public\n */\nexport interface TablePagination {\n\tvisibleRows: Ref<FilteredTableRow[]>\n\thasPrev: Ref<boolean>\n\thasNext: Ref<boolean>\n\t/** Whether the server reported more records beyond what has been fetched. */\n\thasMore: Ref<boolean>\n\tloading: Ref<boolean>\n\tnext: () => Promise<void>\n\tprev: () => void\n\t/** Whether footer chrome should render. */\n\tshowFooter: Ref<boolean>\n\t/** Whether another in-memory window exists before asking the server. */\n\thasLocalNext: Ref<boolean>\n\t/** Rows currently held after filter/sort — useful for a completion summary. */\n\tloadedCount: Ref<number>\n\t/** True once the server reported a further page existed (multi-page fetch). */\n\thasEverHadMore: Ref<boolean>\n}\n\n/**\n * Window rows after filter/sort, and optionally walk {@link @stonecrop/schema#GetRecordsOptions} for the next page.\n * Pagination is not a filter — pass already-filtered rows.\n * @public\n */\nexport function useTablePagination(options: UseTablePaginationOptions): TablePagination {\n\tconst heldRows = computed(() => toValue(options.rows))\n\tconst pageSize = computed(() => toValue(options.pageSize))\n\tconst sourceKey = computed(() => toValue(options.sourceKey))\n\n\tconst windowIndex = ref(0)\n\tconst loading = ref(false)\n\tconst serverHasMore = ref(false)\n\tconst hasEverHadMore = ref(false)\n\tconst lastFetchOffset = ref(0)\n\tconst lastPageLength = ref(0)\n\tconst loadedCount = computed(() => heldRows.value.length)\n\n\tconst effectivePageSize = computed(() => {\n\t\tconst size = pageSize.value\n\t\tif (size != null && size > 0) {\n\t\t\treturn size\n\t\t}\n\t\t// No pageSize: one window over everything held (server list or full child table).\n\t\tconst count = heldRows.value.length\n\t\treturn count > 0 ? count : 1\n\t})\n\n\tconst windowCount = computed(() => Math.max(1, Math.ceil(heldRows.value.length / effectivePageSize.value)))\n\n\tconst visibleRows = computed(() => {\n\t\tconst start = windowIndex.value * effectivePageSize.value\n\t\treturn heldRows.value.slice(start, start + effectivePageSize.value)\n\t})\n\n\tconst hasLocalNext = computed(() => windowIndex.value < windowCount.value - 1)\n\tconst hasPrev = computed(() => windowIndex.value > 0)\n\tconst hasNext = computed(() => hasLocalNext.value || (Boolean(options.getRecords) && serverHasMore.value))\n\tconst hasMore = computed(() => serverHasMore.value)\n\n\tconst showFooter = computed(() => {\n\t\tif (options.getRecords) {\n\t\t\t// Keep the footer after the last \"Load more\" so completion is visible, not silent.\n\t\t\treturn serverHasMore.value || hasPrev.value || loading.value || (hasEverHadMore.value && !serverHasMore.value)\n\t\t}\n\t\tconst size = pageSize.value\n\t\treturn size != null && size > 0 && heldRows.value.length > size\n\t})\n\n\tconst resetWindow = () => {\n\t\twindowIndex.value = 0\n\t\thasEverHadMore.value = false\n\t}\n\n\tconst fetchFromServer = async (fetchOptions?: GetRecordsOptions) => {\n\t\tif (!options.getRecords) {\n\t\t\treturn\n\t\t}\n\t\tloading.value = true\n\t\ttry {\n\t\t\tconst result = await options.getRecords(fetchOptions)\n\t\t\tserverHasMore.value = result.hasMore\n\t\t\tif (result.hasMore) {\n\t\t\t\thasEverHadMore.value = true\n\t\t\t}\n\t\t\tlastFetchOffset.value = fetchOptions?.offset ?? 0\n\t\t\tlastPageLength.value = result.data.length\n\t\t} finally {\n\t\t\tloading.value = false\n\t\t}\n\t}\n\n\twatch(\n\t\t() => sourceKey.value,\n\t\t() => {\n\t\t\tresetWindow()\n\t\t\tif (options.getRecords) {\n\t\t\t\tvoid fetchFromServer()\n\t\t\t}\n\t\t},\n\t\t{ immediate: true }\n\t)\n\n\twatch(heldRows, () => {\n\t\t// Shrinking the held set can leave the window past the end.\n\t\tif (windowIndex.value >= windowCount.value) {\n\t\t\twindowIndex.value = Math.max(0, windowCount.value - 1)\n\t\t}\n\t})\n\n\tconst next = async () => {\n\t\tif (hasLocalNext.value) {\n\t\t\twindowIndex.value += 1\n\t\t\treturn\n\t\t}\n\t\tif (options.getRecords && serverHasMore.value) {\n\t\t\tawait fetchFromServer({ offset: lastFetchOffset.value + lastPageLength.value })\n\t\t\tawait nextTick()\n\t\t\t// Parent/HST grows rows; show the newly appended tail.\n\t\t\twindowIndex.value = Math.max(0, windowCount.value - 1)\n\t\t}\n\t}\n\n\tconst prev = () => {\n\t\tif (windowIndex.value > 0) {\n\t\t\twindowIndex.value -= 1\n\t\t}\n\t}\n\n\treturn {\n\t\tvisibleRows,\n\t\thasPrev,\n\t\thasNext,\n\t\thasMore,\n\t\tloading,\n\t\tnext,\n\t\tprev,\n\t\tshowFooter,\n\t\thasLocalNext,\n\t\tloadedCount,\n\t\thasEverHadMore,\n\t}\n}\n","import { componentCategory } from '@stonecrop/schema'\nimport type { ColumnSchema } from '@stonecrop/schema'\n\nimport type { TableColumn } from './types'\nimport { formatCurrency, formatQuantity } from './utils'\n\n/**\n * Convert an array of doctype field descriptors into ATable column definitions.\n *\n * Fields are excluded when:\n * - `hidden: true` — field should not be visible in any view\n * - no `component` — non-scalar entry (nested table or fieldset), no column equivalent\n *\n * `fieldname` is renamed to `name`; `hidden` is stripped. All other `ColumnSchema` properties\n * spread through automatically.\n *\n * For link fields (those carrying `doctype`) without an explicit `cellComponent`:\n * - `linkDoctype` is set from the field's `doctype` property (used by ACell's async resolver).\n * - A synchronous `format` function is added (unless the field already has one) that handles\n * both bare ID strings and pre-resolved `{ id, displayText }` objects.\n *\n * For quantity fields — those whose `component` carries the `'quantity'` category — without an\n * explicit `format`, a synchronous `format` is added that renders the `{ qty, uom }` value (see\n * `QuantityValue` in `@stonecrop/aform`) as `\"<qty> <uom>\"`.\n *\n * For currency fields — those whose `component` carries the `'currency'` category — without an\n * explicit `format`, a synchronous `format` is added that renders the `{ amount, currency }` value\n * (see `CurrencyValue` in `@stonecrop/aform`) as `\"<amount> <currency>\"`.\n *\n * @public\n */\nexport function schemaToColumns(schema: ColumnSchema[]): TableColumn[] {\n\treturn schema\n\t\t.filter(f => !f.hidden && f.component)\n\t\t.map(({ fieldname, hidden: _hidden, ...rest }) => {\n\t\t\tconst col: TableColumn = Object.assign({ name: fieldname }, rest)\n\n\t\t\t// Link fields: store the linked doctype for async resolution by ACell, and add a sync\n\t\t\t// format that handles pre-resolved AFormLinkValue objects.\n\t\t\tif (rest.doctype && !rest.cellComponent) {\n\t\t\t\tcol.linkDoctype = rest.doctype\n\n\t\t\t\tif (!rest.format) {\n\t\t\t\t\tcol.format = (v: any): string => {\n\t\t\t\t\t\tif (v === null || v === undefined) return ''\n\t\t\t\t\t\tif (typeof v === 'object') {\n\t\t\t\t\t\t\tconst display: unknown = v.displayText ?? v.id ?? ''\n\t\t\t\t\t\t\treturn typeof display === 'string' || typeof display === 'number' ? String(display) : ''\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn String(v)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Quantity fields: render the composite { qty, uom } value as \"<qty> <uom>\".\n\t\t\tif (componentCategory(rest.component) === 'quantity' && !rest.format) {\n\t\t\t\tcol.format = formatQuantity\n\t\t\t}\n\n\t\t\t// Currency fields: render the composite { amount, currency } value as \"<amount> <currency>\".\n\t\t\tif (componentCategory(rest.component) === 'currency' && !rest.format) {\n\t\t\t\tcol.format = formatCurrency\n\t\t\t}\n\n\t\t\treturn col\n\t\t})\n}\n","<template>\n\t<div class=\"atable-container\" style=\"position: relative\">\n\t\t<!-- Main table view -->\n\t\t<table\n\t\t\tref=\"table\"\n\t\t\tv-on-click-outside=\"store.closeModal\"\n\t\t\tclass=\"atable\"\n\t\t\t:style=\"{\n\t\t\t\twidth: store.config.fullWidth ? '100%' : 'auto',\n\t\t\t}\">\n\t\t\t<slot name=\"header\" :data=\"store\">\n\t\t\t\t<ATableHeader :columns=\"store.columns\" :store=\"store\" />\n\t\t\t</slot>\n\t\t\t<tbody>\n\t\t\t\t<slot name=\"body\" :data=\"store\">\n\t\t\t\t\t<ARow\n\t\t\t\t\t\tv-for=\"(row, filteredIndex) in visibleRows\"\n\t\t\t\t\t\t:key=\"`${row.originalIndex}-${filteredIndex}`\"\n\t\t\t\t\t\t:row=\"row\"\n\t\t\t\t\t\t:row-index=\"row.originalIndex\"\n\t\t\t\t\t\t:store=\"store\"\n\t\t\t\t\t\t@row:action=\"handleRowAction\"\n\t\t\t\t\t\t@row:click=\"handleRowClick\">\n\t\t\t\t\t\t<template v-for=\"(column, colIndex) in getProcessedColumnsForRow(row)\" :key=\"column.name\">\n\t\t\t\t\t\t\t<component\n\t\t\t\t\t\t\t\t:is=\"column.ganttComponent || 'AGanttCell'\"\n\t\t\t\t\t\t\t\tv-if=\"column.isGantt\"\n\t\t\t\t\t\t\t\t:store=\"store\"\n\t\t\t\t\t\t\t\t:columns-count=\"store.columns.length - pinnedColumnCount\"\n\t\t\t\t\t\t\t\t:color=\"row.gantt?.color\"\n\t\t\t\t\t\t\t\t:start=\"row.gantt?.startIndex\"\n\t\t\t\t\t\t\t\t:end=\"row.gantt?.endIndex\"\n\t\t\t\t\t\t\t\t:colspan=\"column.colspan\"\n\t\t\t\t\t\t\t\t:pinned=\"column.pinned\"\n\t\t\t\t\t\t\t\t:row-index=\"row.originalIndex\"\n\t\t\t\t\t\t\t\t:col-index=\"column.originalIndex ?? colIndex\"\n\t\t\t\t\t\t\t\t:style=\"{\n\t\t\t\t\t\t\t\t\ttextAlign: column?.align || 'center',\n\t\t\t\t\t\t\t\t\tminWidth: column?.width || '40ch',\n\t\t\t\t\t\t\t\t\twidth: store.config.fullWidth ? 'auto' : null,\n\t\t\t\t\t\t\t\t}\"\n\t\t\t\t\t\t\t\t@connection:create=\"handleConnectionCreate\" />\n\t\t\t\t\t\t\t<component\n\t\t\t\t\t\t\t\t:is=\"column.cellComponent || 'ACell'\"\n\t\t\t\t\t\t\t\tv-else\n\t\t\t\t\t\t\t\t:store=\"store\"\n\t\t\t\t\t\t\t\t:pinned=\"column.pinned\"\n\t\t\t\t\t\t\t\t:row-index=\"row.originalIndex\"\n\t\t\t\t\t\t\t\t:col-index=\"colIndex\"\n\t\t\t\t\t\t\t\t:style=\"{\n\t\t\t\t\t\t\t\t\ttextAlign: column?.align || 'center',\n\t\t\t\t\t\t\t\t\twidth: store.config.fullWidth ? 'auto' : null,\n\t\t\t\t\t\t\t\t}\"\n\t\t\t\t\t\t\t\tspellcheck=\"false\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t</ARow>\n\t\t\t\t</slot>\n\t\t\t</tbody>\n\n\t\t\t<slot name=\"footer\" :data=\"store\" :page=\"pagination\">\n\t\t\t\t<ATablePaginationFooter\n\t\t\t\t\t:column-count=\"footerColumnCount\"\n\t\t\t\t\t:show-footer=\"showFooter\"\n\t\t\t\t\t:has-more=\"hasMore\"\n\t\t\t\t\t:has-prev=\"hasPrev\"\n\t\t\t\t\t:has-next=\"hasNext\"\n\t\t\t\t\t:has-local-next=\"hasLocalNext\"\n\t\t\t\t\t:has-ever-had-more=\"hasEverHadMore\"\n\t\t\t\t\t:loaded-count=\"loadedCount\"\n\t\t\t\t\t:loading=\"paginationLoading\"\n\t\t\t\t\t:next=\"paginationNext\"\n\t\t\t\t\t:prev=\"paginationPrev\" />\n\t\t\t</slot>\n\n\t\t\t<!-- Modal overlay -->\n\t\t\t<slot name=\"modal\" :data=\"store\">\n\t\t\t\t<ATableModal v-show=\"store.modal.visible\" :store=\"store\">\n\t\t\t\t\t<template #default>\n\t\t\t\t\t\t<component\n\t\t\t\t\t\t\t:is=\"store.modal.component\"\n\t\t\t\t\t\t\t:key=\"`${store.modal.rowIndex}:${store.modal.colIndex}`\"\n\t\t\t\t\t\t\t:col-index=\"store.modal.colIndex\"\n\t\t\t\t\t\t\t:row-index=\"store.modal.rowIndex\"\n\t\t\t\t\t\t\t:store=\"store\"\n\t\t\t\t\t\t\tv-bind=\"store.modal.componentProps\" />\n\t\t\t\t\t</template>\n\t\t\t\t</ATableModal>\n\t\t\t</slot>\n\t\t</table>\n\n\t\t<!-- Connection overlay for gantt connections -->\n\t\t<AGanttConnection\n\t\t\tv-if=\"store.isGanttView && store.isDependencyGraphEnabled\"\n\t\t\t:store=\"store\"\n\t\t\t@connection:delete=\"handleConnectionDelete\" />\n\t</div>\n</template>\n\n<script setup lang=\"ts\">\nimport { vOnClickOutside } from '@vueuse/components'\nimport { useMutationObserver } from '@vueuse/core'\nimport { computed, inject, nextTick, onMounted, useTemplateRef, watch } from 'vue'\n\nimport AGanttConnection from './AGanttConnection.vue'\nimport ARow from './ARow.vue'\nimport ATableHeader from './ATableHeader.vue'\nimport ATableModal from './ATableModal.vue'\nimport ATablePaginationFooter from './ATablePaginationFooter.vue'\nimport { useTablePagination } from '../composables/table-pagination'\nimport { createTableStore } from '../stores/table'\nimport type { ColumnSchema, GetRecordsOptions, GetRecordsResult } from '@stonecrop/schema'\n\nimport { schemaToColumns } from '../schemaToColumns'\nimport type {\n\tConnectionEvent,\n\tConnectionPath,\n\tGanttDragEvent,\n\tRowActionType,\n\tRowAddEvent,\n\tRowClickEvent,\n\tRowDeleteEvent,\n\tRowDuplicateEvent,\n\tRowInsertEvent,\n\tRowMoveEvent,\n\tTableColumn,\n\tTableConfig,\n\tTableRow,\n} from '../types'\n\nconst rows = defineModel<TableRow[]>('rows', { required: true })\n// TODO: convert columns from defineModel to a regular prop\nconst columns = defineModel<TableColumn[]>('columns')\n\ntype LinkResolverFn = (doctype: string, id: string) => Promise<string | undefined>\n\nconst {\n\tid = '',\n\tconfig = new Object(),\n\tschema = [],\n\tlinkResolver = undefined,\n\tgetRecords = undefined,\n\tsourceKey = undefined,\n} = defineProps<{\n\tid?: string\n\tconfig?: TableConfig\n\tschema?: ColumnSchema[]\n\tlinkResolver?: LinkResolverFn\n\tgetRecords?: (options?: GetRecordsOptions) => Promise<GetRecordsResult>\n\tsourceKey?: string\n}>()\n\nconst emit = defineEmits<{\n\tcellUpdate: [{ colIndex: number; rowIndex: number; newValue: any; oldValue: any }]\n\t'gantt:drag': [event: GanttDragEvent]\n\t'connection:event': [event: ConnectionEvent]\n\t'columns:update': [columns: TableColumn[]]\n\t'row:add': [event: RowAddEvent]\n\t'row:click': [event: RowClickEvent]\n\t'row:delete': [event: RowDeleteEvent]\n\t'row:duplicate': [event: RowDuplicateEvent]\n\t'row:insert-above': [event: RowInsertEvent]\n\t'row:insert-below': [event: RowInsertEvent]\n\t'row:move': [event: RowMoveEvent]\n\t'row:open': [event: RowClickEvent]\n}>()\n\nconst tableRef = useTemplateRef<HTMLTableElement>('table')\nconst resolvedColumns = columns.value?.length ? columns.value : schemaToColumns(schema ?? [])\nconst injectedLinkResolver = inject<LinkResolverFn | null>('aformLinkResolver', null)\nconst store = createTableStore({\n\tcolumns: resolvedColumns,\n\trows: rows.value,\n\tid,\n\tconfig,\n\tlinkResolver: linkResolver ?? injectedLinkResolver,\n})\n\nconst pagination = useTablePagination({\n\trows: () => store.filteredRows,\n\tpageSize: () => store.config.pageSize,\n\tgetRecords,\n\tsourceKey: () => sourceKey,\n})\n\nconst {\n\tvisibleRows,\n\tshowFooter,\n\thasMore,\n\thasPrev,\n\thasNext,\n\thasLocalNext,\n\thasEverHadMore,\n\tloadedCount,\n\tloading: paginationLoading,\n\tnext: paginationNext,\n\tprev: paginationPrev,\n} = pagination\n\nconst footerColumnCount = computed(() => store.columns.length + (store.zeroColumn ? 1 : 0))\n\nstore.$onAction(({ name, store: storeInstance, args, after }) => {\n\tif (name === 'setCellData' || name === 'setCellText') {\n\t\tconst [colIndex, rowIndex, newValue] = args\n\t\tconst oldValue = storeInstance.getCellData(colIndex, rowIndex)\n\t\tafter(() => {\n\t\t\t// Update rows model to trigger update:rows event\n\t\t\trows.value = [...store.rows]\n\t\t\temit('cellUpdate', { colIndex, rowIndex, newValue, oldValue })\n\t\t})\n\t} else if (name === 'updateGanttBar') {\n\t\tconst [event] = args\n\t\tlet shouldEmit = false\n\t\tif (event.type === 'resize') {\n\t\t\tshouldEmit = event.oldColspan !== event.newColspan\n\t\t} else if (event.type === 'bar') {\n\t\t\tshouldEmit = event.oldStart !== event.newStart || event.oldEnd !== event.newEnd\n\t\t}\n\n\t\tif (shouldEmit) {\n\t\t\tafter(() => {\n\t\t\t\temit('gantt:drag', event)\n\t\t\t})\n\t\t}\n\t} else if (name === 'resizeColumn') {\n\t\tafter(() => {\n\t\t\t// Update columns model\n\t\t\tcolumns.value = [...store.columns]\n\t\t\temit('columns:update', [...store.columns])\n\t\t})\n\t}\n})\n\n// Watch for external changes to rows and sync to store\nwatch(\n\t() => rows.value,\n\tnewRows => {\n\t\t// Only update if the rows have actually changed (avoid infinite loops)\n\t\tif (JSON.stringify(newRows) !== JSON.stringify(store.rows)) {\n\t\t\tstore.rows = [...newRows]\n\t\t}\n\t},\n\t{ deep: true }\n)\n\n// Watch for changes to columns and sync to store\nwatch(\n\tcolumns,\n\tnewColumns => {\n\t\t// The model is optional, so it can be absent — there is nothing to sync from, and the store\n\t\t// keeps the columns it resolved from the schema.\n\t\tif (!newColumns) return\n\t\t// Only update if the columns have actually changed (avoid infinite loops)\n\t\tif (JSON.stringify(newColumns) !== JSON.stringify(store.columns)) {\n\t\t\tstore.columns = [...newColumns]\n\t\t\temit('columns:update', [...newColumns])\n\t\t}\n\t},\n\t{ deep: true }\n)\n\nonMounted(() => {\n\tif (columns.value?.some(column => column.pinned)) {\n\t\tassignStickyCellWidths()\n\n\t\t// in tree views, also add a mutation observer to capture and adjust expanded rows\n\t\tif (store.isTreeView) {\n\t\t\tuseMutationObserver(tableRef, assignStickyCellWidths, { childList: true, subtree: true })\n\t\t}\n\t}\n})\n\nconst pinnedColumnCount = computed(() => {\n\treturn store.columns.filter(column => column.pinned).length\n})\n\nconst assignStickyCellWidths = () => {\n\tconst table = tableRef.value\n\n\t// set header cell width to match sticky cells' width\n\tconst headerRow = table?.rows[0]\n\tconst firstDataRow = table?.rows[1]\n\tconst headerCells = headerRow ? Array.from(headerRow.cells) : []\n\tfor (const [index, headerCell] of headerCells.entries()) {\n\t\tconst rowCell = firstDataRow?.cells[index]\n\t\tif (rowCell) {\n\t\t\theaderCell.style.width = `${rowCell.offsetWidth}px`\n\t\t}\n\t}\n\n\t// pin cells in row that are sticky\n\tfor (const row of table?.rows || []) {\n\t\tlet totalWidth = 0\n\t\tconst pinnedCells: HTMLTableCellElement[] = []\n\n\t\tfor (const column of row.cells) {\n\t\t\tif (column.classList.contains('sticky-column') || column.classList.contains('sticky-index')) {\n\t\t\t\tcolumn.style.left = `${totalWidth}px`\n\t\t\t\ttotalWidth += column.offsetWidth\n\t\t\t\tpinnedCells.push(column)\n\t\t\t}\n\t\t}\n\n\t\tif (pinnedCells.length > 0) {\n\t\t\tconst lastColumn = pinnedCells[pinnedCells.length - 1]\n\t\t\tlastColumn.classList.add('sticky-column-edge')\n\t\t}\n\t}\n}\n\nwindow.addEventListener('keydown', (event: KeyboardEvent) => {\n\tif (event.key === 'Escape') {\n\t\tif (store.modal.visible) {\n\t\t\tstore.modal.visible = false\n\n\t\t\t// focus on the parent cell again\n\t\t\tconst $parent = store.modal.parent\n\t\t\tif ($parent) {\n\t\t\t\t// wait for the modal to close before focusing\n\t\t\t\tvoid nextTick().then(() => {\n\t\t\t\t\treturn $parent.focus()\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}\n})\n\nconst getProcessedColumnsForRow = (row: TableRow) => {\n\tif (!row.gantt || pinnedColumnCount.value === 0) {\n\t\treturn store.columns\n\t}\n\n\t// For Gantt views, first add the pinned columns\n\tconst result: TableColumn[] = []\n\tfor (let i = 0; i < pinnedColumnCount.value; i++) {\n\t\tconst column = { ...store.columns[i] }\n\t\tcolumn.originalIndex = i // Preserve original index\n\t\tresult.push(column)\n\t}\n\n\t// Finally, add the Gantt bar column with either a provided colspan or default to full-width colspan\n\tresult.push({\n\t\t...store.columns[pinnedColumnCount.value],\n\t\tisGantt: true,\n\t\tcolspan: row.gantt?.colspan || store.columns.length - pinnedColumnCount.value,\n\t\toriginalIndex: pinnedColumnCount.value,\n\t\twidth: 'auto', // TODO: refactor to API that can detect when data exists in a cell. Might have be custom and not generalizable\n\t})\n\n\treturn result\n}\n\nconst handleConnectionCreate = (connection: ConnectionPath) => {\n\temit('connection:event', { type: 'create', connection })\n}\n\nconst handleConnectionDelete = (connection: ConnectionPath) => {\n\temit('connection:event', { type: 'delete', connection })\n}\n\n/**\n * Handle row click events from ARow components.\n */\nconst handleRowClick = (rowIndex: number, event: MouseEvent) => {\n\tconst row = store.rows[rowIndex]\n\temit('row:click', { row, rowIndex, event })\n}\n\n/**\n * Handle row action events from ARow components.\n * Performs the default action and emits the appropriate event.\n */\nconst handleRowAction = (actionType: RowActionType, rowIndex: number, event?: MouseEvent) => {\n\tswitch (actionType) {\n\t\tcase 'add': {\n\t\t\t// Add a new row after the current row\n\t\t\tconst newIndex = store.addRow({}, rowIndex + 1)\n\t\t\tconst newRow = store.rows[newIndex]\n\t\t\trows.value = [...store.rows]\n\t\t\temit('row:add', { rowIndex: newIndex, row: newRow })\n\t\t\tbreak\n\t\t}\n\t\tcase 'delete': {\n\t\t\tconst deletedRow = store.deleteRow(rowIndex)\n\t\t\tif (deletedRow) {\n\t\t\t\trows.value = [...store.rows]\n\t\t\t\temit('row:delete', { rowIndex, row: deletedRow })\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t\tcase 'duplicate': {\n\t\t\tconst newIndex = store.duplicateRow(rowIndex)\n\t\t\tif (newIndex >= 0) {\n\t\t\t\tconst newRow = store.rows[newIndex]\n\t\t\t\trows.value = [...store.rows]\n\t\t\t\temit('row:duplicate', { sourceIndex: rowIndex, newIndex, row: newRow })\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t\tcase 'insertAbove': {\n\t\t\tconst newIndex = store.insertRowAbove(rowIndex)\n\t\t\tconst newRow = store.rows[newIndex]\n\t\t\trows.value = [...store.rows]\n\t\t\temit('row:insert-above', { targetIndex: rowIndex, newIndex, row: newRow })\n\t\t\tbreak\n\t\t}\n\t\tcase 'insertBelow': {\n\t\t\tconst newIndex = store.insertRowBelow(rowIndex)\n\t\t\tconst newRow = store.rows[newIndex]\n\t\t\trows.value = [...store.rows]\n\t\t\temit('row:insert-below', { targetIndex: rowIndex, newIndex, row: newRow })\n\t\t\tbreak\n\t\t}\n\t\tcase 'move': {\n\t\t\t// Move action requires a target index - for now, emit an event\n\t\t\t// The consumer should handle showing a UI for selecting the target\n\t\t\temit('row:move', { fromIndex: rowIndex, toIndex: -1 })\n\t\t\tbreak\n\t\t}\n\t\tcase 'moveUp': {\n\t\t\tif (rowIndex > 0 && store.moveRow(rowIndex, rowIndex - 1)) {\n\t\t\t\trows.value = [...store.rows]\n\t\t\t\temit('row:move', { fromIndex: rowIndex, toIndex: rowIndex - 1 })\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t\tcase 'moveDown': {\n\t\t\tif (rowIndex < store.rows.length - 1 && store.moveRow(rowIndex, rowIndex + 1)) {\n\t\t\t\trows.value = [...store.rows]\n\t\t\t\temit('row:move', { fromIndex: rowIndex, toIndex: rowIndex + 1 })\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t\tcase 'open': {\n\t\t\tconst row = store.rows[rowIndex]\n\t\t\temit('row:open', { row, rowIndex, event })\n\t\t\tbreak\n\t\t}\n\t}\n}\n\ndefineExpose({\n\tstore,\n\tpagination,\n\tcreateConnection: store.createConnection,\n\tdeleteConnection: store.deleteConnection,\n\tgetConnectionsForBar: store.getConnectionsForBar,\n\tgetHandlesForBar: store.getHandlesForBar,\n\t// Row action methods\n\taddRow: store.addRow,\n\tdeleteRow: store.deleteRow,\n\tduplicateRow: store.duplicateRow,\n\tinsertRowAbove: store.insertRowAbove,\n\tinsertRowBelow: store.insertRowBelow,\n\tmoveRow: store.moveRow,\n})\n</script>\n\n<style>\n.atable-container {\n\tposition: relative;\n}\n\n.sticky-index {\n\tposition: sticky;\n\tleft: 0px;\n\tz-index: 100;\n\torder: 0;\n}\n\n.sticky-column,\nth.sticky-column,\ntd.sticky-column,\nth.sticky-index,\ntd.sticky-index {\n\tposition: sticky;\n\tz-index: 100;\n\torder: 0;\n\tbackground: white;\n}\n\n.sticky-column-edge,\n.atable th.sticky-column-edge {\n\tborder-right: 1px solid var(--sc-row-border-color);\n}\n</style>\n\n<style scoped>\n.atable {\n\tposition: relative;\n\tfont-family: var(--sc-atable-font-family);\n\t-webkit-font-smoothing: antialiased;\n\t-moz-osx-font-smoothing: grayscale;\n\tfont-size: var(--sc-table-font-size);\n\tborder-collapse: collapse;\n\tbox-sizing: border-box;\n\ttable-layout: auto;\n\twidth: auto;\n\toverflow: clip;\n\theight: 1px;\n\t/* border-left:4px solid var(--sc-form-border); */\n}\n.atable th {\n\tborder-width: 0px;\n\tborder-style: solid;\n\tborder-radius: 0px;\n\tpadding-left: 0.5ch;\n\tpadding-right: 0.5ch;\n\tpadding-top: var(--sc-atable-row-padding);\n\tpadding-bottom: var(--sc-atable-row-padding);\n\tcolor: var(--sc-gray-60);\n\theight: var(--sc-atable-row-height);\n\tfont-weight: 300;\n\tletter-spacing: 0.05rem;\n\torder: 1;\n\tbox-sizing: border-box;\n}\n.atable th:focus {\n\toutline: none;\n}\n</style>\n","<template>\n\t<div class=\"atable-container\" style=\"position: relative\">\n\t\t<!-- Main table view -->\n\t\t<table\n\t\t\tref=\"table\"\n\t\t\tv-on-click-outside=\"store.closeModal\"\n\t\t\tclass=\"atable\"\n\t\t\t:style=\"{\n\t\t\t\twidth: store.config.fullWidth ? '100%' : 'auto',\n\t\t\t}\">\n\t\t\t<slot name=\"header\" :data=\"store\">\n\t\t\t\t<ATableHeader :columns=\"store.columns\" :store=\"store\" />\n\t\t\t</slot>\n\t\t\t<tbody>\n\t\t\t\t<slot name=\"body\" :data=\"store\">\n\t\t\t\t\t<ARow\n\t\t\t\t\t\tv-for=\"(row, filteredIndex) in visibleRows\"\n\t\t\t\t\t\t:key=\"`${row.originalIndex}-${filteredIndex}`\"\n\t\t\t\t\t\t:row=\"row\"\n\t\t\t\t\t\t:row-index=\"row.originalIndex\"\n\t\t\t\t\t\t:store=\"store\"\n\t\t\t\t\t\t@row:action=\"handleRowAction\"\n\t\t\t\t\t\t@row:click=\"handleRowClick\">\n\t\t\t\t\t\t<template v-for=\"(column, colIndex) in getProcessedColumnsForRow(row)\" :key=\"column.name\">\n\t\t\t\t\t\t\t<component\n\t\t\t\t\t\t\t\t:is=\"column.ganttComponent || 'AGanttCell'\"\n\t\t\t\t\t\t\t\tv-if=\"column.isGantt\"\n\t\t\t\t\t\t\t\t:store=\"store\"\n\t\t\t\t\t\t\t\t:columns-count=\"store.columns.length - pinnedColumnCount\"\n\t\t\t\t\t\t\t\t:color=\"row.gantt?.color\"\n\t\t\t\t\t\t\t\t:start=\"row.gantt?.startIndex\"\n\t\t\t\t\t\t\t\t:end=\"row.gantt?.endIndex\"\n\t\t\t\t\t\t\t\t:colspan=\"column.colspan\"\n\t\t\t\t\t\t\t\t:pinned=\"column.pinned\"\n\t\t\t\t\t\t\t\t:row-index=\"row.originalIndex\"\n\t\t\t\t\t\t\t\t:col-index=\"column.originalIndex ?? colIndex\"\n\t\t\t\t\t\t\t\t:style=\"{\n\t\t\t\t\t\t\t\t\ttextAlign: column?.align || 'center',\n\t\t\t\t\t\t\t\t\tminWidth: column?.width || '40ch',\n\t\t\t\t\t\t\t\t\twidth: store.config.fullWidth ? 'auto' : null,\n\t\t\t\t\t\t\t\t}\"\n\t\t\t\t\t\t\t\t@connection:create=\"handleConnectionCreate\" />\n\t\t\t\t\t\t\t<component\n\t\t\t\t\t\t\t\t:is=\"column.cellComponent || 'ACell'\"\n\t\t\t\t\t\t\t\tv-else\n\t\t\t\t\t\t\t\t:store=\"store\"\n\t\t\t\t\t\t\t\t:pinned=\"column.pinned\"\n\t\t\t\t\t\t\t\t:row-index=\"row.originalIndex\"\n\t\t\t\t\t\t\t\t:col-index=\"colIndex\"\n\t\t\t\t\t\t\t\t:style=\"{\n\t\t\t\t\t\t\t\t\ttextAlign: column?.align || 'center',\n\t\t\t\t\t\t\t\t\twidth: store.config.fullWidth ? 'auto' : null,\n\t\t\t\t\t\t\t\t}\"\n\t\t\t\t\t\t\t\tspellcheck=\"false\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t</ARow>\n\t\t\t\t</slot>\n\t\t\t</tbody>\n\n\t\t\t<slot name=\"footer\" :data=\"store\" :page=\"pagination\">\n\t\t\t\t<ATablePaginationFooter\n\t\t\t\t\t:column-count=\"footerColumnCount\"\n\t\t\t\t\t:show-footer=\"showFooter\"\n\t\t\t\t\t:has-more=\"hasMore\"\n\t\t\t\t\t:has-prev=\"hasPrev\"\n\t\t\t\t\t:has-next=\"hasNext\"\n\t\t\t\t\t:has-local-next=\"hasLocalNext\"\n\t\t\t\t\t:has-ever-had-more=\"hasEverHadMore\"\n\t\t\t\t\t:loaded-count=\"loadedCount\"\n\t\t\t\t\t:loading=\"paginationLoading\"\n\t\t\t\t\t:next=\"paginationNext\"\n\t\t\t\t\t:prev=\"paginationPrev\" />\n\t\t\t</slot>\n\n\t\t\t<!-- Modal overlay -->\n\t\t\t<slot name=\"modal\" :data=\"store\">\n\t\t\t\t<ATableModal v-show=\"store.modal.visible\" :store=\"store\">\n\t\t\t\t\t<template #default>\n\t\t\t\t\t\t<component\n\t\t\t\t\t\t\t:is=\"store.modal.component\"\n\t\t\t\t\t\t\t:key=\"`${store.modal.rowIndex}:${store.modal.colIndex}`\"\n\t\t\t\t\t\t\t:col-index=\"store.modal.colIndex\"\n\t\t\t\t\t\t\t:row-index=\"store.modal.rowIndex\"\n\t\t\t\t\t\t\t:store=\"store\"\n\t\t\t\t\t\t\tv-bind=\"store.modal.componentProps\" />\n\t\t\t\t\t</template>\n\t\t\t\t</ATableModal>\n\t\t\t</slot>\n\t\t</table>\n\n\t\t<!-- Connection overlay for gantt connections -->\n\t\t<AGanttConnection\n\t\t\tv-if=\"store.isGanttView && store.isDependencyGraphEnabled\"\n\t\t\t:store=\"store\"\n\t\t\t@connection:delete=\"handleConnectionDelete\" />\n\t</div>\n</template>\n\n<script setup lang=\"ts\">\nimport { vOnClickOutside } from '@vueuse/components'\nimport { useMutationObserver } from '@vueuse/core'\nimport { computed, inject, nextTick, onMounted, useTemplateRef, watch } from 'vue'\n\nimport AGanttConnection from './AGanttConnection.vue'\nimport ARow from './ARow.vue'\nimport ATableHeader from './ATableHeader.vue'\nimport ATableModal from './ATableModal.vue'\nimport ATablePaginationFooter from './ATablePaginationFooter.vue'\nimport { useTablePagination } from '../composables/table-pagination'\nimport { createTableStore } from '../stores/table'\nimport type { ColumnSchema, GetRecordsOptions, GetRecordsResult } from '@stonecrop/schema'\n\nimport { schemaToColumns } from '../schemaToColumns'\nimport type {\n\tConnectionEvent,\n\tConnectionPath,\n\tGanttDragEvent,\n\tRowActionType,\n\tRowAddEvent,\n\tRowClickEvent,\n\tRowDeleteEvent,\n\tRowDuplicateEvent,\n\tRowInsertEvent,\n\tRowMoveEvent,\n\tTableColumn,\n\tTableConfig,\n\tTableRow,\n} from '../types'\n\nconst rows = defineModel<TableRow[]>('rows', { required: true })\n// TODO: convert columns from defineModel to a regular prop\nconst columns = defineModel<TableColumn[]>('columns')\n\ntype LinkResolverFn = (doctype: string, id: string) => Promise<string | undefined>\n\nconst {\n\tid = '',\n\tconfig = new Object(),\n\tschema = [],\n\tlinkResolver = undefined,\n\tgetRecords = undefined,\n\tsourceKey = undefined,\n} = defineProps<{\n\tid?: string\n\tconfig?: TableConfig\n\tschema?: ColumnSchema[]\n\tlinkResolver?: LinkResolverFn\n\tgetRecords?: (options?: GetRecordsOptions) => Promise<GetRecordsResult>\n\tsourceKey?: string\n}>()\n\nconst emit = defineEmits<{\n\tcellUpdate: [{ colIndex: number; rowIndex: number; newValue: any; oldValue: any }]\n\t'gantt:drag': [event: GanttDragEvent]\n\t'connection:event': [event: ConnectionEvent]\n\t'columns:update': [columns: TableColumn[]]\n\t'row:add': [event: RowAddEvent]\n\t'row:click': [event: RowClickEvent]\n\t'row:delete': [event: RowDeleteEvent]\n\t'row:duplicate': [event: RowDuplicateEvent]\n\t'row:insert-above': [event: RowInsertEvent]\n\t'row:insert-below': [event: RowInsertEvent]\n\t'row:move': [event: RowMoveEvent]\n\t'row:open': [event: RowClickEvent]\n}>()\n\nconst tableRef = useTemplateRef<HTMLTableElement>('table')\nconst resolvedColumns = columns.value?.length ? columns.value : schemaToColumns(schema ?? [])\nconst injectedLinkResolver = inject<LinkResolverFn | null>('aformLinkResolver', null)\nconst store = createTableStore({\n\tcolumns: resolvedColumns,\n\trows: rows.value,\n\tid,\n\tconfig,\n\tlinkResolver: linkResolver ?? injectedLinkResolver,\n})\n\nconst pagination = useTablePagination({\n\trows: () => store.filteredRows,\n\tpageSize: () => store.config.pageSize,\n\tgetRecords,\n\tsourceKey: () => sourceKey,\n})\n\nconst {\n\tvisibleRows,\n\tshowFooter,\n\thasMore,\n\thasPrev,\n\thasNext,\n\thasLocalNext,\n\thasEverHadMore,\n\tloadedCount,\n\tloading: paginationLoading,\n\tnext: paginationNext,\n\tprev: paginationPrev,\n} = pagination\n\nconst footerColumnCount = computed(() => store.columns.length + (store.zeroColumn ? 1 : 0))\n\nstore.$onAction(({ name, store: storeInstance, args, after }) => {\n\tif (name === 'setCellData' || name === 'setCellText') {\n\t\tconst [colIndex, rowIndex, newValue] = args\n\t\tconst oldValue = storeInstance.getCellData(colIndex, rowIndex)\n\t\tafter(() => {\n\t\t\t// Update rows model to trigger update:rows event\n\t\t\trows.value = [...store.rows]\n\t\t\temit('cellUpdate', { colIndex, rowIndex, newValue, oldValue })\n\t\t})\n\t} else if (name === 'updateGanttBar') {\n\t\tconst [event] = args\n\t\tlet shouldEmit = false\n\t\tif (event.type === 'resize') {\n\t\t\tshouldEmit = event.oldColspan !== event.newColspan\n\t\t} else if (event.type === 'bar') {\n\t\t\tshouldEmit = event.oldStart !== event.newStart || event.oldEnd !== event.newEnd\n\t\t}\n\n\t\tif (shouldEmit) {\n\t\t\tafter(() => {\n\t\t\t\temit('gantt:drag', event)\n\t\t\t})\n\t\t}\n\t} else if (name === 'resizeColumn') {\n\t\tafter(() => {\n\t\t\t// Update columns model\n\t\t\tcolumns.value = [...store.columns]\n\t\t\temit('columns:update', [...store.columns])\n\t\t})\n\t}\n})\n\n// Watch for external changes to rows and sync to store\nwatch(\n\t() => rows.value,\n\tnewRows => {\n\t\t// Only update if the rows have actually changed (avoid infinite loops)\n\t\tif (JSON.stringify(newRows) !== JSON.stringify(store.rows)) {\n\t\t\tstore.rows = [...newRows]\n\t\t}\n\t},\n\t{ deep: true }\n)\n\n// Watch for changes to columns and sync to store\nwatch(\n\tcolumns,\n\tnewColumns => {\n\t\t// The model is optional, so it can be absent — there is nothing to sync from, and the store\n\t\t// keeps the columns it resolved from the schema.\n\t\tif (!newColumns) return\n\t\t// Only update if the columns have actually changed (avoid infinite loops)\n\t\tif (JSON.stringify(newColumns) !== JSON.stringify(store.columns)) {\n\t\t\tstore.columns = [...newColumns]\n\t\t\temit('columns:update', [...newColumns])\n\t\t}\n\t},\n\t{ deep: true }\n)\n\nonMounted(() => {\n\tif (columns.value?.some(column => column.pinned)) {\n\t\tassignStickyCellWidths()\n\n\t\t// in tree views, also add a mutation observer to capture and adjust expanded rows\n\t\tif (store.isTreeView) {\n\t\t\tuseMutationObserver(tableRef, assignStickyCellWidths, { childList: true, subtree: true })\n\t\t}\n\t}\n})\n\nconst pinnedColumnCount = computed(() => {\n\treturn store.columns.filter(column => column.pinned).length\n})\n\nconst assignStickyCellWidths = () => {\n\tconst table = tableRef.value\n\n\t// set header cell width to match sticky cells' width\n\tconst headerRow = table?.rows[0]\n\tconst firstDataRow = table?.rows[1]\n\tconst headerCells = headerRow ? Array.from(headerRow.cells) : []\n\tfor (const [index, headerCell] of headerCells.entries()) {\n\t\tconst rowCell = firstDataRow?.cells[index]\n\t\tif (rowCell) {\n\t\t\theaderCell.style.width = `${rowCell.offsetWidth}px`\n\t\t}\n\t}\n\n\t// pin cells in row that are sticky\n\tfor (const row of table?.rows || []) {\n\t\tlet totalWidth = 0\n\t\tconst pinnedCells: HTMLTableCellElement[] = []\n\n\t\tfor (const column of row.cells) {\n\t\t\tif (column.classList.contains('sticky-column') || column.classList.contains('sticky-index')) {\n\t\t\t\tcolumn.style.left = `${totalWidth}px`\n\t\t\t\ttotalWidth += column.offsetWidth\n\t\t\t\tpinnedCells.push(column)\n\t\t\t}\n\t\t}\n\n\t\tif (pinnedCells.length > 0) {\n\t\t\tconst lastColumn = pinnedCells[pinnedCells.length - 1]\n\t\t\tlastColumn.classList.add('sticky-column-edge')\n\t\t}\n\t}\n}\n\nwindow.addEventListener('keydown', (event: KeyboardEvent) => {\n\tif (event.key === 'Escape') {\n\t\tif (store.modal.visible) {\n\t\t\tstore.modal.visible = false\n\n\t\t\t// focus on the parent cell again\n\t\t\tconst $parent = store.modal.parent\n\t\t\tif ($parent) {\n\t\t\t\t// wait for the modal to close before focusing\n\t\t\t\tvoid nextTick().then(() => {\n\t\t\t\t\treturn $parent.focus()\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}\n})\n\nconst getProcessedColumnsForRow = (row: TableRow) => {\n\tif (!row.gantt || pinnedColumnCount.value === 0) {\n\t\treturn store.columns\n\t}\n\n\t// For Gantt views, first add the pinned columns\n\tconst result: TableColumn[] = []\n\tfor (let i = 0; i < pinnedColumnCount.value; i++) {\n\t\tconst column = { ...store.columns[i] }\n\t\tcolumn.originalIndex = i // Preserve original index\n\t\tresult.push(column)\n\t}\n\n\t// Finally, add the Gantt bar column with either a provided colspan or default to full-width colspan\n\tresult.push({\n\t\t...store.columns[pinnedColumnCount.value],\n\t\tisGantt: true,\n\t\tcolspan: row.gantt?.colspan || store.columns.length - pinnedColumnCount.value,\n\t\toriginalIndex: pinnedColumnCount.value,\n\t\twidth: 'auto', // TODO: refactor to API that can detect when data exists in a cell. Might have be custom and not generalizable\n\t})\n\n\treturn result\n}\n\nconst handleConnectionCreate = (connection: ConnectionPath) => {\n\temit('connection:event', { type: 'create', connection })\n}\n\nconst handleConnectionDelete = (connection: ConnectionPath) => {\n\temit('connection:event', { type: 'delete', connection })\n}\n\n/**\n * Handle row click events from ARow components.\n */\nconst handleRowClick = (rowIndex: number, event: MouseEvent) => {\n\tconst row = store.rows[rowIndex]\n\temit('row:click', { row, rowIndex, event })\n}\n\n/**\n * Handle row action events from ARow components.\n * Performs the default action and emits the appropriate event.\n */\nconst handleRowAction = (actionType: RowActionType, rowIndex: number, event?: MouseEvent) => {\n\tswitch (actionType) {\n\t\tcase 'add': {\n\t\t\t// Add a new row after the current row\n\t\t\tconst newIndex = store.addRow({}, rowIndex + 1)\n\t\t\tconst newRow = store.rows[newIndex]\n\t\t\trows.value = [...store.rows]\n\t\t\temit('row:add', { rowIndex: newIndex, row: newRow })\n\t\t\tbreak\n\t\t}\n\t\tcase 'delete': {\n\t\t\tconst deletedRow = store.deleteRow(rowIndex)\n\t\t\tif (deletedRow) {\n\t\t\t\trows.value = [...store.rows]\n\t\t\t\temit('row:delete', { rowIndex, row: deletedRow })\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t\tcase 'duplicate': {\n\t\t\tconst newIndex = store.duplicateRow(rowIndex)\n\t\t\tif (newIndex >= 0) {\n\t\t\t\tconst newRow = store.rows[newIndex]\n\t\t\t\trows.value = [...store.rows]\n\t\t\t\temit('row:duplicate', { sourceIndex: rowIndex, newIndex, row: newRow })\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t\tcase 'insertAbove': {\n\t\t\tconst newIndex = store.insertRowAbove(rowIndex)\n\t\t\tconst newRow = store.rows[newIndex]\n\t\t\trows.value = [...store.rows]\n\t\t\temit('row:insert-above', { targetIndex: rowIndex, newIndex, row: newRow })\n\t\t\tbreak\n\t\t}\n\t\tcase 'insertBelow': {\n\t\t\tconst newIndex = store.insertRowBelow(rowIndex)\n\t\t\tconst newRow = store.rows[newIndex]\n\t\t\trows.value = [...store.rows]\n\t\t\temit('row:insert-below', { targetIndex: rowIndex, newIndex, row: newRow })\n\t\t\tbreak\n\t\t}\n\t\tcase 'move': {\n\t\t\t// Move action requires a target index - for now, emit an event\n\t\t\t// The consumer should handle showing a UI for selecting the target\n\t\t\temit('row:move', { fromIndex: rowIndex, toIndex: -1 })\n\t\t\tbreak\n\t\t}\n\t\tcase 'moveUp': {\n\t\t\tif (rowIndex > 0 && store.moveRow(rowIndex, rowIndex - 1)) {\n\t\t\t\trows.value = [...store.rows]\n\t\t\t\temit('row:move', { fromIndex: rowIndex, toIndex: rowIndex - 1 })\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t\tcase 'moveDown': {\n\t\t\tif (rowIndex < store.rows.length - 1 && store.moveRow(rowIndex, rowIndex + 1)) {\n\t\t\t\trows.value = [...store.rows]\n\t\t\t\temit('row:move', { fromIndex: rowIndex, toIndex: rowIndex + 1 })\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t\tcase 'open': {\n\t\t\tconst row = store.rows[rowIndex]\n\t\t\temit('row:open', { row, rowIndex, event })\n\t\t\tbreak\n\t\t}\n\t}\n}\n\ndefineExpose({\n\tstore,\n\tpagination,\n\tcreateConnection: store.createConnection,\n\tdeleteConnection: store.deleteConnection,\n\tgetConnectionsForBar: store.getConnectionsForBar,\n\tgetHandlesForBar: store.getHandlesForBar,\n\t// Row action methods\n\taddRow: store.addRow,\n\tdeleteRow: store.deleteRow,\n\tduplicateRow: store.duplicateRow,\n\tinsertRowAbove: store.insertRowAbove,\n\tinsertRowBelow: store.insertRowBelow,\n\tmoveRow: store.moveRow,\n})\n</script>\n\n<style>\n.atable-container {\n\tposition: relative;\n}\n\n.sticky-index {\n\tposition: sticky;\n\tleft: 0px;\n\tz-index: 100;\n\torder: 0;\n}\n\n.sticky-column,\nth.sticky-column,\ntd.sticky-column,\nth.sticky-index,\ntd.sticky-index {\n\tposition: sticky;\n\tz-index: 100;\n\torder: 0;\n\tbackground: white;\n}\n\n.sticky-column-edge,\n.atable th.sticky-column-edge {\n\tborder-right: 1px solid var(--sc-row-border-color);\n}\n</style>\n\n<style scoped>\n.atable {\n\tposition: relative;\n\tfont-family: var(--sc-atable-font-family);\n\t-webkit-font-smoothing: antialiased;\n\t-moz-osx-font-smoothing: grayscale;\n\tfont-size: var(--sc-table-font-size);\n\tborder-collapse: collapse;\n\tbox-sizing: border-box;\n\ttable-layout: auto;\n\twidth: auto;\n\toverflow: clip;\n\theight: 1px;\n\t/* border-left:4px solid var(--sc-form-border); */\n}\n.atable th {\n\tborder-width: 0px;\n\tborder-style: solid;\n\tborder-radius: 0px;\n\tpadding-left: 0.5ch;\n\tpadding-right: 0.5ch;\n\tpadding-top: var(--sc-atable-row-padding);\n\tpadding-bottom: var(--sc-atable-row-padding);\n\tcolor: var(--sc-gray-60);\n\theight: var(--sc-atable-row-height);\n\tfont-weight: 300;\n\tletter-spacing: 0.05rem;\n\torder: 1;\n\tbox-sizing: border-box;\n}\n.atable th:focus {\n\toutline: none;\n}\n</style>\n","<template>\n\t<div class=\"aloading\">\n\t\t<h2 class=\"aloading-header\">\n\t\t\t<slot></slot>\n\t\t</h2>\n\t\t<div class=\"aloading-bar\"></div>\n\t</div>\n</template>\n\n<style scoped>\n.aloading {\n\twidth: 100%;\n\tborder-top: 1px solid var(--sc-row-border-color);\n\tborder-bottom: 1px solid var(--sc-row-border-color);\n\tdisplay: flex;\n\tbackground-color: white;\n\tborder-left: 4px solid var(--sc-row-border-color);\n\tpadding-left: 0.5ch !important;\n\tpadding-right: 0.5ch;\n\tpadding-top: var(--sc-atable-row-padding);\n\tpadding-bottom: var(--sc-atable-row-padding);\n\talign-items: center;\n\tbox-sizing: border-box;\n\tbackground: var(--sc-focus-cell-background);\n\toverflow: hidden;\n\tposition: relative;\n}\n.aloading-bar {\n\twidth: 100%;\n\theight: 100%;\n\tposition: absolute;\n\tleft: -100%;\n\ttop: 0;\n\tbackground: linear-gradient(\n\t\t90deg,\n\t\trgba(var(--sc-table-loading-color), 0) 0%,\n\t\trgba(var(--sc-table-loading-color), 1) 50%,\n\t\trgba(var(--sc-table-loading-color), 0) 100%\n\t);\n\tanimation: gradient infinite 2s;\n\tz-index: 0;\n}\n.aloading-header {\n\tcolor: var(--sc-cell-text-color);\n\tfont-family: var(--sc-atable-font-family);\n\t-webkit-font-smoothing: antialiased;\n\t-moz-osx-font-smoothing: grayscale;\n\tfont-size: var(--sc-table-font-size);\n\tpadding: 0;\n\tmargin: 0;\n\tfont-weight: normal;\n\tz-index: 1;\n}\n.aloading-header::after {\n\tcontent: '...';\n\tanimation: ellipse 2s;\n\tanimation-iteration-count: infinite;\n}\n\n@keyframes gradient {\n\t0% {\n\t\tleft: -100%;\n\t}\n\t100% {\n\t\tleft: 100%;\n\t}\n}\n\n@keyframes ellipse {\n\t0% {\n\t\tcontent: '';\n\t}\n\t20% {\n\t\tcontent: '';\n\t}\n\t40% {\n\t\tcontent: '.';\n\t}\n\t60% {\n\t\tcontent: '..';\n\t}\n\t80% {\n\t\tcontent: '...';\n\t}\n}\n</style>\n","<template>\n\t<div class=\"aloading\">\n\t\t<h2 class=\"aloading-header\">\n\t\t\t<slot></slot>\n\t\t</h2>\n\t\t<div class=\"aloading-bar\"></div>\n\t</div>\n</template>\n\n<style scoped>\n.aloading {\n\twidth: 100%;\n\tborder-top: 1px solid var(--sc-row-border-color);\n\tborder-bottom: 1px solid var(--sc-row-border-color);\n\tdisplay: flex;\n\tbackground-color: white;\n\tborder-left: 4px solid var(--sc-row-border-color);\n\tpadding-left: 0.5ch !important;\n\tpadding-right: 0.5ch;\n\tpadding-top: var(--sc-atable-row-padding);\n\tpadding-bottom: var(--sc-atable-row-padding);\n\talign-items: center;\n\tbox-sizing: border-box;\n\tbackground: var(--sc-focus-cell-background);\n\toverflow: hidden;\n\tposition: relative;\n}\n.aloading-bar {\n\twidth: 50%;\n\theight: 3px;\n\tposition: absolute;\n\tleft: -100%;\n\tbottom: 0;\n\tbackground: var(--sc-row-border-color);\n\tanimation: bar-left infinite 2s;\n\tz-index: 0;\n}\n.aloading-header {\n\tcolor: var(--sc-cell-text-color);\n\tfont-family: var(--sc-atable-font-family);\n\t-webkit-font-smoothing: antialiased;\n\t-moz-osx-font-smoothing: grayscale;\n\tfont-size: var(--sc-table-font-size);\n\tpadding: 0;\n\tmargin: 0;\n\tfont-weight: normal;\n\tz-index: 1;\n}\n.aloading-header::after {\n\tcontent: '...';\n\tanimation: ellipse 2s;\n\tanimation-iteration-count: infinite;\n}\n\n@keyframes bar-left {\n\t0% {\n\t\tleft: -50%;\n\t}\n\t100% {\n\t\tleft: 100%;\n\t}\n}\n\n@keyframes ellipse {\n\t0% {\n\t\tcontent: '';\n\t}\n\t20% {\n\t\tcontent: '';\n\t}\n\t40% {\n\t\tcontent: '.';\n\t}\n\t60% {\n\t\tcontent: '..';\n\t}\n\t80% {\n\t\tcontent: '...';\n\t}\n}\n</style>\n","import { App } from 'vue'\n\nimport ACell from './components/ACell.vue'\nimport AGanttCell from './components/AGanttCell.vue'\nimport ARow from './components/ARow.vue'\nimport ARowActions from './components/ARowActions.vue'\nimport ATable from './components/ATable.vue'\nimport ATableHeader from './components/ATableHeader.vue'\nimport ATableLoading from './components/ATableLoading.vue'\nimport ATableLoadingBar from './components/ATableLoadingBar.vue'\nimport ATableModal from './components/ATableModal.vue'\nimport ATablePaginationFooter from './components/ATablePaginationFooter.vue'\nexport { createTableStore } from './stores/table'\nexport { useTablePagination } from './composables/table-pagination'\nexport type { FilteredTableRow, TablePagination, UseTablePaginationOptions } from './composables/table-pagination'\nexport type { FilterState, FilterStateRecord } from './stores/table'\nexport type * from './types'\nexport { schemaToColumns } from './schemaToColumns'\n\n// Icon exports\nexport {\n\tAddIcon,\n\tDeleteIcon,\n\tDuplicateIcon,\n\tInsertAboveIcon,\n\tInsertBelowIcon,\n\tMoveIcon,\n\tOpenIcon,\n\tactionIcons,\n} from './icons'\n\n/**\n * Install all ATable components\n * @param app - Vue app instance\n * @public\n */\nfunction install(app: App /* options */) {\n\tapp.component('ACell', ACell)\n\tapp.component('AGanttCell', AGanttCell)\n\tapp.component('ARow', ARow)\n\tapp.component('ARowActions', ARowActions)\n\tapp.component('ATable', ATable)\n\tapp.component('ATableHeader', ATableHeader)\n\tapp.component('ATableLoading', ATableLoading)\n\tapp.component('ATableLoadingBar', ATableLoadingBar)\n\tapp.component('ATableModal', ATableModal)\n\tapp.component('ATablePaginationFooter', ATablePaginationFooter)\n}\n\nexport {\n\tACell,\n\tAGanttCell,\n\tARow,\n\tARowActions,\n\tATable,\n\tATableHeader,\n\tATableLoading,\n\tATableLoadingBar,\n\tATableModal,\n\tATablePaginationFooter,\n\tinstall,\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"atable.js","names":["$attrs"],"sources":["../src/linkSearchableText.ts","../src/resolveFilterType.ts","../src/utils.ts","../src/stores/table.ts","../src/components/ACell.vue","../src/components/ACell.vue","../src/components/AGanttCell.vue","../src/components/AGanttCell.vue","../src/icons/index.ts","../src/components/ARowActions.vue","../src/components/ARowActions.vue","../src/components/ARow.vue","../src/components/ARow.vue","../src/components/AGanttConnection.vue","../src/components/AGanttConnection.vue","../src/components/ATableColumnFilter.vue","../src/components/ATableColumnFilter.vue","../src/components/ATableHeader.vue","../src/components/ATableHeader.vue","../src/components/ATableModal.vue","../src/components/ATableModal.vue","../src/components/ATablePaginationFooter.vue","../src/components/ATablePaginationFooter.vue","../src/composables/table-pagination.ts","../src/schemaToColumns.ts","../src/components/ATable.vue","../src/components/ATable.vue","../src/components/ATableLoading.vue","../src/components/ATableLoadingBar.vue","../src/index.ts"],"sourcesContent":["/**\n * Normalize a scalar cell value to a non-empty string, or nothing.\n *\n * Rejecting objects is what the haystack wants: a nested value has no single textual form, and\n * `String()` on one contributes `[object Object]`, which matches a search for \"object\" and nothing\n * a user would actually type.\n */\nfunction scalarText(value: unknown): string | undefined {\n\tif (value == null || typeof value === 'object') return undefined\n\tif (typeof value === 'string') return value === '' ? undefined : value\n\tif (typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint') {\n\t\treturn String(value)\n\t}\n\treturn undefined\n}\n\n/**\n * Build the substring-search haystack for a link column cell.\n * Server middleware enriches inline FKs to `{ id, displayText }`; search both.\n * @public\n */\nexport function linkSearchableText(cellValue: unknown): string {\n\tif (cellValue == null || cellValue === '') return ''\n\n\t// `in` rather than an assertion to `Record<string, unknown>`: the assertion claims the value has\n\t// string keys of unknown type, which is narrower than `object` and so is a claim this function\n\t// cannot make about a cell it did not build.\n\tif (typeof cellValue === 'object') {\n\t\tconst parts: string[] = []\n\t\tif ('id' in cellValue) {\n\t\t\tconst id = scalarText(cellValue.id)\n\t\t\tif (id !== undefined) parts.push(id)\n\t\t}\n\t\tif ('displayText' in cellValue) {\n\t\t\tconst displayText = scalarText(cellValue.displayText)\n\t\t\tif (displayText !== undefined) parts.push(displayText)\n\t\t}\n\t\treturn parts.join(' ')\n\t}\n\n\treturn scalarText(cellValue) ?? ''\n}\n","import { componentCategory, type ComponentCategory } from '@stonecrop/schema'\n\nimport type { TableColumn } from './types'\n\n/** Filter widget type derived from a component's semantic category. */\nexport type ResolvedFilterType = 'text' | 'select' | 'number' | 'date' | 'dateRange' | 'checkbox' | 'component'\n\nconst CATEGORY_FILTER: Record<ComponentCategory, Exclude<ResolvedFilterType, 'component'>> = {\n\ttext: 'text',\n\tnumber: 'number',\n\tboolean: 'checkbox',\n\tdate: 'date',\n\tdatetime: 'dateRange',\n\tselect: 'select',\n\tcode: 'text',\n\tlink: 'text',\n\tattach: 'text',\n\tquantity: 'number',\n\tcurrency: 'number',\n}\n\n/**\n * Resolve the filter widget and filter logic type for a column.\n * Explicit `filterType` wins; otherwise derive from the component category.\n * @public\n */\nexport function resolveFilterType(column: Pick<TableColumn, 'filterType' | 'component'>): ResolvedFilterType {\n\tif (column.filterType) return column.filterType\n\tconst category = componentCategory(column.component)\n\tif (category) return CATEGORY_FILTER[category]\n\treturn 'text'\n}\n","export const isHtmlString = (htmlString: string) => {\n\tconst $document = new DOMParser().parseFromString(htmlString, 'text/html')\n\treturn Array.from($document.body.childNodes).some(node => node.nodeType === 1)\n}\n\nexport const generateHash = (length = 8) => {\n\treturn Array.from({ length }, () => Math.floor(Math.random() * 16).toString(16)).join('')\n}\n\n/**\n * Render a composite quantity value (`{ qty, uom }`, see `QuantityValue` in `@stonecrop/aform`)\n * as `\"<qty> <uom>\"`. Shared by the two paths a quantity column can reach formatting through:\n * the `format` that `schemaToColumns` attaches, and the table store's category-based default.\n */\nexport const formatQuantity = (value: any): string => {\n\tif (value === null || value === undefined) return ''\n\tif (typeof value === 'object') {\n\t\tconst qty = value.qty ?? ''\n\t\tconst uom = value.uom ?? ''\n\t\treturn uom ? `${qty} ${uom}`.trim() : String(qty)\n\t}\n\treturn String(value)\n}\n\n/**\n * Render a composite currency value (`{ amount, currency }`, see `CurrencyValue` in\n * `@stonecrop/aform`) as `\"<amount> <currency>\"`. `currency` is an AFormLinkValue FK reference —\n * its `displayText` is preferred, falling back to `id`. Shared by the two paths a currency column\n * can reach formatting through: the `format` that `schemaToColumns` attaches, and the table\n * store's category-based default.\n */\nexport const formatCurrency = (value: any): string => {\n\tif (value === null || value === undefined) return ''\n\tif (typeof value === 'object') {\n\t\tconst amount = value.amount ?? ''\n\t\tconst currency = value.currency?.displayText ?? value.currency?.id ?? ''\n\t\treturn currency ? `${amount} ${currency}`.trim() : String(amount)\n\t}\n\treturn String(value)\n}\n","import { defineStore } from 'pinia'\nimport { componentCategory } from '@stonecrop/schema'\nimport type { BadgeDescriptor } from '@stonecrop/schema'\nimport { type CSSProperties, computed, ref } from 'vue'\n\nimport { linkSearchableText } from '../linkSearchableText'\nimport type {\n\tCellContext,\n\tConnectionHandle,\n\tConnectionPath,\n\tGanttBarInfo,\n\tGanttDragEvent,\n\tTableColumn,\n\tTableConfig,\n\tTableDisplay,\n\tTableModal,\n\tTableRow,\n} from '../types'\nimport { resolveFilterType } from '../resolveFilterType'\nimport { formatCurrency, formatQuantity, generateHash } from '../utils'\n\n/**\n * Represents the state of a single filter\n * @public\n */\nexport interface FilterState {\n\t/** The main filter value */\n\tvalue: any\n\t/** Start value for date range filters */\n\tstartValue?: any\n\t/** End value for date range filters */\n\tendValue?: any\n}\n\n/**\n * Record mapping column indices to their filter states\n * @public\n */\nexport type FilterStateRecord = Record<number, FilterState>\n\n// Quantity columns hold a composite `{ qty, uom, ... }` value (see `QuantityValue` in\n// `@stonecrop/aform`); numeric comparisons (filtering, sorting) operate on `qty`.\n//\n// Currency columns hold a composite `{ amount, currency, baseAmount, ... }` value (see\n// `CurrencyValue` in `@stonecrop/aform`), and a single column routinely mixes currencies —\n// comparing raw `amount` would rank 5 EUR equal to 5 USD and match 100 JPY against a `> 100`\n// filter. `baseAmount` is the whole reason the value carries one: it restates every row in the\n// record's base currency, which is the only axis on which they are comparable. Fall back to\n// `amount` for a value that predates the base conversion (or was authored without one).\nfunction toComparableNumber(cellValue: unknown): number {\n\tif (cellValue !== null && typeof cellValue === 'object') {\n\t\tif ('qty' in cellValue) return Number(cellValue.qty)\n\t\tif ('baseAmount' in cellValue && (cellValue as { baseAmount: unknown }).baseAmount != null) {\n\t\t\treturn Number((cellValue as { baseAmount: unknown }).baseAmount)\n\t\t}\n\t\tif ('amount' in cellValue) return Number((cellValue as { amount: unknown }).amount)\n\t}\n\treturn Number(cellValue)\n}\n\nfunction isNodeOpen(rowIndex: number, treeDisplay: TableDisplay[]): boolean {\n\tconst row = treeDisplay[rowIndex]\n\tif (row.isRoot) {\n\t\treturn true // Root nodes are always open\n\t}\n\n\tif (row.parent === null || row.parent === undefined) {\n\t\treturn true\n\t}\n\n\tconst parentIndex = row.parent\n\tif (parentIndex < 0 || parentIndex >= treeDisplay.length) {\n\t\treturn false\n\t}\n\n\tconst parent = treeDisplay[parentIndex]\n\t// Node is open if parent's children are open AND parent itself is open\n\treturn (parent.childrenOpen || false) && isNodeOpen(parentIndex, treeDisplay)\n}\n\nfunction applyFilter(cellValue: any, filter: FilterState, column: TableColumn): boolean {\n\tconst filterType = resolveFilterType(column)\n\tconst value = filter.value\n\n\tif (!value && filterType !== 'dateRange' && filterType !== 'checkbox') return true\n\n\tswitch (filterType) {\n\t\tcase 'text': {\n\t\t\tconst searchableText = column.linkDoctype\n\t\t\t\t? linkSearchableText(cellValue)\n\t\t\t\t: typeof cellValue === 'object' && cellValue !== null\n\t\t\t\t\t? Object.values(cellValue).join(' ')\n\t\t\t\t\t: String(cellValue || '')\n\t\t\treturn searchableText.toLowerCase().includes(String(value).toLowerCase())\n\t\t}\n\n\t\tcase 'number': {\n\t\t\tconst numValue = toComparableNumber(cellValue)\n\t\t\tconst filterNum = Number(value)\n\t\t\treturn !isNaN(numValue) && !isNaN(filterNum) && numValue === filterNum\n\t\t}\n\n\t\tcase 'select':\n\t\t\treturn cellValue === value\n\n\t\tcase 'checkbox':\n\t\t\t// For checkbox filter, if checked (true), show only truthy values\n\t\t\t// If unchecked (false/undefined), show all values\n\t\t\tif (value === true) {\n\t\t\t\treturn !!cellValue\n\t\t\t}\n\t\t\treturn true\n\n\t\tcase 'date': {\n\t\t\t// Handle both timestamp numbers and date strings\n\t\t\tlet cellDate: Date\n\t\t\tif (typeof cellValue === 'number') {\n\t\t\t\t// Apply the same year transformation as in the format function\n\t\t\t\tconst originalDate = new Date(cellValue)\n\t\t\t\tconst currentYear = new Date().getFullYear()\n\t\t\t\tcellDate = new Date(currentYear, originalDate.getMonth(), originalDate.getDate())\n\t\t\t} else {\n\t\t\t\tcellDate = new Date(String(cellValue))\n\t\t\t}\n\t\t\tconst filterDate = new Date(String(value))\n\t\t\treturn cellDate.toDateString() === filterDate.toDateString()\n\t\t}\n\n\t\tcase 'dateRange': {\n\t\t\tconst startValue = filter.startValue\n\t\t\tconst endValue = filter.endValue\n\t\t\tif (!startValue && !endValue) return true\n\n\t\t\t// Handle both timestamp numbers and date strings\n\t\t\tlet cellDateRange: Date\n\t\t\tif (typeof cellValue === 'number') {\n\t\t\t\t// Apply the same year transformation as in the format function\n\t\t\t\tconst originalDate = new Date(cellValue)\n\t\t\t\tconst currentYear = new Date().getFullYear()\n\t\t\t\tcellDateRange = new Date(currentYear, originalDate.getMonth(), originalDate.getDate())\n\t\t\t} else {\n\t\t\t\tcellDateRange = new Date(String(cellValue))\n\t\t\t}\n\t\t\tif (startValue && cellDateRange < new Date(String(startValue))) return false\n\t\t\tif (endValue && cellDateRange > new Date(String(endValue))) return false\n\n\t\t\treturn true\n\t\t}\n\n\t\tdefault:\n\t\t\treturn true\n\t}\n}\n\n/**\n * Compute the CSS indentation for a tree-table cell. Pure helper (captures no store state);\n * imported directly by cell components rather than exposed on the store's public return.\n * @internal\n */\nexport function getIndent(colIndex: number, indentLevel?: number): string {\n\tif (indentLevel && colIndex === 0 && indentLevel > 0) {\n\t\treturn `${indentLevel}ch`\n\t} else {\n\t\treturn 'inherit'\n\t}\n}\n\n/**\n * Create a table store\n * @param initData - Initial data for the table store\n * @returns table store instance\n * @public\n */\nexport const createTableStore = (initData: {\n\tcolumns: TableColumn[]\n\trows: TableRow[]\n\tid?: string\n\tconfig?: TableConfig\n\tmodal?: TableModal\n\tlinkResolver?: ((doctype: string, id: string) => Promise<string | undefined>) | null\n}) => {\n\tconst id = initData.id || generateHash()\n\tconst linkResolver = initData.linkResolver ?? null\n\tconst createStore = defineStore(`table-${id}`, () => {\n\t\tconst createDisplayObject = () => {\n\t\t\tconst defaultDisplay: TableDisplay[] = [Object.assign({}, { rowModified: false })]\n\n\t\t\t// TODO: (typing) is this type correct for the parent set?\n\t\t\tconst parents = new Set<string | number>()\n\t\t\tfor (let rowIndex = 0; rowIndex < rows.value.length; rowIndex++) {\n\t\t\t\tconst row = rows.value[rowIndex]\n\t\t\t\tif (row.parent !== null && row.parent !== undefined) {\n\t\t\t\t\tparents.add(row.parent)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Helper function to check if a row has gantt data\n\t\t\tconst hasGanttData = (rowIndex: number): boolean => {\n\t\t\t\treturn rows.value[rowIndex]?.gantt !== undefined\n\t\t\t}\n\n\t\t\t// Helper function to check if any descendant has gantt data\n\t\t\tconst hasGanttDescendant = (rowIndex: number): boolean => {\n\t\t\t\tfor (let i = 0; i < rows.value.length; i++) {\n\t\t\t\t\tif (rows.value[i].parent === rowIndex) {\n\t\t\t\t\t\tif (hasGanttData(i) || hasGanttDescendant(i)) {\n\t\t\t\t\t\t\treturn true\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\t// Helper function to determine if children should be open based on expansion mode\n\t\t\tconst shouldChildrenBeOpen = (rowIndex: number): boolean => {\n\t\t\t\tconst currentConfig = config.value\n\t\t\t\tconst expansionMode =\n\t\t\t\t\tcurrentConfig.view === 'tree' || currentConfig.view === 'tree-gantt'\n\t\t\t\t\t\t? currentConfig.defaultTreeExpansion\n\t\t\t\t\t\t: undefined\n\n\t\t\t\tif (!expansionMode) return true // Default behavior - start expanded (leaf mode)\n\n\t\t\t\tswitch (expansionMode) {\n\t\t\t\t\tcase 'root':\n\t\t\t\t\t\treturn false // Only root nodes are visible, all children start collapsed\n\t\t\t\t\tcase 'branch':\n\t\t\t\t\t\t// Only expand if this node leads to gantt nodes OR if this node itself has gantt data AND has gantt children\n\t\t\t\t\t\treturn hasGanttDescendant(rowIndex)\n\t\t\t\t\tcase 'leaf':\n\t\t\t\t\t\treturn true // All nodes should be expanded\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn true // Default to expanded if unknown mode\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (let rowIndex = 0; rowIndex < rows.value.length; rowIndex++) {\n\t\t\t\tconst row = rows.value[rowIndex]\n\t\t\t\tconst isRootNode = row.parent === null || row.parent === undefined\n\t\t\t\tconst isParentNode = parents.has(rowIndex)\n\n\t\t\t\tdefaultDisplay[rowIndex] = {\n\t\t\t\t\tchildrenOpen: shouldChildrenBeOpen(rowIndex),\n\t\t\t\t\texpanded: false,\n\t\t\t\t\tindent: row.indent || 0,\n\t\t\t\t\tisParent: isParentNode,\n\t\t\t\t\tisRoot: isRootNode,\n\t\t\t\t\trowModified: false,\n\t\t\t\t\topen: isRootNode, // This will be recalculated later for non-root nodes\n\t\t\t\t\tparent: row.parent,\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn defaultDisplay\n\t\t}\n\n\t\t// state\n\t\tconst columns = ref(initData.columns)\n\t\tconst rows = ref(initData.rows)\n\t\tconst config = ref<TableConfig>(initData.config || {})\n\n\t\t// Track row modifications and expand states separately from the computed display\n\t\tconst rowModifications = ref<Record<number, boolean>>({})\n\t\tconst rowExpandStates = ref<Record<number, { childrenOpen?: boolean; expanded?: boolean }>>({})\n\n\t\tconst table = computed(() => {\n\t\t\tconst tableData: Record<string, any> = {}\n\t\t\tfor (const [colIndex, column] of columns.value.entries()) {\n\t\t\t\tfor (const [rowIndex, row] of rows.value.entries()) {\n\t\t\t\t\ttableData[`${colIndex}:${rowIndex}`] = row[column.name]\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn tableData\n\t\t})\n\n\t\tconst display = computed({\n\t\t\tget: () => {\n\t\t\t\tconst baseDisplay = createDisplayObject()\n\n\t\t\t\t// Apply persistent modifications and expand states\n\t\t\t\tfor (let i = 0; i < baseDisplay.length; i++) {\n\t\t\t\t\tif (rowModifications.value[i]) {\n\t\t\t\t\t\tbaseDisplay[i].rowModified = rowModifications.value[i]\n\t\t\t\t\t}\n\t\t\t\t\tif (rowExpandStates.value[i]) {\n\t\t\t\t\t\tif (rowExpandStates.value[i].childrenOpen !== undefined) {\n\t\t\t\t\t\t\tbaseDisplay[i].childrenOpen = rowExpandStates.value[i].childrenOpen!\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (rowExpandStates.value[i].expanded !== undefined) {\n\t\t\t\t\t\t\tbaseDisplay[i].expanded = rowExpandStates.value[i].expanded!\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Calculate 'open' property for tree view based on parent's childrenOpen state\n\t\t\t\tif (isTreeView.value) {\n\t\t\t\t\t// Helper function to check if all ancestors are open\n\n\t\t\t\t\tfor (let i = 0; i < baseDisplay.length; i++) {\n\t\t\t\t\t\tconst row = baseDisplay[i]\n\t\t\t\t\t\tif (!row.isRoot) {\n\t\t\t\t\t\t\tbaseDisplay[i].open = isNodeOpen(i, baseDisplay)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn baseDisplay\n\t\t\t},\n\t\t\tset: (newDisplay: TableDisplay[]) => {\n\t\t\t\t// Only update if the new display is different from the current one; also avoids recursive updates\n\t\t\t\tif (JSON.stringify(newDisplay) !== JSON.stringify(display.value)) {\n\t\t\t\t\tdisplay.value = newDisplay\n\t\t\t\t}\n\t\t\t},\n\t\t})\n\n\t\tconst modal = ref<TableModal>(initData.modal || { visible: false })\n\t\tconst updates = ref<Record<string, string>>({})\n\t\tconst ganttBars = ref<GanttBarInfo[]>([])\n\t\tconst connectionHandles = ref<ConnectionHandle[]>([])\n\t\tconst connectionPaths = ref<ConnectionPath[]>([])\n\t\tconst sortState = ref<{ column: number | null; direction: 'asc' | 'desc' | null }>({\n\t\t\tcolumn: null,\n\t\t\tdirection: null,\n\t\t})\n\t\tconst filterState = ref<FilterStateRecord>({})\n\n\t\t// getters\n\t\tconst hasPinnedColumns = computed(() => columns.value.some(col => col.pinned))\n\t\tconst isGanttView = computed(() => config.value.view === 'gantt' || config.value.view === 'tree-gantt')\n\t\tconst isTreeView = computed(() => config.value.view === 'tree' || config.value.view === 'tree-gantt')\n\t\tconst isDependencyGraphEnabled = computed(() => {\n\t\t\tconst currentConfig = config.value\n\t\t\treturn currentConfig.view === 'gantt' || currentConfig.view === 'tree-gantt'\n\t\t\t\t? currentConfig.dependencyGraph !== false\n\t\t\t\t: true\n\t\t})\n\n\t\tconst numberedRowWidth = computed(() => {\n\t\t\tconst indent = Math.ceil(rows.value.length / 100 + 1)\n\t\t\treturn `${indent}ch`\n\t\t})\n\n\t\tconst zeroColumn = computed(() =>\n\t\t\tconfig.value.view ? ['list', 'tree', 'tree-gantt', 'list-expansion'].includes(config.value.view) : false\n\t\t)\n\n\t\tconst filteredRows = computed(() => {\n\t\t\tlet filtered: Array<TableRow & { originalIndex: number }> = rows.value.map((row, originalIndex) => ({\n\t\t\t\t...row,\n\t\t\t\toriginalIndex,\n\t\t\t}))\n\n\t\t\t// Apply filters\n\t\t\tObject.entries(filterState.value).forEach(([colIndexStr, filter]) => {\n\t\t\t\tconst colIndex = parseInt(colIndexStr)\n\t\t\t\tconst column = columns.value[colIndex]\n\n\t\t\t\tif (!column) return\n\n\t\t\t\t// Skip if filter has no value (except for dateRange and checkbox which can have different value structures)\n\t\t\t\tconst hasFilterValue =\n\t\t\t\t\tfilter.value ||\n\t\t\t\t\tfilter.startValue ||\n\t\t\t\t\tfilter.endValue ||\n\t\t\t\t\t(resolveFilterType(column) === 'checkbox' && filter.value !== undefined)\n\n\t\t\t\tif (!hasFilterValue) return\n\n\t\t\t\tfiltered = filtered.filter(row => {\n\t\t\t\t\tconst cellValue = row[column.name]\n\t\t\t\t\treturn applyFilter(cellValue, filter, column)\n\t\t\t\t})\n\t\t\t})\n\n\t\t\t// Apply sorting if active\n\t\t\tif (sortState.value.column !== null && sortState.value.direction) {\n\t\t\t\tconst column = columns.value[sortState.value.column]\n\t\t\t\tconst direction = sortState.value.direction\n\n\t\t\t\tfiltered.sort((a, b) => {\n\t\t\t\t\tlet aVal = a[column.name]\n\t\t\t\t\tlet bVal = b[column.name]\n\n\t\t\t\t\tif (aVal === null || aVal === undefined) aVal = ''\n\t\t\t\t\tif (bVal === null || bVal === undefined) bVal = ''\n\n\t\t\t\t\tconst aNum = toComparableNumber(aVal)\n\t\t\t\t\tconst bNum = toComparableNumber(bVal)\n\t\t\t\t\tconst isNumeric = !isNaN(aNum) && !isNaN(bNum) && aVal !== '' && bVal !== ''\n\n\t\t\t\t\tif (isNumeric) {\n\t\t\t\t\t\treturn direction === 'asc' ? aNum - bNum : bNum - aNum\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst aStr = String(aVal).toLowerCase()\n\t\t\t\t\t\tconst bStr = String(bVal).toLowerCase()\n\t\t\t\t\t\treturn direction === 'asc' ? aStr.localeCompare(bStr) : bStr.localeCompare(aStr)\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t}\n\n\t\t\treturn filtered\n\t\t})\n\n\t\t// actions\n\t\tconst getCellData = (colIndex: number, rowIndex: number): any => table.value[`${colIndex}:${rowIndex}`]\n\t\tconst setCellData = (colIndex: number, rowIndex: number, value: any) => {\n\t\t\tconst index = `${colIndex}:${rowIndex}`\n\t\t\tconst col = columns.value[colIndex]\n\n\t\t\tif (table.value[index] !== value) {\n\t\t\t\trowModifications.value[rowIndex] = true\n\t\t\t}\n\n\t\t\ttable.value[index] = value\n\t\t\t// Create a new row object to ensure reactivity\n\t\t\trows.value[rowIndex] = {\n\t\t\t\t...rows.value[rowIndex],\n\t\t\t\t[col.name]: value,\n\t\t\t}\n\t\t}\n\n\t\tconst updateRows = (newRows: TableRow[]) => {\n\t\t\trows.value = newRows\n\t\t}\n\n\t\tconst setCellText = (colIndex: number, rowIndex: number, value: string) => {\n\t\t\tconst index = `${colIndex}:${rowIndex}`\n\n\t\t\tif (table.value[index] !== value) {\n\t\t\t\trowModifications.value[rowIndex] = true\n\t\t\t\tupdates.value[index] = value\n\t\t\t}\n\t\t}\n\n\t\tconst getHeaderCellStyle = (column: TableColumn): CSSProperties => {\n\t\t\tconst isLastCol = columns.value.indexOf(column) === columns.value.length - 1\n\n\t\t\t// if the table is full width, the last column should not be resizable;\n\t\t\t// ref: https://github.com/agritheory/stonecrop/pull/196#issuecomment-2503762641\n\n\t\t\tconst isResizable = config.value.fullWidth ? column.resizable && !isLastCol : column.resizable\n\n\t\t\treturn {\n\t\t\t\twidth: column.width || '40ch',\n\t\t\t\ttextAlign: column.align || 'center',\n\t\t\t\t...(isResizable && {\n\t\t\t\t\tresize: 'horizontal',\n\t\t\t\t\toverflow: 'hidden',\n\t\t\t\t\twhiteSpace: 'nowrap',\n\t\t\t\t}),\n\t\t\t}\n\t\t}\n\n\t\tconst resizeColumn = (colIndex: number, newWidth: number) => {\n\t\t\tif (colIndex < 0 || colIndex >= columns.value.length) return\n\n\t\t\tconst minWidth = 40\n\t\t\tconst finalWidth = Math.max(newWidth, minWidth)\n\n\t\t\tcolumns.value[colIndex] = {\n\t\t\t\t...columns.value[colIndex],\n\t\t\t\twidth: `${finalWidth}px`,\n\t\t\t}\n\t\t}\n\n\t\tconst isRowGantt = (rowIndex: number) => {\n\t\t\tconst row = rows.value[rowIndex]\n\t\t\treturn isGanttView.value && row.gantt !== undefined\n\t\t}\n\n\t\tconst isRowVisible = (rowIndex: number) => {\n\t\t\treturn !isTreeView.value || display.value[rowIndex].isRoot || display.value[rowIndex].open\n\t\t}\n\n\t\tconst getRowExpandSymbol = (rowIndex: number) => {\n\t\t\tif (!isTreeView.value && config.value.view !== 'list-expansion') {\n\t\t\t\treturn ''\n\t\t\t}\n\n\t\t\tif (isTreeView.value && (display.value[rowIndex].isRoot || display.value[rowIndex].isParent)) {\n\t\t\t\treturn display.value[rowIndex].childrenOpen ? '▼' : '►'\n\t\t\t}\n\n\t\t\tif (config.value.view === 'list-expansion') {\n\t\t\t\treturn display.value[rowIndex].expanded ? '▼' : '►'\n\t\t\t}\n\n\t\t\treturn ''\n\t\t}\n\n\t\tconst toggleRowExpand = (rowIndex: number) => {\n\t\t\tif (isTreeView.value) {\n\t\t\t\tconst currentState = rowExpandStates.value[rowIndex] || {}\n\t\t\t\tconst currentChildrenOpen = currentState.childrenOpen ?? display.value[rowIndex].childrenOpen\n\t\t\t\tconst newChildrenOpen = !currentChildrenOpen\n\n\t\t\t\trowExpandStates.value[rowIndex] = {\n\t\t\t\t\t...currentState,\n\t\t\t\t\tchildrenOpen: newChildrenOpen,\n\t\t\t\t}\n\n\t\t\t\t// If we're closing, recursively close all descendant nodes\n\t\t\t\tif (!newChildrenOpen) {\n\t\t\t\t\tcloseDescendants(rowIndex)\n\t\t\t\t}\n\t\t\t} else if (config.value.view === 'list-expansion') {\n\t\t\t\tconst currentState = rowExpandStates.value[rowIndex] || {}\n\t\t\t\tconst currentExpanded = currentState.expanded ?? display.value[rowIndex].expanded\n\t\t\t\trowExpandStates.value[rowIndex] = {\n\t\t\t\t\t...currentState,\n\t\t\t\t\texpanded: !currentExpanded,\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst closeDescendants = (parentRowIndex: number) => {\n\t\t\tfor (let index = 0; index < rows.value.length; index++) {\n\t\t\t\tif (display.value[index].parent === parentRowIndex) {\n\t\t\t\t\tconst childState = rowExpandStates.value[index] || {}\n\t\t\t\t\trowExpandStates.value[index] = {\n\t\t\t\t\t\t...childState,\n\t\t\t\t\t\tchildrenOpen: false,\n\t\t\t\t\t}\n\t\t\t\t\t// Recursively close this child's descendants\n\t\t\t\t\tcloseDescendants(index)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst getCellDisplayValue = (colIndex: number, rowIndex: number) => {\n\t\t\tconst cellData = getCellData(colIndex, rowIndex)\n\t\t\treturn getFormattedValue(colIndex, rowIndex, cellData)\n\t\t}\n\n\t\tconst getFormattedValue = (colIndex: number, rowIndex: number, value: any) => {\n\t\t\tconst column = columns.value[colIndex]\n\t\t\tconst row = rows.value[rowIndex]\n\t\t\tconst format = column.format\n\n\t\t\tif (!format) {\n\t\t\t\t// Default cell formatting comes from the component's category; anything without an\n\t\t\t\t// opinion (including an unknown component) renders the raw value.\n\t\t\t\tconst category = componentCategory(column.component)\n\t\t\t\tif (category === 'boolean') return value ? '✓' : '✗'\n\t\t\t\tif (category === 'date') return value != null ? new Date(String(value)).toLocaleDateString() : value\n\t\t\t\tif (category === 'datetime') return value != null ? new Date(String(value)).toLocaleString() : value\n\t\t\t\tif (category === 'quantity') return formatQuantity(value)\n\t\t\t\tif (category === 'currency') return formatCurrency(value)\n\t\t\t\treturn value\n\t\t\t}\n\n\t\t\tif (typeof format === 'function') {\n\t\t\t\treturn format(value, { table: table.value, row, column })\n\t\t\t} else if (typeof format === 'string') {\n\t\t\t\t// parse format function from string. The alias keeps the declaration on one line so the\n\t\t\t\t// disable directive below stays attached to the Function call it covers.\n\t\t\t\ttype DeserializedFormat = (value: any, context?: CellContext) => string | BadgeDescriptor\n\t\t\t\t// oxlint-disable-next-line @typescript-eslint/no-implied-eval\n\t\t\t\tconst formatFn: DeserializedFormat = Function(`\"use strict\";return (${format})`)()\n\t\t\t\treturn formatFn(value, { table: table.value, row, column })\n\t\t\t}\n\n\t\t\treturn value\n\t\t}\n\n\t\tconst closeModal = (event: MouseEvent) => {\n\t\t\tif (!(event.target instanceof Node)) {\n\t\t\t\t// if the target is not a node, it's probably a custom click event to Document or Window\n\t\t\t\t// err on the side of closing the modal in that case\n\t\t\t\tif (modal.value.visible) modal.value.visible = false\n\t\t\t} else if (!modal.value.parent?.contains(event.target)) {\n\t\t\t\tif (modal.value.visible) modal.value.visible = false\n\t\t\t}\n\t\t}\n\n\t\tconst updateGanttBar = (event: GanttDragEvent) => {\n\t\t\t// update the local gantt bar cache\n\t\t\tconst ganttBar = rows.value[event.rowIndex]?.gantt\n\t\t\tif (ganttBar) {\n\t\t\t\tif (event.type === 'resize') {\n\t\t\t\t\tif (event.edge === 'start') {\n\t\t\t\t\t\tganttBar.startIndex = event.newStart\n\t\t\t\t\t\tganttBar.endIndex = event.end\n\t\t\t\t\t\tganttBar.colspan = ganttBar.endIndex - ganttBar.startIndex\n\t\t\t\t\t} else if (event.edge === 'end') {\n\t\t\t\t\t\tganttBar.startIndex = event.start\n\t\t\t\t\t\tganttBar.endIndex = event.newEnd\n\t\t\t\t\t\tganttBar.colspan = ganttBar.endIndex - ganttBar.startIndex\n\t\t\t\t\t}\n\t\t\t\t} else if (event.type === 'bar') {\n\t\t\t\t\tganttBar.startIndex = event.newStart\n\t\t\t\t\tganttBar.endIndex = event.newEnd\n\t\t\t\t\tganttBar.colspan = ganttBar.endIndex - ganttBar.startIndex\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst registerGanttBar = (barInfo: GanttBarInfo) => {\n\t\t\tconst existingIndex = ganttBars.value.findIndex(bar => bar.id === barInfo.id)\n\t\t\tif (existingIndex >= 0) {\n\t\t\t\t// @ts-expect-error TODO: for some reason, the IDE is expecting an unref'd value\n\t\t\t\tganttBars.value[existingIndex] = barInfo\n\t\t\t} else {\n\t\t\t\t// @ts-expect-error TODO: for some reason, the IDE is expecting an unref'd value\n\t\t\t\tganttBars.value.push(barInfo)\n\t\t\t}\n\t\t}\n\n\t\tconst unregisterGanttBar = (barId: string) => {\n\t\t\tconst index = ganttBars.value.findIndex(bar => bar.id === barId)\n\t\t\tif (index >= 0) {\n\t\t\t\tganttBars.value.splice(index, 1)\n\t\t\t}\n\t\t}\n\n\t\tconst registerConnectionHandle = (handleInfo: ConnectionHandle) => {\n\t\t\tconst existingIndex = connectionHandles.value.findIndex(handle => handle.id === handleInfo.id)\n\t\t\tif (existingIndex >= 0) {\n\t\t\t\t// @ts-expect-error TODO: for some reason, the IDE is expecting an unref'd value\n\t\t\t\tconnectionHandles.value[existingIndex] = handleInfo\n\t\t\t} else {\n\t\t\t\t// @ts-expect-error TODO: for some reason, the IDE is expecting an unref'd value\n\t\t\t\tconnectionHandles.value.push(handleInfo)\n\t\t\t}\n\t\t}\n\n\t\tconst unregisterConnectionHandle = (handleId: string) => {\n\t\t\tconst index = connectionHandles.value.findIndex(handle => handle.id === handleId)\n\t\t\tif (index >= 0) {\n\t\t\t\tconnectionHandles.value.splice(index, 1)\n\t\t\t}\n\t\t}\n\n\t\tconst createConnection = (\n\t\t\tfromHandleId: string,\n\t\t\ttoHandleId: string,\n\t\t\toptions?: { style?: ConnectionPath['style']; label?: string }\n\t\t) => {\n\t\t\tconst fromHandle = connectionHandles.value.find(h => h.id === fromHandleId)\n\t\t\tconst toHandle = connectionHandles.value.find(h => h.id === toHandleId)\n\n\t\t\tif (!fromHandle || !toHandle) {\n\t\t\t\tconsole.warn('Cannot create connection: handle not found')\n\t\t\t\treturn null\n\t\t\t}\n\n\t\t\tconst connection: ConnectionPath = {\n\t\t\t\tid: `connection-${fromHandleId}-${toHandleId}`,\n\t\t\t\tfrom: {\n\t\t\t\t\tbarId: fromHandle.barId,\n\t\t\t\t\tside: fromHandle.side,\n\t\t\t\t},\n\t\t\t\tto: {\n\t\t\t\t\tbarId: toHandle.barId,\n\t\t\t\t\tside: toHandle.side,\n\t\t\t\t},\n\t\t\t\tstyle: options?.style,\n\t\t\t\tlabel: options?.label,\n\t\t\t}\n\n\t\t\tconnectionPaths.value.push(connection)\n\t\t\treturn connection\n\t\t}\n\n\t\tconst deleteConnection = (connectionId: string) => {\n\t\t\tconst index = connectionPaths.value.findIndex(conn => conn.id === connectionId)\n\t\t\tif (index >= 0) {\n\t\t\t\tconnectionPaths.value.splice(index, 1)\n\t\t\t\treturn true\n\t\t\t}\n\t\t\treturn false\n\t\t}\n\n\t\tconst getConnectionsForBar = (barId: string) => {\n\t\t\treturn connectionPaths.value.filter(conn => conn.from.barId === barId || conn.to.barId === barId)\n\t\t}\n\n\t\tconst getHandlesForBar = (barId: string) => {\n\t\t\treturn connectionHandles.value.filter(handle => handle.barId === barId)\n\t\t}\n\n\t\tconst sortByColumn = (colIndex: number) => {\n\t\t\tconst column = columns.value[colIndex]\n\t\t\tif (column.sortable === false) return\n\n\t\t\tlet newDirection: 'asc' | 'desc'\n\t\t\tif (sortState.value.column === colIndex) {\n\t\t\t\tif (sortState.value.direction === 'asc') {\n\t\t\t\t\tnewDirection = 'desc'\n\t\t\t\t} else {\n\t\t\t\t\tnewDirection = 'asc'\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tnewDirection = 'asc'\n\t\t\t}\n\n\t\t\tsortState.value.column = colIndex\n\t\t\tsortState.value.direction = newDirection\n\n\t\t\t// Note: The actual sorting is now handled in the filteredRows computed property\n\t\t\t// This ensures that sorting works on filtered data without modifying the original rows\n\t\t}\n\n\t\tconst setFilter = (colIndex: number, filter: FilterState) => {\n\t\t\tif (!filter.value && !filter.startValue && !filter.endValue) {\n\t\t\t\t// Remove filter if empty\n\t\t\t\tdelete filterState.value[colIndex]\n\t\t\t} else {\n\t\t\t\tfilterState.value[colIndex] = filter\n\t\t\t}\n\t\t}\n\n\t\tconst clearFilter = (colIndex: number) => {\n\t\t\tdelete filterState.value[colIndex]\n\t\t}\n\n\t\t// Row action methods\n\n\t\t/**\n\t\t * Add a new row to the table.\n\t\t * @param rowData - Optional partial row data to initialize the new row with\n\t\t * @param position - Where to insert the row: 'start', 'end', or a specific index\n\t\t * @returns The index of the newly added row\n\t\t */\n\t\tconst addRow = (rowData?: Partial<TableRow>, position: 'start' | 'end' | number = 'end'): number => {\n\t\t\t// Create a new row with default empty values for each column\n\t\t\tconst newRow: TableRow = {}\n\t\t\tfor (const column of columns.value) {\n\t\t\t\tnewRow[column.name] = ''\n\t\t\t}\n\n\t\t\t// Merge in any provided row data\n\t\t\tif (rowData) {\n\t\t\t\tObject.assign(newRow, rowData)\n\t\t\t}\n\n\t\t\tlet insertIndex: number\n\t\t\tif (position === 'start') {\n\t\t\t\tinsertIndex = 0\n\t\t\t\trows.value.unshift(newRow)\n\t\t\t} else if (position === 'end') {\n\t\t\t\tinsertIndex = rows.value.length\n\t\t\t\trows.value.push(newRow)\n\t\t\t} else {\n\t\t\t\tinsertIndex = Math.max(0, Math.min(position, rows.value.length))\n\t\t\t\trows.value.splice(insertIndex, 0, newRow)\n\t\t\t}\n\n\t\t\treturn insertIndex\n\t\t}\n\n\t\t/**\n\t\t * Delete a row from the table.\n\t\t * @param rowIndex - The index of the row to delete\n\t\t * @returns The deleted row, or null if the index was invalid\n\t\t */\n\t\tconst deleteRow = (rowIndex: number): TableRow | null => {\n\t\t\tif (rowIndex < 0 || rowIndex >= rows.value.length) {\n\t\t\t\treturn null\n\t\t\t}\n\n\t\t\tconst [deletedRow] = rows.value.splice(rowIndex, 1)\n\n\t\t\t// Clean up row modifications tracking for the deleted row\n\t\t\tdelete rowModifications.value[rowIndex]\n\t\t\tdelete rowExpandStates.value[rowIndex]\n\n\t\t\t// Shift modification/expand state indices for rows after the deleted one\n\t\t\tconst newModifications: Record<number, boolean> = {}\n\t\t\tconst newExpandStates: Record<number, { childrenOpen?: boolean; expanded?: boolean }> = {}\n\n\t\t\tfor (const [key, value] of Object.entries(rowModifications.value)) {\n\t\t\t\tconst idx = parseInt(key)\n\t\t\t\tif (idx > rowIndex) {\n\t\t\t\t\tnewModifications[idx - 1] = value\n\t\t\t\t} else {\n\t\t\t\t\tnewModifications[idx] = value\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (const [key, value] of Object.entries(rowExpandStates.value)) {\n\t\t\t\tconst idx = parseInt(key)\n\t\t\t\tif (idx > rowIndex) {\n\t\t\t\t\tnewExpandStates[idx - 1] = value\n\t\t\t\t} else {\n\t\t\t\t\tnewExpandStates[idx] = value\n\t\t\t\t}\n\t\t\t}\n\n\t\t\trowModifications.value = newModifications\n\t\t\trowExpandStates.value = newExpandStates\n\n\t\t\treturn deletedRow\n\t\t}\n\n\t\t/**\n\t\t * Duplicate a row in the table.\n\t\t * @param rowIndex - The index of the row to duplicate\n\t\t * @returns The index of the new duplicated row, or -1 if the index was invalid\n\t\t */\n\t\tconst duplicateRow = (rowIndex: number): number => {\n\t\t\tif (rowIndex < 0 || rowIndex >= rows.value.length) {\n\t\t\t\treturn -1\n\t\t\t}\n\n\t\t\t// Deep clone the row data\n\t\t\tconst originalRow = rows.value[rowIndex]\n\t\t\tconst duplicatedRow: TableRow = JSON.parse(JSON.stringify(originalRow))\n\n\t\t\t// Insert the duplicated row after the original\n\t\t\tconst newIndex = rowIndex + 1\n\t\t\trows.value.splice(newIndex, 0, duplicatedRow)\n\n\t\t\treturn newIndex\n\t\t}\n\n\t\t/**\n\t\t * Insert a new row above the specified row.\n\t\t * @param rowIndex - The index of the row to insert above\n\t\t * @param rowData - Optional partial row data to initialize the new row with\n\t\t * @returns The index of the newly inserted row\n\t\t */\n\t\tconst insertRowAbove = (rowIndex: number, rowData?: Partial<TableRow>): number => {\n\t\t\tconst insertIndex = Math.max(0, rowIndex)\n\t\t\treturn addRow(rowData, insertIndex)\n\t\t}\n\n\t\t/**\n\t\t * Insert a new row below the specified row.\n\t\t * @param rowIndex - The index of the row to insert below\n\t\t * @param rowData - Optional partial row data to initialize the new row with\n\t\t * @returns The index of the newly inserted row\n\t\t */\n\t\tconst insertRowBelow = (rowIndex: number, rowData?: Partial<TableRow>): number => {\n\t\t\tconst insertIndex = Math.min(rowIndex + 1, rows.value.length)\n\t\t\treturn addRow(rowData, insertIndex)\n\t\t}\n\n\t\t/**\n\t\t * Move a row from one position to another.\n\t\t * @param fromIndex - The current index of the row to move\n\t\t * @param toIndex - The target index to move the row to\n\t\t * @returns true if the move was successful, false otherwise\n\t\t */\n\t\tconst moveRow = (fromIndex: number, toIndex: number): boolean => {\n\t\t\t// Validate indices\n\t\t\tif (\n\t\t\t\tfromIndex < 0 ||\n\t\t\t\tfromIndex >= rows.value.length ||\n\t\t\t\ttoIndex < 0 ||\n\t\t\t\ttoIndex >= rows.value.length ||\n\t\t\t\tfromIndex === toIndex\n\t\t\t) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\t// Remove the row from its current position\n\t\t\tconst [movedRow] = rows.value.splice(fromIndex, 1)\n\n\t\t\t// Insert at the new position\n\t\t\trows.value.splice(toIndex, 0, movedRow)\n\n\t\t\t// Update row modification and expand state indices\n\t\t\tconst newModifications: Record<number, boolean> = {}\n\t\t\tconst newExpandStates: Record<number, { childrenOpen?: boolean; expanded?: boolean }> = {}\n\n\t\t\tfor (const [key, value] of Object.entries(rowModifications.value)) {\n\t\t\t\tconst idx = parseInt(key)\n\t\t\t\tlet newIdx = idx\n\n\t\t\t\tif (idx === fromIndex) {\n\t\t\t\t\t// The moved row\n\t\t\t\t\tnewIdx = toIndex\n\t\t\t\t} else if (fromIndex < toIndex) {\n\t\t\t\t\t// Moving down: rows between fromIndex and toIndex shift up\n\t\t\t\t\tif (idx > fromIndex && idx <= toIndex) {\n\t\t\t\t\t\tnewIdx = idx - 1\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Moving up: rows between toIndex and fromIndex shift down\n\t\t\t\t\tif (idx >= toIndex && idx < fromIndex) {\n\t\t\t\t\t\tnewIdx = idx + 1\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tnewModifications[newIdx] = value\n\t\t\t}\n\n\t\t\tfor (const [key, value] of Object.entries(rowExpandStates.value)) {\n\t\t\t\tconst idx = parseInt(key)\n\t\t\t\tlet newIdx = idx\n\n\t\t\t\tif (idx === fromIndex) {\n\t\t\t\t\tnewIdx = toIndex\n\t\t\t\t} else if (fromIndex < toIndex) {\n\t\t\t\t\tif (idx > fromIndex && idx <= toIndex) {\n\t\t\t\t\t\tnewIdx = idx - 1\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif (idx >= toIndex && idx < fromIndex) {\n\t\t\t\t\t\tnewIdx = idx + 1\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tnewExpandStates[newIdx] = value\n\t\t\t}\n\n\t\t\trowModifications.value = newModifications\n\t\t\trowExpandStates.value = newExpandStates\n\n\t\t\treturn true\n\t\t}\n\n\t\treturn {\n\t\t\t// state\n\t\t\tcolumns,\n\t\t\tconfig,\n\t\t\tconnectionHandles,\n\t\t\tconnectionPaths,\n\t\t\tdisplay,\n\t\t\tfilterState,\n\t\t\tganttBars,\n\t\t\tmodal,\n\t\t\trows,\n\t\t\tsortState,\n\t\t\ttable,\n\t\t\tupdates,\n\n\t\t\t// getters\n\t\t\tfilteredRows,\n\t\t\thasPinnedColumns,\n\t\t\tisGanttView,\n\t\t\tisTreeView,\n\t\t\tisDependencyGraphEnabled,\n\t\t\tnumberedRowWidth,\n\t\t\tzeroColumn,\n\n\t\t\t// resolver\n\t\t\tlinkResolver,\n\n\t\t\t// actions\n\t\t\taddRow,\n\t\t\tclearFilter,\n\t\t\tcloseModal,\n\t\t\tcreateConnection,\n\t\t\tdeleteConnection,\n\t\t\tdeleteRow,\n\t\t\tduplicateRow,\n\t\t\tgetCellData,\n\t\t\tgetCellDisplayValue,\n\t\t\tgetConnectionsForBar,\n\t\t\tgetFormattedValue,\n\t\t\tgetHandlesForBar,\n\t\t\tgetHeaderCellStyle,\n\t\t\tgetRowExpandSymbol,\n\t\t\tinsertRowAbove,\n\t\t\tinsertRowBelow,\n\t\t\tisRowGantt,\n\t\t\tisRowVisible,\n\t\t\tmoveRow,\n\t\t\tregisterConnectionHandle,\n\t\t\tregisterGanttBar,\n\t\t\tresizeColumn,\n\t\t\tsetCellData,\n\t\t\tsetCellText,\n\t\t\tsetFilter,\n\t\t\tsortByColumn,\n\t\t\ttoggleRowExpand,\n\t\t\tunregisterConnectionHandle,\n\t\t\tunregisterGanttBar,\n\t\t\tupdateGanttBar,\n\t\t\tupdateRows,\n\t\t}\n\t})\n\n\treturn createStore()\n}\n","<template>\n\t<td\n\t\tref=\"cell\"\n\t\t:data-colindex=\"colIndex\"\n\t\t:data-rowindex=\"rowIndex\"\n\t\t:data-editable=\"column.edit\"\n\t\t:contenteditable=\"isContentEditable\"\n\t\t:tabindex=\"tabIndex\"\n\t\t:spellcheck=\"false\"\n\t\t:style=\"cellStyle\"\n\t\tclass=\"atable-cell\"\n\t\t:class=\"cellClasses\"\n\t\t@focus=\"onFocus\"\n\t\t@paste=\"updateCellData\"\n\t\t@input=\"debouncedUpdateCellData\"\n\t\t@click=\"onCellClick\">\n\t\t<component :is=\"column.cellComponent\" v-if=\"column.cellComponent\" v-bind=\"cellComponentBindings\" />\n\t\t<component :is=\"'ABadge'\" v-else-if=\"badgeFromFormat\" v-bind=\"badgeFromFormat\" presentation=\"cell-fill\" />\n\t\t<component :is=\"'ABadge'\" v-else-if=\"badgeFromOptions\" v-bind=\"badgeFromOptions\" />\n\t\t<span v-else-if=\"isHtmlValue\" v-html=\"renderedValue\" />\n\t\t<span v-else>{{ renderedValue }}</span>\n\t</td>\n</template>\n\n<script setup lang=\"ts\">\nimport { KeypressHandlers, defaultKeypressHandlers, useKeyboardNav } from '@stonecrop/utilities'\nimport { isBadgeDescriptor, hasBadgeOptions } from '@stonecrop/schema'\nimport { useDebounceFn, useElementBounding } from '@vueuse/core'\nimport { computed, type CSSProperties, onMounted, ref, useTemplateRef, nextTick } from 'vue'\n\nimport { createTableStore, getIndent } from '../stores/table'\nimport { isHtmlString } from '../utils'\n\nconst {\n\tcolIndex,\n\trowIndex,\n\tstore,\n\taddNavigation = true,\n\ttabIndex = 0,\n\tpinned = false,\n\tdebounce = 300,\n} = defineProps<{\n\tcolIndex: number\n\trowIndex: number\n\tstore: ReturnType<typeof createTableStore>\n\taddNavigation?: boolean | KeypressHandlers\n\ttabIndex?: number\n\tpinned?: boolean\n\tdebounce?: number\n}>()\n\nconst cellRef = useTemplateRef<HTMLTableCellElement>('cell')\n\n// keep a shallow copy of the original cell value for comparison\nconst originalData = store.getCellData(colIndex, rowIndex)\nconst currentData = ref('')\nconst cellModified = ref(false)\n\nconst column = store.columns[colIndex]\nconst row = store.rows[rowIndex]\n\nconst textAlign = column.align || 'center'\nconst cellWidth = column.width || '40ch'\n\nconst displayValue = computed(() => store.getCellDisplayValue(colIndex, rowIndex))\n\n// Resolved display text for Link columns with bare string IDs.\n// null = not yet resolved or not applicable; non-null overrides displayValue.\nconst resolvedText = ref<string | null>(null)\n\nonMounted(() => {\n\tif (!column.linkDoctype) return\n\tconst raw = store.getCellData(colIndex, rowIndex)\n\n\t// Server returns link fields as { id, displayText } objects.\n\tif (raw !== null && raw !== undefined && typeof raw === 'object') {\n\t\tconst obj = raw as Record<string, unknown>\n\t\tconst display = obj.displayText ?? obj.id\n\t\tif (typeof display === 'string' || typeof display === 'number') {\n\t\t\tresolvedText.value = String(display)\n\t\t}\n\t\treturn\n\t}\n\n\t// Bare string ID — call the resolver if available.\n\tconst resolver = store.linkResolver\n\tif (!resolver || typeof raw !== 'string' || raw === '') return\n\tvoid resolver(column.linkDoctype, raw).then(text => {\n\t\tif (text != null) resolvedText.value = text\n\t\treturn text\n\t})\n})\n\nconst renderedValue = computed(() => resolvedText.value ?? displayValue.value)\n\nconst badgeFromFormat = computed(() => {\n\tif (column.cellComponent) return undefined\n\tconst value = renderedValue.value\n\treturn isBadgeDescriptor(value) ? value : undefined\n})\n\nconst badgeFromOptions = computed(() => {\n\tif (column.cellComponent || badgeFromFormat.value) return undefined\n\tif (!hasBadgeOptions(column.options)) return undefined\n\treturn {\n\t\tvalue: store.getCellData(colIndex, rowIndex),\n\t\toptions: column.options,\n\t\tpresentation: 'cell-fill' as const,\n\t}\n})\n\nconst usesBadgeDisplay = computed(\n\t() => !!column.cellComponent || badgeFromFormat.value !== undefined || hasBadgeOptions(column.options)\n)\n\nconst isContentEditable = computed(() => column.edit && !usesBadgeDisplay.value)\n\nconst cellComponentBindings = computed(() => {\n\tconst props = { ...column.cellComponentProps }\n\tif (column.cellComponent !== 'ABadge') {\n\t\treturn { ...props, value: renderedValue.value }\n\t}\n\tif (isBadgeDescriptor(renderedValue.value)) {\n\t\treturn { presentation: 'cell-fill' as const, ...props, ...renderedValue.value }\n\t}\n\t// ABadge resolves its own label, so it needs the badge map as well as the value — and the value\n\t// has to be the stored one, because badge maps are keyed on that rather than on formatted text.\n\treturn {\n\t\tpresentation: 'cell-fill' as const,\n\t\toptions: column.options,\n\t\t...props,\n\t\tvalue: store.getCellData(colIndex, rowIndex),\n\t}\n})\n\nconst isHtmlValue = computed(() => {\n\t// TODO: check if display value is a native DOM element\n\treturn typeof renderedValue.value === 'string' ? isHtmlString(renderedValue.value) : false\n})\n\nconst cellStyle = computed((): CSSProperties => {\n\treturn {\n\t\ttextAlign,\n\t\twidth: cellWidth,\n\t\tfontWeight: !cellModified.value ? 'inherit' : 'bold',\n\t\tpaddingLeft: getIndent(colIndex, store.display[rowIndex]?.indent),\n\t}\n})\n\nconst cellClasses = computed(() => {\n\treturn {\n\t\t'sticky-column': pinned,\n\t\t'cell-modified': cellModified.value,\n\t\t'atable-cell--badge-fill': usesBadgeDisplay.value,\n\t}\n})\n\nconst onCellClick = () => {\n\t// First, select all text if the cell is editable\n\tselectAllText()\n\n\t// Then handle modal display (original showModal behavior)\n\tshowModal()\n}\n\nconst showModal = () => {\n\tconst { left, bottom, width, height } = useElementBounding(cellRef)\n\n\tif (column.mask) {\n\t\t// TODO: add masking to cell values\n\t\t// column.mask(event)\n\t}\n\n\tif (column.modalComponent) {\n\t\tstore.$patch(state => {\n\t\t\tstate.modal.visible = true\n\t\t\tstate.modal.colIndex = colIndex\n\t\t\tstate.modal.rowIndex = rowIndex\n\t\t\t// Snapshot the cell's box as it was when the modal opened. These are refs, and assigning\n\t\t\t// them raw happened to work only because reactive reads unwrap refs — which also left the\n\t\t\t// stored values live, tracking the cell for as long as the modal stayed open.\n\t\t\tstate.modal.left = left.value\n\t\t\tstate.modal.bottom = bottom.value\n\t\t\tstate.modal.width = width.value\n\t\t\tstate.modal.height = height.value\n\t\t\tstate.modal.cell = cellRef.value\n\n\t\t\tif (typeof column.modalComponent === 'function') {\n\t\t\t\t// `table` is a computed, so Pinia exposes it as a getter — it is not on `$state`, which\n\t\t\t\t// is what $patch hands back. Reading it off the store is what passes a real table.\n\t\t\t\tstate.modal.component = column.modalComponent({ table: store.table, row, column })\n\t\t\t} else {\n\t\t\t\tstate.modal.component = column.modalComponent\n\t\t\t}\n\n\t\t\tstate.modal.componentProps = column.modalComponentExtraProps\n\t\t})\n\t}\n}\n\nif (addNavigation) {\n\tlet handlers = {\n\t\t...defaultKeypressHandlers,\n\t\t'keydown.f2': showModal,\n\t\t'keydown.alt.up': showModal,\n\t\t'keydown.alt.down': showModal,\n\t\t'keydown.alt.left': showModal,\n\t\t'keydown.alt.right': showModal,\n\t}\n\n\tif (typeof addNavigation === 'object') {\n\t\thandlers = {\n\t\t\t...handlers,\n\t\t\t...addNavigation,\n\t\t}\n\t}\n\n\tuseKeyboardNav([\n\t\t{\n\t\t\tselectors: cellRef,\n\t\t\thandlers: handlers,\n\t\t},\n\t])\n}\n\n// const updateData = (event: Event) => {\n// \tif (event) {\n// \t\t// custom components need to handle their own updateData, this is the default\n// \t\tif (!column.component) {\n// \t\t\tstore.setCellData(colIndex, rowIndex, cell.value.innerHTML)\n// \t\t}\n// \t\tcellModified.value = true\n// \t}\n// }\n\nconst selectAllText = () => {\n\tif (cellRef.value && column.edit) {\n\t\t// Use the Selection API to select all text content in the contenteditable cell\n\t\tconst selection = window.getSelection()\n\t\tif (selection) {\n\t\t\ttry {\n\t\t\t\tconst range = document.createRange()\n\t\t\t\tif (range.selectNodeContents) {\n\t\t\t\t\trange.selectNodeContents(cellRef.value)\n\t\t\t\t\tselection.removeAllRanges()\n\t\t\t\t\tselection.addRange(range)\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Fallback for environments where Range API is not fully supported\n\t\t\t\t// This is expected in some test environments\n\t\t\t}\n\t\t}\n\t}\n}\n\nconst onFocus = () => {\n\tif (cellRef.value) {\n\t\tcurrentData.value = cellRef.value.textContent!\n\t\t// Select all text when the cell receives focus\n\t\tselectAllText()\n\t}\n}\n\nconst saveCursorPosition = () => {\n\ttry {\n\t\tconst selection = window.getSelection()\n\t\tif (selection && selection.rangeCount > 0 && cellRef.value) {\n\t\t\tconst range = selection.getRangeAt(0)\n\t\t\t// Save the offset from the start of the cell\n\t\t\tconst preCaretRange = range.cloneRange()\n\t\t\tif (preCaretRange.selectNodeContents && preCaretRange.setEnd) {\n\t\t\t\tpreCaretRange.selectNodeContents(cellRef.value)\n\t\t\t\tpreCaretRange.setEnd(range.endContainer, range.endOffset)\n\t\t\t\treturn preCaretRange.toString().length\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// Fallback for environments where Selection API is not fully supported\n\t}\n\treturn 0\n}\n\nconst restoreCursorPosition = (position: number) => {\n\tif (!cellRef.value) return\n\n\ttry {\n\t\tconst selection = window.getSelection()\n\t\tif (!selection) return\n\n\t\tlet charIndex = 0\n\t\tconst walker = document.createTreeWalker\n\t\t\t? document.createTreeWalker(cellRef.value, NodeFilter.SHOW_TEXT, null)\n\t\t\t: null\n\n\t\tif (!walker) return\n\n\t\tlet node: Node | null\n\t\tlet range: Range | null = null\n\n\t\twhile ((node = walker.nextNode())) {\n\t\t\tconst textNode = node as Text\n\t\t\tconst nextCharIndex = charIndex + textNode.textContent.length\n\n\t\t\tif (position <= nextCharIndex) {\n\t\t\t\trange = document.createRange()\n\t\t\t\tif (range.setStart && range.setEnd) {\n\t\t\t\t\trange.setStart(textNode, position - charIndex)\n\t\t\t\t\trange.setEnd(textNode, position - charIndex)\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tcharIndex = nextCharIndex\n\t\t}\n\n\t\tif (range && selection.removeAllRanges && selection.addRange) {\n\t\t\tselection.removeAllRanges()\n\t\t\tselection.addRange(range)\n\t\t}\n\t} catch {\n\t\t// Fallback for environments where DOM APIs are not fully supported\n\t}\n}\n\nconst updateCellData = (payload: Event) => {\n\tif (!column.edit) return\n\n\tconst target = payload.target as HTMLTableCellElement\n\tif (target.textContent === currentData.value) {\n\t\treturn\n\t}\n\n\t// Save cursor position before updating\n\tconst cursorPosition = saveCursorPosition()\n\n\tcurrentData.value = target.textContent!\n\n\t// only apply changes if the cell value has changed after being mounted\n\tif (column.format) {\n\t\tcellModified.value = target.textContent !== store.getFormattedValue(colIndex, rowIndex, originalData)\n\t\t// TODO: need to setup reverse format function?\n\t\tstore.setCellText(colIndex, rowIndex, target.textContent)\n\t} else {\n\t\tcellModified.value = target.textContent !== originalData\n\t\tstore.setCellData(colIndex, rowIndex, target.textContent)\n\t}\n\n\t// Use nextTick to restore cursor position after Vue's reactive updates but before browser repaint\n\tvoid nextTick().then(() => {\n\t\treturn restoreCursorPosition(cursorPosition)\n\t})\n}\n\nconst debouncedUpdateCellData = useDebounceFn(updateCellData, debounce)\n\ndefineExpose({\n\tcurrentData,\n})\n</script>\n\n<style>\n.atable-cell {\n\tbackground-color: inherit;\n\tborder-radius: 0px;\n\tbox-sizing: border-box;\n\tmargin: 0px;\n\toutline: none;\n\tbox-shadow: none;\n\tcolor: var(--sc-cell-text-color);\n\toverflow: hidden;\n\tpadding-left: 0.5ch !important;\n\tpadding-right: 0.5ch;\n\tpadding-top: var(--sc-atable-row-padding);\n\tpadding-bottom: var(--sc-atable-row-padding);\n\tborder-spacing: 0px;\n\tborder-collapse: collapse;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\torder: 1;\n\twhite-space: nowrap;\n\tmax-width: 40ch;\n\tborder-top: 1px solid var(--sc-row-border-color);\n\tmargin-left: 1px;\n}\n.atable-cell a {\n\tcolor: var(--sc-cell-text-color);\n\ttext-decoration: none;\n}\n.atable-cell:focus,\n.atable-cell:focus-within {\n\tbackground-color: var(--sc-focus-cell-background);\n\toutline-width: var(--sc-atable-cell-border-width);\n\toutline-style: solid;\n\toutline-offset: calc(var(--sc-atable-cell-border-width) * -1);\n\toutline-color: var(--sc-focus-cell-outline);\n\tbox-shadow: none;\n\toverflow: hidden;\n\ttext-wrap: nowrap;\n\tbox-sizing: border-box;\n}\n.cell-modified {\n\tfont-weight: bold;\n\tfont-style: italic;\n}\n.cell-modified-highlight {\n\tbackground-color: var(--sc-cell-changed-color);\n}\n.atable-cell--badge-fill {\n\tpadding: 0 !important;\n\tmargin-left: 0;\n}\n</style>\n","<template>\n\t<td\n\t\tref=\"cell\"\n\t\t:data-colindex=\"colIndex\"\n\t\t:data-rowindex=\"rowIndex\"\n\t\t:data-editable=\"column.edit\"\n\t\t:contenteditable=\"isContentEditable\"\n\t\t:tabindex=\"tabIndex\"\n\t\t:spellcheck=\"false\"\n\t\t:style=\"cellStyle\"\n\t\tclass=\"atable-cell\"\n\t\t:class=\"cellClasses\"\n\t\t@focus=\"onFocus\"\n\t\t@paste=\"updateCellData\"\n\t\t@input=\"debouncedUpdateCellData\"\n\t\t@click=\"onCellClick\">\n\t\t<component :is=\"column.cellComponent\" v-if=\"column.cellComponent\" v-bind=\"cellComponentBindings\" />\n\t\t<component :is=\"'ABadge'\" v-else-if=\"badgeFromFormat\" v-bind=\"badgeFromFormat\" presentation=\"cell-fill\" />\n\t\t<component :is=\"'ABadge'\" v-else-if=\"badgeFromOptions\" v-bind=\"badgeFromOptions\" />\n\t\t<span v-else-if=\"isHtmlValue\" v-html=\"renderedValue\" />\n\t\t<span v-else>{{ renderedValue }}</span>\n\t</td>\n</template>\n\n<script setup lang=\"ts\">\nimport { KeypressHandlers, defaultKeypressHandlers, useKeyboardNav } from '@stonecrop/utilities'\nimport { isBadgeDescriptor, hasBadgeOptions } from '@stonecrop/schema'\nimport { useDebounceFn, useElementBounding } from '@vueuse/core'\nimport { computed, type CSSProperties, onMounted, ref, useTemplateRef, nextTick } from 'vue'\n\nimport { createTableStore, getIndent } from '../stores/table'\nimport { isHtmlString } from '../utils'\n\nconst {\n\tcolIndex,\n\trowIndex,\n\tstore,\n\taddNavigation = true,\n\ttabIndex = 0,\n\tpinned = false,\n\tdebounce = 300,\n} = defineProps<{\n\tcolIndex: number\n\trowIndex: number\n\tstore: ReturnType<typeof createTableStore>\n\taddNavigation?: boolean | KeypressHandlers\n\ttabIndex?: number\n\tpinned?: boolean\n\tdebounce?: number\n}>()\n\nconst cellRef = useTemplateRef<HTMLTableCellElement>('cell')\n\n// keep a shallow copy of the original cell value for comparison\nconst originalData = store.getCellData(colIndex, rowIndex)\nconst currentData = ref('')\nconst cellModified = ref(false)\n\nconst column = store.columns[colIndex]\nconst row = store.rows[rowIndex]\n\nconst textAlign = column.align || 'center'\nconst cellWidth = column.width || '40ch'\n\nconst displayValue = computed(() => store.getCellDisplayValue(colIndex, rowIndex))\n\n// Resolved display text for Link columns with bare string IDs.\n// null = not yet resolved or not applicable; non-null overrides displayValue.\nconst resolvedText = ref<string | null>(null)\n\nonMounted(() => {\n\tif (!column.linkDoctype) return\n\tconst raw = store.getCellData(colIndex, rowIndex)\n\n\t// Server returns link fields as { id, displayText } objects.\n\tif (raw !== null && raw !== undefined && typeof raw === 'object') {\n\t\tconst obj = raw as Record<string, unknown>\n\t\tconst display = obj.displayText ?? obj.id\n\t\tif (typeof display === 'string' || typeof display === 'number') {\n\t\t\tresolvedText.value = String(display)\n\t\t}\n\t\treturn\n\t}\n\n\t// Bare string ID — call the resolver if available.\n\tconst resolver = store.linkResolver\n\tif (!resolver || typeof raw !== 'string' || raw === '') return\n\tvoid resolver(column.linkDoctype, raw).then(text => {\n\t\tif (text != null) resolvedText.value = text\n\t\treturn text\n\t})\n})\n\nconst renderedValue = computed(() => resolvedText.value ?? displayValue.value)\n\nconst badgeFromFormat = computed(() => {\n\tif (column.cellComponent) return undefined\n\tconst value = renderedValue.value\n\treturn isBadgeDescriptor(value) ? value : undefined\n})\n\nconst badgeFromOptions = computed(() => {\n\tif (column.cellComponent || badgeFromFormat.value) return undefined\n\tif (!hasBadgeOptions(column.options)) return undefined\n\treturn {\n\t\tvalue: store.getCellData(colIndex, rowIndex),\n\t\toptions: column.options,\n\t\tpresentation: 'cell-fill' as const,\n\t}\n})\n\nconst usesBadgeDisplay = computed(\n\t() => !!column.cellComponent || badgeFromFormat.value !== undefined || hasBadgeOptions(column.options)\n)\n\nconst isContentEditable = computed(() => column.edit && !usesBadgeDisplay.value)\n\nconst cellComponentBindings = computed(() => {\n\tconst props = { ...column.cellComponentProps }\n\tif (column.cellComponent !== 'ABadge') {\n\t\treturn { ...props, value: renderedValue.value }\n\t}\n\tif (isBadgeDescriptor(renderedValue.value)) {\n\t\treturn { presentation: 'cell-fill' as const, ...props, ...renderedValue.value }\n\t}\n\t// ABadge resolves its own label, so it needs the badge map as well as the value — and the value\n\t// has to be the stored one, because badge maps are keyed on that rather than on formatted text.\n\treturn {\n\t\tpresentation: 'cell-fill' as const,\n\t\toptions: column.options,\n\t\t...props,\n\t\tvalue: store.getCellData(colIndex, rowIndex),\n\t}\n})\n\nconst isHtmlValue = computed(() => {\n\t// TODO: check if display value is a native DOM element\n\treturn typeof renderedValue.value === 'string' ? isHtmlString(renderedValue.value) : false\n})\n\nconst cellStyle = computed((): CSSProperties => {\n\treturn {\n\t\ttextAlign,\n\t\twidth: cellWidth,\n\t\tfontWeight: !cellModified.value ? 'inherit' : 'bold',\n\t\tpaddingLeft: getIndent(colIndex, store.display[rowIndex]?.indent),\n\t}\n})\n\nconst cellClasses = computed(() => {\n\treturn {\n\t\t'sticky-column': pinned,\n\t\t'cell-modified': cellModified.value,\n\t\t'atable-cell--badge-fill': usesBadgeDisplay.value,\n\t}\n})\n\nconst onCellClick = () => {\n\t// First, select all text if the cell is editable\n\tselectAllText()\n\n\t// Then handle modal display (original showModal behavior)\n\tshowModal()\n}\n\nconst showModal = () => {\n\tconst { left, bottom, width, height } = useElementBounding(cellRef)\n\n\tif (column.mask) {\n\t\t// TODO: add masking to cell values\n\t\t// column.mask(event)\n\t}\n\n\tif (column.modalComponent) {\n\t\tstore.$patch(state => {\n\t\t\tstate.modal.visible = true\n\t\t\tstate.modal.colIndex = colIndex\n\t\t\tstate.modal.rowIndex = rowIndex\n\t\t\t// Snapshot the cell's box as it was when the modal opened. These are refs, and assigning\n\t\t\t// them raw happened to work only because reactive reads unwrap refs — which also left the\n\t\t\t// stored values live, tracking the cell for as long as the modal stayed open.\n\t\t\tstate.modal.left = left.value\n\t\t\tstate.modal.bottom = bottom.value\n\t\t\tstate.modal.width = width.value\n\t\t\tstate.modal.height = height.value\n\t\t\tstate.modal.cell = cellRef.value\n\n\t\t\tif (typeof column.modalComponent === 'function') {\n\t\t\t\t// `table` is a computed, so Pinia exposes it as a getter — it is not on `$state`, which\n\t\t\t\t// is what $patch hands back. Reading it off the store is what passes a real table.\n\t\t\t\tstate.modal.component = column.modalComponent({ table: store.table, row, column })\n\t\t\t} else {\n\t\t\t\tstate.modal.component = column.modalComponent\n\t\t\t}\n\n\t\t\tstate.modal.componentProps = column.modalComponentExtraProps\n\t\t})\n\t}\n}\n\nif (addNavigation) {\n\tlet handlers = {\n\t\t...defaultKeypressHandlers,\n\t\t'keydown.f2': showModal,\n\t\t'keydown.alt.up': showModal,\n\t\t'keydown.alt.down': showModal,\n\t\t'keydown.alt.left': showModal,\n\t\t'keydown.alt.right': showModal,\n\t}\n\n\tif (typeof addNavigation === 'object') {\n\t\thandlers = {\n\t\t\t...handlers,\n\t\t\t...addNavigation,\n\t\t}\n\t}\n\n\tuseKeyboardNav([\n\t\t{\n\t\t\tselectors: cellRef,\n\t\t\thandlers: handlers,\n\t\t},\n\t])\n}\n\n// const updateData = (event: Event) => {\n// \tif (event) {\n// \t\t// custom components need to handle their own updateData, this is the default\n// \t\tif (!column.component) {\n// \t\t\tstore.setCellData(colIndex, rowIndex, cell.value.innerHTML)\n// \t\t}\n// \t\tcellModified.value = true\n// \t}\n// }\n\nconst selectAllText = () => {\n\tif (cellRef.value && column.edit) {\n\t\t// Use the Selection API to select all text content in the contenteditable cell\n\t\tconst selection = window.getSelection()\n\t\tif (selection) {\n\t\t\ttry {\n\t\t\t\tconst range = document.createRange()\n\t\t\t\tif (range.selectNodeContents) {\n\t\t\t\t\trange.selectNodeContents(cellRef.value)\n\t\t\t\t\tselection.removeAllRanges()\n\t\t\t\t\tselection.addRange(range)\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Fallback for environments where Range API is not fully supported\n\t\t\t\t// This is expected in some test environments\n\t\t\t}\n\t\t}\n\t}\n}\n\nconst onFocus = () => {\n\tif (cellRef.value) {\n\t\tcurrentData.value = cellRef.value.textContent!\n\t\t// Select all text when the cell receives focus\n\t\tselectAllText()\n\t}\n}\n\nconst saveCursorPosition = () => {\n\ttry {\n\t\tconst selection = window.getSelection()\n\t\tif (selection && selection.rangeCount > 0 && cellRef.value) {\n\t\t\tconst range = selection.getRangeAt(0)\n\t\t\t// Save the offset from the start of the cell\n\t\t\tconst preCaretRange = range.cloneRange()\n\t\t\tif (preCaretRange.selectNodeContents && preCaretRange.setEnd) {\n\t\t\t\tpreCaretRange.selectNodeContents(cellRef.value)\n\t\t\t\tpreCaretRange.setEnd(range.endContainer, range.endOffset)\n\t\t\t\treturn preCaretRange.toString().length\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// Fallback for environments where Selection API is not fully supported\n\t}\n\treturn 0\n}\n\nconst restoreCursorPosition = (position: number) => {\n\tif (!cellRef.value) return\n\n\ttry {\n\t\tconst selection = window.getSelection()\n\t\tif (!selection) return\n\n\t\tlet charIndex = 0\n\t\tconst walker = document.createTreeWalker\n\t\t\t? document.createTreeWalker(cellRef.value, NodeFilter.SHOW_TEXT, null)\n\t\t\t: null\n\n\t\tif (!walker) return\n\n\t\tlet node: Node | null\n\t\tlet range: Range | null = null\n\n\t\twhile ((node = walker.nextNode())) {\n\t\t\tconst textNode = node as Text\n\t\t\tconst nextCharIndex = charIndex + textNode.textContent.length\n\n\t\t\tif (position <= nextCharIndex) {\n\t\t\t\trange = document.createRange()\n\t\t\t\tif (range.setStart && range.setEnd) {\n\t\t\t\t\trange.setStart(textNode, position - charIndex)\n\t\t\t\t\trange.setEnd(textNode, position - charIndex)\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\tcharIndex = nextCharIndex\n\t\t}\n\n\t\tif (range && selection.removeAllRanges && selection.addRange) {\n\t\t\tselection.removeAllRanges()\n\t\t\tselection.addRange(range)\n\t\t}\n\t} catch {\n\t\t// Fallback for environments where DOM APIs are not fully supported\n\t}\n}\n\nconst updateCellData = (payload: Event) => {\n\tif (!column.edit) return\n\n\tconst target = payload.target as HTMLTableCellElement\n\tif (target.textContent === currentData.value) {\n\t\treturn\n\t}\n\n\t// Save cursor position before updating\n\tconst cursorPosition = saveCursorPosition()\n\n\tcurrentData.value = target.textContent!\n\n\t// only apply changes if the cell value has changed after being mounted\n\tif (column.format) {\n\t\tcellModified.value = target.textContent !== store.getFormattedValue(colIndex, rowIndex, originalData)\n\t\t// TODO: need to setup reverse format function?\n\t\tstore.setCellText(colIndex, rowIndex, target.textContent)\n\t} else {\n\t\tcellModified.value = target.textContent !== originalData\n\t\tstore.setCellData(colIndex, rowIndex, target.textContent)\n\t}\n\n\t// Use nextTick to restore cursor position after Vue's reactive updates but before browser repaint\n\tvoid nextTick().then(() => {\n\t\treturn restoreCursorPosition(cursorPosition)\n\t})\n}\n\nconst debouncedUpdateCellData = useDebounceFn(updateCellData, debounce)\n\ndefineExpose({\n\tcurrentData,\n})\n</script>\n\n<style>\n.atable-cell {\n\tbackground-color: inherit;\n\tborder-radius: 0px;\n\tbox-sizing: border-box;\n\tmargin: 0px;\n\toutline: none;\n\tbox-shadow: none;\n\tcolor: var(--sc-cell-text-color);\n\toverflow: hidden;\n\tpadding-left: 0.5ch !important;\n\tpadding-right: 0.5ch;\n\tpadding-top: var(--sc-atable-row-padding);\n\tpadding-bottom: var(--sc-atable-row-padding);\n\tborder-spacing: 0px;\n\tborder-collapse: collapse;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\torder: 1;\n\twhite-space: nowrap;\n\tmax-width: 40ch;\n\tborder-top: 1px solid var(--sc-row-border-color);\n\tmargin-left: 1px;\n}\n.atable-cell a {\n\tcolor: var(--sc-cell-text-color);\n\ttext-decoration: none;\n}\n.atable-cell:focus,\n.atable-cell:focus-within {\n\tbackground-color: var(--sc-focus-cell-background);\n\toutline-width: var(--sc-atable-cell-border-width);\n\toutline-style: solid;\n\toutline-offset: calc(var(--sc-atable-cell-border-width) * -1);\n\toutline-color: var(--sc-focus-cell-outline);\n\tbox-shadow: none;\n\toverflow: hidden;\n\ttext-wrap: nowrap;\n\tbox-sizing: border-box;\n}\n.cell-modified {\n\tfont-weight: bold;\n\tfont-style: italic;\n}\n.cell-modified-highlight {\n\tbackground-color: var(--sc-cell-changed-color);\n}\n.atable-cell--badge-fill {\n\tpadding: 0 !important;\n\tmargin-left: 0;\n}\n</style>\n","<template>\n\t<td class=\"aganttcell\" :colspan=\"colspan\">\n\t\t<div ref=\"container\" class=\"gantt-container\">\n\t\t\t<!-- Draggable gantt bar -->\n\t\t\t<div\n\t\t\t\tref=\"bar\"\n\t\t\t\t:data-rowindex=\"rowIndex\"\n\t\t\t\t:data-colindex=\"colIndex\"\n\t\t\t\tclass=\"gantt-bar\"\n\t\t\t\t:class=\"{ 'is-dragging': isAnyDragging }\"\n\t\t\t\t:style=\"barStyle\"\n\t\t\t\t@mouseenter=\"showConnectionHandles\"\n\t\t\t\t@mouseleave=\"hideConnectionHandles\">\n\t\t\t\t<!-- Connection handles for linking bars - only show if dependency graph is enabled -->\n\t\t\t\t<div\n\t\t\t\t\tv-if=\"store.isDependencyGraphEnabled\"\n\t\t\t\t\tref=\"leftConnectionHandle\"\n\t\t\t\t\tclass=\"connection-handle left-connection-handle\"\n\t\t\t\t\t:class=\"{ visible: isLeftConnectionVisible, 'is-dragging': isLeftConnectionDragging }\"\n\t\t\t\t\t@mousedown.stop=\"startConnectionDrag('left', $event)\">\n\t\t\t\t\t<div class=\"connection-dot\"></div>\n\t\t\t\t</div>\n\n\t\t\t\t<div\n\t\t\t\t\tv-if=\"store.isDependencyGraphEnabled\"\n\t\t\t\t\tref=\"rightConnectionHandle\"\n\t\t\t\t\tclass=\"connection-handle right-connection-handle\"\n\t\t\t\t\t:class=\"{ visible: isRightConnectionVisible, 'is-dragging': isRightConnectionDragging }\"\n\t\t\t\t\t@mousedown.stop=\"startConnectionDrag('right', $event)\">\n\t\t\t\t\t<div class=\"connection-dot\"></div>\n\t\t\t\t</div>\n\n\t\t\t\t<!-- Resize handles for changing bar length -->\n\t\t\t\t<div ref=\"leftResizeHandle\" class=\"resize-handle left-resize-handle\" :class=\"{ 'is-dragging': isLeftResizing }\">\n\t\t\t\t\t<div class=\"handle-grip\"></div>\n\t\t\t\t\t<div class=\"vertical-indicator left-indicator\"></div>\n\t\t\t\t</div>\n\n\t\t\t\t<label v-if=\"label\" class=\"gantt-label\">{{ label }}</label>\n\n\t\t\t\t<div\n\t\t\t\t\tref=\"rightResizeHandle\"\n\t\t\t\t\tclass=\"resize-handle right-resize-handle\"\n\t\t\t\t\t:class=\"{ 'is-dragging': isRightResizing }\">\n\t\t\t\t\t<div class=\"handle-grip\"></div>\n\t\t\t\t\t<div class=\"vertical-indicator right-indicator\"></div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<!-- Connection drag preview line - only show if dependency graph is enabled -->\n\t\t<svg v-if=\"store.isDependencyGraphEnabled && showDragPreview\" :style=\"connectionDragStyle\">\n\t\t\t<line\n\t\t\t\t:x1=\"dragPreview.startX\"\n\t\t\t\t:y1=\"dragPreview.startY\"\n\t\t\t\t:x2=\"dragPreview.endX\"\n\t\t\t\t:y2=\"dragPreview.endY\"\n\t\t\t\tstroke=\"#2196f3\"\n\t\t\t\tstroke-width=\"2\"\n\t\t\t\tstroke-dasharray=\"5,5\" />\n\t\t</svg>\n\t</td>\n</template>\n\n<script setup lang=\"ts\">\nimport { useDraggable, useElementBounding } from '@vueuse/core'\nimport { ref, computed, onMounted, onUnmounted, useTemplateRef, type StyleValue } from 'vue'\n\nimport { createTableStore } from '../stores/table'\nimport type { ConnectionPath } from '../types'\n\nconst {\n\tstore,\n\tcolumnsCount,\n\trowIndex,\n\tcolIndex,\n\tstart = 0,\n\tend = 0,\n\tcolspan = 1,\n\tlabel = '',\n\tcolor = '#cccccc',\n} = defineProps<{\n\tstore: ReturnType<typeof createTableStore>\n\tcolumnsCount: number\n\trowIndex: number\n\tcolIndex: number\n\tstart?: number\n\tend?: number\n\tcolspan?: number\n\tlabel?: string\n\tcolor?: string\n}>()\n\nconst emit = defineEmits<{\n\t'connection:create': [connection: ConnectionPath]\n}>()\n\n// Core refs and state\nconst barColor = ref(color.length >= 6 ? color : '#cccccc')\nconst barId = `gantt-bar-row-${rowIndex}-col-${colIndex}`\n\n// Template refs\nconst containerRef = useTemplateRef<HTMLDivElement>('container')\nconst barRef = useTemplateRef<HTMLDivElement>('bar')\nconst leftResizeHandleRef = useTemplateRef<HTMLDivElement>('leftResizeHandle')\nconst rightResizeHandleRef = useTemplateRef<HTMLDivElement>('rightResizeHandle')\nconst leftConnectionHandleRef = useTemplateRef<HTMLDivElement>('leftConnectionHandle')\nconst rightConnectionHandleRef = useTemplateRef<HTMLDivElement>('rightConnectionHandle')\n\n// Position tracking\nconst { width: totalBarWidth } = useElementBounding(containerRef)\nconst { left: barLeft, right: barRight } = useElementBounding(barRef)\n\n// Bar positioning\nconst currentStart = ref(start)\nconst currentEnd = ref(end || currentStart.value + colspan)\n\n// Drag states\nconst isLeftConnectionVisible = ref(false)\nconst isRightConnectionVisible = ref(false)\nconst isLeftConnectionDragging = ref(false)\nconst isRightConnectionDragging = ref(false)\nconst showDragPreview = ref(false)\nconst dragPreview = ref({ startX: 0, startY: 0, endX: 0, endY: 0 })\n\n// Computed properties\nconst isAnyDragging = computed(() => isBarDragging.value || isLeftResizing.value || isRightResizing.value)\n\nconst pixelsPerColumn = computed(() => (colspan > 0 ? totalBarWidth.value / colspan : 0))\n\nconst barStyle = computed((): StyleValue => {\n\tconst startPercent = (currentStart.value / colspan) * 100\n\tconst endPercent = (currentEnd.value / colspan) * 100\n\treturn {\n\t\tleft: `${startPercent}%`,\n\t\twidth: `${endPercent - startPercent}%`,\n\t\tbackgroundColor: barColor.value,\n\t}\n})\n\nconst connectionDragStyle = computed((): StyleValue => ({\n\tposition: 'fixed',\n\ttop: 0,\n\tleft: 0,\n\twidth: '100vw',\n\theight: '100vh',\n\tpointerEvents: 'none',\n\tzIndex: 1000,\n}))\n\n// Drag setup data\nconst dragStartData = ref({ startX: 0, startPos: 0 })\n\n// Left resize handle dragging\nconst { isDragging: isLeftResizing } = useDraggable(leftResizeHandleRef, {\n\taxis: 'x',\n\tonStart: () => setupDragStart(barLeft.value, currentStart.value),\n\tonMove: ({ x }) => handleLeftResize(x),\n\tonEnd: ({ x }) => finishLeftResize(x),\n})\n\n// Right resize handle dragging\nconst { isDragging: isRightResizing } = useDraggable(rightResizeHandleRef, {\n\taxis: 'x',\n\tonStart: () => setupDragStart(barRight.value, currentEnd.value),\n\tonMove: ({ x }) => handleRightResize(x),\n\tonEnd: ({ x }) => finishRightResize(x),\n})\n\n// Bar movement dragging\nconst { isDragging: isBarDragging } = useDraggable(barRef, {\n\texact: true,\n\taxis: 'x',\n\tonStart: () => setupDragStart(barLeft.value, currentStart.value),\n\tonMove: ({ x }) => handleBarMove(x),\n\tonEnd: ({ x }) => finishBarMove(x),\n})\n\n// Lifecycle\nonMounted(() => {\n\tregisterGanttComponents()\n})\n\nonUnmounted(() => {\n\tunregisterGanttComponents()\n})\n\n// Helper functions\nfunction setupDragStart(startX: number, startPos: number) {\n\tif (barRef.value) barRef.value.style.transition = 'none'\n\tdragStartData.value = { startX, startPos }\n}\n\nfunction handleLeftResize(x: number) {\n\tif (!isLeftResizing.value || !barRef.value) return\n\n\tconst deltaX = x - dragStartData.value.startX\n\tconst deltaColumns = deltaX / pixelsPerColumn.value\n\tconst newStart = Math.max(0, Math.min(currentEnd.value - 1, dragStartData.value.startPos + deltaColumns))\n\n\tbarRef.value.style.left = `${(newStart / colspan) * 100}%`\n\tbarRef.value.style.width = `${((currentEnd.value - newStart) / colspan) * 100}%`\n}\n\nfunction finishLeftResize(x: number) {\n\tif (!barRef.value) return\n\n\tconst deltaX = x - dragStartData.value.startX\n\tconst deltaColumns = Math.round(deltaX / pixelsPerColumn.value)\n\tconst oldStart = currentStart.value\n\tconst newStart = Math.max(0, Math.min(currentEnd.value - 1, dragStartData.value.startPos + deltaColumns))\n\n\tcurrentStart.value = newStart\n\tstore.updateGanttBar({\n\t\trowIndex,\n\t\tcolIndex,\n\t\ttype: 'resize',\n\t\tedge: 'start',\n\t\toldStart,\n\t\tnewStart,\n\t\tend: currentEnd.value,\n\t\tdelta: deltaColumns,\n\t\toldColspan: currentEnd.value - oldStart,\n\t\tnewColspan: currentEnd.value - newStart,\n\t})\n}\n\nfunction handleRightResize(x: number) {\n\tif (!isRightResizing.value || !barRef.value) return\n\n\tconst deltaX = x - dragStartData.value.startX\n\tconst deltaColumns = deltaX / pixelsPerColumn.value\n\tconst newEnd = Math.max(currentStart.value + 1, Math.min(columnsCount, dragStartData.value.startPos + deltaColumns))\n\n\tbarRef.value.style.width = `${((newEnd - currentStart.value) / colspan) * 100}%`\n}\n\nfunction finishRightResize(x: number) {\n\tif (!barRef.value) return\n\n\tconst deltaX = x - dragStartData.value.startX\n\tconst deltaColumns = Math.round(deltaX / pixelsPerColumn.value)\n\tconst oldEnd = currentEnd.value\n\tconst newEnd = Math.max(currentStart.value + 1, Math.min(columnsCount, dragStartData.value.startPos + deltaColumns))\n\n\tcurrentEnd.value = newEnd\n\tstore.updateGanttBar({\n\t\trowIndex,\n\t\tcolIndex,\n\t\ttype: 'resize',\n\t\tedge: 'end',\n\t\toldEnd,\n\t\tnewEnd,\n\t\tstart: currentStart.value,\n\t\tdelta: deltaColumns,\n\t\toldColspan: oldEnd - currentStart.value,\n\t\tnewColspan: newEnd - currentStart.value,\n\t})\n}\n\nfunction handleBarMove(x: number) {\n\tif (!isBarDragging.value || !barRef.value) return\n\n\tconst deltaX = x - dragStartData.value.startX\n\tconst deltaColumns = deltaX / pixelsPerColumn.value\n\tconst barWidth = currentEnd.value - currentStart.value\n\tconst newStart = Math.max(0, Math.min(dragStartData.value.startPos + deltaColumns, columnsCount - barWidth))\n\n\tbarRef.value.style.left = `${(newStart / colspan) * 100}%`\n}\n\nfunction finishBarMove(x: number) {\n\tif (!barRef.value) return\n\n\tconst deltaX = x - dragStartData.value.startX\n\tconst deltaColumns = Math.round(deltaX / pixelsPerColumn.value)\n\tconst barWidth = currentEnd.value - currentStart.value\n\n\tconst oldStart = currentStart.value\n\tconst oldEnd = currentEnd.value\n\tlet newStart = dragStartData.value.startPos + deltaColumns\n\tlet newEnd = newStart + barWidth\n\n\t// Boundary checks\n\tif (newStart < 0) {\n\t\tnewStart = 0\n\t\tnewEnd = barWidth\n\t} else if (newEnd > columnsCount) {\n\t\tnewEnd = columnsCount\n\t\tnewStart = newEnd - barWidth\n\t}\n\n\tcurrentStart.value = newStart\n\tcurrentEnd.value = newEnd\n\n\tstore.updateGanttBar({\n\t\trowIndex,\n\t\tcolIndex,\n\t\ttype: 'bar',\n\t\toldStart,\n\t\toldEnd,\n\t\tnewStart,\n\t\tnewEnd,\n\t\tdelta: deltaColumns,\n\t\tcolspan: newEnd - newStart,\n\t})\n}\n\nfunction registerGanttComponents() {\n\tconst { x: barX, y: barY } = useElementBounding(barRef)\n\tconst { x: leftX, y: leftY } = useElementBounding(leftConnectionHandleRef)\n\tconst { x: rightX, y: rightY } = useElementBounding(rightConnectionHandleRef)\n\n\tstore.registerGanttBar({\n\t\tid: barId,\n\t\trowIndex,\n\t\tcolIndex,\n\t\tstartIndex: currentStart,\n\t\tendIndex: currentEnd,\n\t\tcolor: barColor,\n\t\tlabel,\n\t\tposition: { x: barX, y: barY },\n\t})\n\n\t// Only register connection handles if dependency graph is enabled\n\tif (store.isDependencyGraphEnabled) {\n\t\tstore.registerConnectionHandle({\n\t\t\tid: `${barId}-connection-left`,\n\t\t\trowIndex,\n\t\t\tcolIndex,\n\t\t\tside: 'left',\n\t\t\tposition: { x: leftX, y: leftY },\n\t\t\tvisible: isLeftConnectionVisible,\n\t\t\tbarId,\n\t\t})\n\n\t\tstore.registerConnectionHandle({\n\t\t\tid: `${barId}-connection-right`,\n\t\t\trowIndex,\n\t\t\tcolIndex,\n\t\t\tside: 'right',\n\t\t\tposition: { x: rightX, y: rightY },\n\t\t\tvisible: isRightConnectionVisible,\n\t\t\tbarId,\n\t\t})\n\t}\n}\n\nfunction unregisterGanttComponents() {\n\tstore.unregisterGanttBar(barId)\n\t// Only unregister connection handles if dependency graph is enabled\n\tif (store.isDependencyGraphEnabled) {\n\t\tstore.unregisterConnectionHandle(`${barId}-connection-left`)\n\t\tstore.unregisterConnectionHandle(`${barId}-connection-right`)\n\t}\n}\n\nfunction showConnectionHandles() {\n\t// Only show connection handles if dependency graph is enabled\n\tif (store.isDependencyGraphEnabled) {\n\t\tisLeftConnectionVisible.value = true\n\t\tisRightConnectionVisible.value = true\n\t}\n}\n\nfunction hideConnectionHandles() {\n\tif (!isLeftConnectionDragging.value && !isRightConnectionDragging.value) {\n\t\tisLeftConnectionVisible.value = false\n\t\tisRightConnectionVisible.value = false\n\t}\n}\n\nfunction startConnectionDrag(side: 'left' | 'right', event: MouseEvent) {\n\tevent.preventDefault()\n\tevent.stopPropagation()\n\n\tshowDragPreview.value = true\n\tif (side === 'left') {\n\t\tisLeftConnectionDragging.value = true\n\t} else {\n\t\tisRightConnectionDragging.value = true\n\t}\n\n\t// Set initial drag preview position\n\tconst handle = side === 'left' ? leftConnectionHandleRef.value : rightConnectionHandleRef.value\n\tif (handle) {\n\t\tconst handleRect = handle.getBoundingClientRect()\n\t\tconst centerX = handleRect.left + handleRect.width / 2\n\t\tconst centerY = handleRect.top + handleRect.height / 2\n\t\tdragPreview.value = { startX: centerX, startY: centerY, endX: centerX, endY: centerY }\n\t}\n\n\tconst handleMouseMove = (moveEvent: MouseEvent) => {\n\t\tdragPreview.value.endX = moveEvent.clientX\n\t\tdragPreview.value.endY = moveEvent.clientY\n\t}\n\n\tconst handleMouseUp = (upEvent: MouseEvent) => {\n\t\thandleConnectionDrop(upEvent, side)\n\t\tcleanupConnectionDrag(handleMouseMove, handleMouseUp)\n\t}\n\n\tdocument.addEventListener('mousemove', handleMouseMove)\n\tdocument.addEventListener('mouseup', handleMouseUp)\n}\n\nfunction handleConnectionDrop(upEvent: MouseEvent, sourceSide: 'left' | 'right') {\n\tconst targetElement = document.elementFromPoint(upEvent.clientX, upEvent.clientY)\n\tconst targetHandle = targetElement?.closest('.connection-handle')\n\n\tif (\n\t\ttargetHandle &&\n\t\ttargetHandle !== (sourceSide === 'left' ? leftConnectionHandleRef.value : rightConnectionHandleRef.value)\n\t) {\n\t\tconst targetBar = targetHandle.closest('.gantt-bar')\n\n\t\tif (targetBar) {\n\t\t\tconst targetRowIndex = parseInt(targetBar.getAttribute('data-rowindex') || '0')\n\t\t\tconst targetColIndex = parseInt(targetBar.getAttribute('data-colindex') || '0')\n\t\t\tconst targetSide = targetHandle.classList.contains('left-connection-handle') ? 'left' : 'right'\n\t\t\tconst targetBarId = `gantt-bar-row-${targetRowIndex}-col-${targetColIndex}`\n\n\t\t\tconst connection = store.createConnection(\n\t\t\t\t`${barId}-connection-${sourceSide}`,\n\t\t\t\t`${targetBarId}-connection-${targetSide}`\n\t\t\t)\n\n\t\t\tif (connection) {\n\t\t\t\temit('connection:create', connection)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction cleanupConnectionDrag(\n\thandleMouseMove: (event: MouseEvent) => void,\n\thandleMouseUp: (event: MouseEvent) => void\n) {\n\tshowDragPreview.value = false\n\tisLeftConnectionDragging.value = false\n\tisRightConnectionDragging.value = false\n\n\tdocument.removeEventListener('mousemove', handleMouseMove)\n\tdocument.removeEventListener('mouseup', handleMouseUp)\n\n\tif (!barRef.value?.matches(':hover')) {\n\t\thideConnectionHandles()\n\t}\n}\n\ndefineExpose({\n\tbarStyle,\n\tcleanupConnectionDrag,\n\tcurrentEnd,\n\thandleConnectionDrop,\n\tisLeftConnectionDragging,\n\tisLeftConnectionVisible,\n\tisRightConnectionDragging,\n\tisRightConnectionVisible,\n\tshowDragPreview,\n})\n</script>\n\n<style scoped>\n.aganttcell {\n\tbackground-color: #f9f9f9;\n\twidth: 100%;\n\tpadding: 0;\n\theight: 100%;\n}\n\n.gantt-container {\n\tposition: relative;\n\theight: 100%;\n\tbackground-color: #f0f0f0;\n\tborder-radius: 4px;\n\toverflow: visible;\n}\n\n.gantt-bar {\n\tposition: absolute;\n\tborder-radius: 4px;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tcursor: grab;\n\tbox-sizing: border-box;\n\tborder: 1px solid rgba(0, 0, 0, 0.5);\n\ttransition:\n\t\tleft 0.1s ease-out,\n\t\twidth 0.1s ease-out;\n\theight: 80%;\n\ttop: 50%;\n\tz-index: 0;\n\ttransform: translateY(-50%);\n}\n\n.gantt-bar:active {\n\tcursor: grabbing;\n}\n\n.gantt-bar.is-dragging {\n\tz-index: 10;\n}\n\n.gantt-label {\n\tflex: 1;\n\ttext-align: center;\n\tfont-size: 12px;\n\tcolor: #aaaaaa;\n\twhite-space: nowrap;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\tpadding: 0 8px;\n\tuser-select: none;\n}\n\n.resize-handle {\n\tposition: relative;\n\twidth: 12px;\n\theight: 100%;\n\tcursor: ew-resize;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tz-index: 0;\n\tbackground: rgba(0, 0, 0, 0.25);\n}\n\n.left-resize-handle {\n\tborder-right: 1px solid rgba(0, 0, 0, 0.5);\n}\n\n.right-resize-handle {\n\tborder-left: 1px solid rgba(0, 0, 0, 0.5);\n}\n\n.handle-grip {\n\twidth: 4px;\n\theight: 12px;\n\tborder-radius: 2px;\n\tbackground: rgba(0, 0, 0, 0.8);\n}\n\n.resize-handle:hover {\n\tbackground-color: rgba(255, 255, 255, 0.5);\n}\n\n.vertical-indicator {\n\tposition: absolute;\n\twidth: 2px;\n\topacity: 0;\n\tpointer-events: none;\n\ttransition: opacity 0.2s ease;\n\ttop: -100vh;\n\theight: 100vh;\n\tz-index: 5;\n\tbackground-color: v-bind(barColor);\n}\n\n.left-indicator {\n\tleft: 50%;\n\ttransform: translateX(-50%);\n}\n\n.right-indicator {\n\tright: 50%;\n\ttransform: translateX(50%);\n}\n\n.resize-handle.is-dragging .vertical-indicator {\n\topacity: 0.7;\n}\n\n.gantt-container::after {\n\tcontent: '';\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\tright: 0;\n\tbottom: 0;\n\tbackground-size: calc(100% / v-bind(colspan)) 100%;\n\tbackground-image: linear-gradient(to right, rgba(0, 0, 0, 0.1) 1px, transparent 1px);\n\tpointer-events: none;\n\tz-index: 1;\n}\n\n.connection-handle {\n\tposition: absolute;\n\ttop: 50%;\n\ttransform: translateY(-50%);\n\twidth: 16px;\n\theight: 16px;\n\topacity: 0;\n\ttransition: opacity 0.2s ease;\n\tcursor: crosshair;\n\tz-index: 2;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n}\n\n.connection-handle.visible {\n\topacity: 1;\n}\n\n.left-connection-handle {\n\tleft: -16px;\n}\n\n.right-connection-handle {\n\tright: -16px;\n}\n\n.connection-dot {\n\twidth: 8px;\n\theight: 8px;\n\tborder-radius: 50%;\n\tbackground-color: #2196f3;\n\tborder: 2px solid white;\n\tbox-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);\n}\n\n.connection-handle:hover .connection-dot {\n\tbackground-color: #1976d2;\n\ttransform: scale(1.2);\n}\n\n.connection-handle.is-dragging {\n\topacity: 1 !important;\n}\n\n.connection-handle.is-dragging .connection-dot {\n\tbackground-color: #1976d2;\n\ttransform: scale(1.3);\n\tbox-shadow: 0 2px 8px rgba(33, 150, 243, 0.4);\n}\n</style>\n","<template>\n\t<td class=\"aganttcell\" :colspan=\"colspan\">\n\t\t<div ref=\"container\" class=\"gantt-container\">\n\t\t\t<!-- Draggable gantt bar -->\n\t\t\t<div\n\t\t\t\tref=\"bar\"\n\t\t\t\t:data-rowindex=\"rowIndex\"\n\t\t\t\t:data-colindex=\"colIndex\"\n\t\t\t\tclass=\"gantt-bar\"\n\t\t\t\t:class=\"{ 'is-dragging': isAnyDragging }\"\n\t\t\t\t:style=\"barStyle\"\n\t\t\t\t@mouseenter=\"showConnectionHandles\"\n\t\t\t\t@mouseleave=\"hideConnectionHandles\">\n\t\t\t\t<!-- Connection handles for linking bars - only show if dependency graph is enabled -->\n\t\t\t\t<div\n\t\t\t\t\tv-if=\"store.isDependencyGraphEnabled\"\n\t\t\t\t\tref=\"leftConnectionHandle\"\n\t\t\t\t\tclass=\"connection-handle left-connection-handle\"\n\t\t\t\t\t:class=\"{ visible: isLeftConnectionVisible, 'is-dragging': isLeftConnectionDragging }\"\n\t\t\t\t\t@mousedown.stop=\"startConnectionDrag('left', $event)\">\n\t\t\t\t\t<div class=\"connection-dot\"></div>\n\t\t\t\t</div>\n\n\t\t\t\t<div\n\t\t\t\t\tv-if=\"store.isDependencyGraphEnabled\"\n\t\t\t\t\tref=\"rightConnectionHandle\"\n\t\t\t\t\tclass=\"connection-handle right-connection-handle\"\n\t\t\t\t\t:class=\"{ visible: isRightConnectionVisible, 'is-dragging': isRightConnectionDragging }\"\n\t\t\t\t\t@mousedown.stop=\"startConnectionDrag('right', $event)\">\n\t\t\t\t\t<div class=\"connection-dot\"></div>\n\t\t\t\t</div>\n\n\t\t\t\t<!-- Resize handles for changing bar length -->\n\t\t\t\t<div ref=\"leftResizeHandle\" class=\"resize-handle left-resize-handle\" :class=\"{ 'is-dragging': isLeftResizing }\">\n\t\t\t\t\t<div class=\"handle-grip\"></div>\n\t\t\t\t\t<div class=\"vertical-indicator left-indicator\"></div>\n\t\t\t\t</div>\n\n\t\t\t\t<label v-if=\"label\" class=\"gantt-label\">{{ label }}</label>\n\n\t\t\t\t<div\n\t\t\t\t\tref=\"rightResizeHandle\"\n\t\t\t\t\tclass=\"resize-handle right-resize-handle\"\n\t\t\t\t\t:class=\"{ 'is-dragging': isRightResizing }\">\n\t\t\t\t\t<div class=\"handle-grip\"></div>\n\t\t\t\t\t<div class=\"vertical-indicator right-indicator\"></div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<!-- Connection drag preview line - only show if dependency graph is enabled -->\n\t\t<svg v-if=\"store.isDependencyGraphEnabled && showDragPreview\" :style=\"connectionDragStyle\">\n\t\t\t<line\n\t\t\t\t:x1=\"dragPreview.startX\"\n\t\t\t\t:y1=\"dragPreview.startY\"\n\t\t\t\t:x2=\"dragPreview.endX\"\n\t\t\t\t:y2=\"dragPreview.endY\"\n\t\t\t\tstroke=\"#2196f3\"\n\t\t\t\tstroke-width=\"2\"\n\t\t\t\tstroke-dasharray=\"5,5\" />\n\t\t</svg>\n\t</td>\n</template>\n\n<script setup lang=\"ts\">\nimport { useDraggable, useElementBounding } from '@vueuse/core'\nimport { ref, computed, onMounted, onUnmounted, useTemplateRef, type StyleValue } from 'vue'\n\nimport { createTableStore } from '../stores/table'\nimport type { ConnectionPath } from '../types'\n\nconst {\n\tstore,\n\tcolumnsCount,\n\trowIndex,\n\tcolIndex,\n\tstart = 0,\n\tend = 0,\n\tcolspan = 1,\n\tlabel = '',\n\tcolor = '#cccccc',\n} = defineProps<{\n\tstore: ReturnType<typeof createTableStore>\n\tcolumnsCount: number\n\trowIndex: number\n\tcolIndex: number\n\tstart?: number\n\tend?: number\n\tcolspan?: number\n\tlabel?: string\n\tcolor?: string\n}>()\n\nconst emit = defineEmits<{\n\t'connection:create': [connection: ConnectionPath]\n}>()\n\n// Core refs and state\nconst barColor = ref(color.length >= 6 ? color : '#cccccc')\nconst barId = `gantt-bar-row-${rowIndex}-col-${colIndex}`\n\n// Template refs\nconst containerRef = useTemplateRef<HTMLDivElement>('container')\nconst barRef = useTemplateRef<HTMLDivElement>('bar')\nconst leftResizeHandleRef = useTemplateRef<HTMLDivElement>('leftResizeHandle')\nconst rightResizeHandleRef = useTemplateRef<HTMLDivElement>('rightResizeHandle')\nconst leftConnectionHandleRef = useTemplateRef<HTMLDivElement>('leftConnectionHandle')\nconst rightConnectionHandleRef = useTemplateRef<HTMLDivElement>('rightConnectionHandle')\n\n// Position tracking\nconst { width: totalBarWidth } = useElementBounding(containerRef)\nconst { left: barLeft, right: barRight } = useElementBounding(barRef)\n\n// Bar positioning\nconst currentStart = ref(start)\nconst currentEnd = ref(end || currentStart.value + colspan)\n\n// Drag states\nconst isLeftConnectionVisible = ref(false)\nconst isRightConnectionVisible = ref(false)\nconst isLeftConnectionDragging = ref(false)\nconst isRightConnectionDragging = ref(false)\nconst showDragPreview = ref(false)\nconst dragPreview = ref({ startX: 0, startY: 0, endX: 0, endY: 0 })\n\n// Computed properties\nconst isAnyDragging = computed(() => isBarDragging.value || isLeftResizing.value || isRightResizing.value)\n\nconst pixelsPerColumn = computed(() => (colspan > 0 ? totalBarWidth.value / colspan : 0))\n\nconst barStyle = computed((): StyleValue => {\n\tconst startPercent = (currentStart.value / colspan) * 100\n\tconst endPercent = (currentEnd.value / colspan) * 100\n\treturn {\n\t\tleft: `${startPercent}%`,\n\t\twidth: `${endPercent - startPercent}%`,\n\t\tbackgroundColor: barColor.value,\n\t}\n})\n\nconst connectionDragStyle = computed((): StyleValue => ({\n\tposition: 'fixed',\n\ttop: 0,\n\tleft: 0,\n\twidth: '100vw',\n\theight: '100vh',\n\tpointerEvents: 'none',\n\tzIndex: 1000,\n}))\n\n// Drag setup data\nconst dragStartData = ref({ startX: 0, startPos: 0 })\n\n// Left resize handle dragging\nconst { isDragging: isLeftResizing } = useDraggable(leftResizeHandleRef, {\n\taxis: 'x',\n\tonStart: () => setupDragStart(barLeft.value, currentStart.value),\n\tonMove: ({ x }) => handleLeftResize(x),\n\tonEnd: ({ x }) => finishLeftResize(x),\n})\n\n// Right resize handle dragging\nconst { isDragging: isRightResizing } = useDraggable(rightResizeHandleRef, {\n\taxis: 'x',\n\tonStart: () => setupDragStart(barRight.value, currentEnd.value),\n\tonMove: ({ x }) => handleRightResize(x),\n\tonEnd: ({ x }) => finishRightResize(x),\n})\n\n// Bar movement dragging\nconst { isDragging: isBarDragging } = useDraggable(barRef, {\n\texact: true,\n\taxis: 'x',\n\tonStart: () => setupDragStart(barLeft.value, currentStart.value),\n\tonMove: ({ x }) => handleBarMove(x),\n\tonEnd: ({ x }) => finishBarMove(x),\n})\n\n// Lifecycle\nonMounted(() => {\n\tregisterGanttComponents()\n})\n\nonUnmounted(() => {\n\tunregisterGanttComponents()\n})\n\n// Helper functions\nfunction setupDragStart(startX: number, startPos: number) {\n\tif (barRef.value) barRef.value.style.transition = 'none'\n\tdragStartData.value = { startX, startPos }\n}\n\nfunction handleLeftResize(x: number) {\n\tif (!isLeftResizing.value || !barRef.value) return\n\n\tconst deltaX = x - dragStartData.value.startX\n\tconst deltaColumns = deltaX / pixelsPerColumn.value\n\tconst newStart = Math.max(0, Math.min(currentEnd.value - 1, dragStartData.value.startPos + deltaColumns))\n\n\tbarRef.value.style.left = `${(newStart / colspan) * 100}%`\n\tbarRef.value.style.width = `${((currentEnd.value - newStart) / colspan) * 100}%`\n}\n\nfunction finishLeftResize(x: number) {\n\tif (!barRef.value) return\n\n\tconst deltaX = x - dragStartData.value.startX\n\tconst deltaColumns = Math.round(deltaX / pixelsPerColumn.value)\n\tconst oldStart = currentStart.value\n\tconst newStart = Math.max(0, Math.min(currentEnd.value - 1, dragStartData.value.startPos + deltaColumns))\n\n\tcurrentStart.value = newStart\n\tstore.updateGanttBar({\n\t\trowIndex,\n\t\tcolIndex,\n\t\ttype: 'resize',\n\t\tedge: 'start',\n\t\toldStart,\n\t\tnewStart,\n\t\tend: currentEnd.value,\n\t\tdelta: deltaColumns,\n\t\toldColspan: currentEnd.value - oldStart,\n\t\tnewColspan: currentEnd.value - newStart,\n\t})\n}\n\nfunction handleRightResize(x: number) {\n\tif (!isRightResizing.value || !barRef.value) return\n\n\tconst deltaX = x - dragStartData.value.startX\n\tconst deltaColumns = deltaX / pixelsPerColumn.value\n\tconst newEnd = Math.max(currentStart.value + 1, Math.min(columnsCount, dragStartData.value.startPos + deltaColumns))\n\n\tbarRef.value.style.width = `${((newEnd - currentStart.value) / colspan) * 100}%`\n}\n\nfunction finishRightResize(x: number) {\n\tif (!barRef.value) return\n\n\tconst deltaX = x - dragStartData.value.startX\n\tconst deltaColumns = Math.round(deltaX / pixelsPerColumn.value)\n\tconst oldEnd = currentEnd.value\n\tconst newEnd = Math.max(currentStart.value + 1, Math.min(columnsCount, dragStartData.value.startPos + deltaColumns))\n\n\tcurrentEnd.value = newEnd\n\tstore.updateGanttBar({\n\t\trowIndex,\n\t\tcolIndex,\n\t\ttype: 'resize',\n\t\tedge: 'end',\n\t\toldEnd,\n\t\tnewEnd,\n\t\tstart: currentStart.value,\n\t\tdelta: deltaColumns,\n\t\toldColspan: oldEnd - currentStart.value,\n\t\tnewColspan: newEnd - currentStart.value,\n\t})\n}\n\nfunction handleBarMove(x: number) {\n\tif (!isBarDragging.value || !barRef.value) return\n\n\tconst deltaX = x - dragStartData.value.startX\n\tconst deltaColumns = deltaX / pixelsPerColumn.value\n\tconst barWidth = currentEnd.value - currentStart.value\n\tconst newStart = Math.max(0, Math.min(dragStartData.value.startPos + deltaColumns, columnsCount - barWidth))\n\n\tbarRef.value.style.left = `${(newStart / colspan) * 100}%`\n}\n\nfunction finishBarMove(x: number) {\n\tif (!barRef.value) return\n\n\tconst deltaX = x - dragStartData.value.startX\n\tconst deltaColumns = Math.round(deltaX / pixelsPerColumn.value)\n\tconst barWidth = currentEnd.value - currentStart.value\n\n\tconst oldStart = currentStart.value\n\tconst oldEnd = currentEnd.value\n\tlet newStart = dragStartData.value.startPos + deltaColumns\n\tlet newEnd = newStart + barWidth\n\n\t// Boundary checks\n\tif (newStart < 0) {\n\t\tnewStart = 0\n\t\tnewEnd = barWidth\n\t} else if (newEnd > columnsCount) {\n\t\tnewEnd = columnsCount\n\t\tnewStart = newEnd - barWidth\n\t}\n\n\tcurrentStart.value = newStart\n\tcurrentEnd.value = newEnd\n\n\tstore.updateGanttBar({\n\t\trowIndex,\n\t\tcolIndex,\n\t\ttype: 'bar',\n\t\toldStart,\n\t\toldEnd,\n\t\tnewStart,\n\t\tnewEnd,\n\t\tdelta: deltaColumns,\n\t\tcolspan: newEnd - newStart,\n\t})\n}\n\nfunction registerGanttComponents() {\n\tconst { x: barX, y: barY } = useElementBounding(barRef)\n\tconst { x: leftX, y: leftY } = useElementBounding(leftConnectionHandleRef)\n\tconst { x: rightX, y: rightY } = useElementBounding(rightConnectionHandleRef)\n\n\tstore.registerGanttBar({\n\t\tid: barId,\n\t\trowIndex,\n\t\tcolIndex,\n\t\tstartIndex: currentStart,\n\t\tendIndex: currentEnd,\n\t\tcolor: barColor,\n\t\tlabel,\n\t\tposition: { x: barX, y: barY },\n\t})\n\n\t// Only register connection handles if dependency graph is enabled\n\tif (store.isDependencyGraphEnabled) {\n\t\tstore.registerConnectionHandle({\n\t\t\tid: `${barId}-connection-left`,\n\t\t\trowIndex,\n\t\t\tcolIndex,\n\t\t\tside: 'left',\n\t\t\tposition: { x: leftX, y: leftY },\n\t\t\tvisible: isLeftConnectionVisible,\n\t\t\tbarId,\n\t\t})\n\n\t\tstore.registerConnectionHandle({\n\t\t\tid: `${barId}-connection-right`,\n\t\t\trowIndex,\n\t\t\tcolIndex,\n\t\t\tside: 'right',\n\t\t\tposition: { x: rightX, y: rightY },\n\t\t\tvisible: isRightConnectionVisible,\n\t\t\tbarId,\n\t\t})\n\t}\n}\n\nfunction unregisterGanttComponents() {\n\tstore.unregisterGanttBar(barId)\n\t// Only unregister connection handles if dependency graph is enabled\n\tif (store.isDependencyGraphEnabled) {\n\t\tstore.unregisterConnectionHandle(`${barId}-connection-left`)\n\t\tstore.unregisterConnectionHandle(`${barId}-connection-right`)\n\t}\n}\n\nfunction showConnectionHandles() {\n\t// Only show connection handles if dependency graph is enabled\n\tif (store.isDependencyGraphEnabled) {\n\t\tisLeftConnectionVisible.value = true\n\t\tisRightConnectionVisible.value = true\n\t}\n}\n\nfunction hideConnectionHandles() {\n\tif (!isLeftConnectionDragging.value && !isRightConnectionDragging.value) {\n\t\tisLeftConnectionVisible.value = false\n\t\tisRightConnectionVisible.value = false\n\t}\n}\n\nfunction startConnectionDrag(side: 'left' | 'right', event: MouseEvent) {\n\tevent.preventDefault()\n\tevent.stopPropagation()\n\n\tshowDragPreview.value = true\n\tif (side === 'left') {\n\t\tisLeftConnectionDragging.value = true\n\t} else {\n\t\tisRightConnectionDragging.value = true\n\t}\n\n\t// Set initial drag preview position\n\tconst handle = side === 'left' ? leftConnectionHandleRef.value : rightConnectionHandleRef.value\n\tif (handle) {\n\t\tconst handleRect = handle.getBoundingClientRect()\n\t\tconst centerX = handleRect.left + handleRect.width / 2\n\t\tconst centerY = handleRect.top + handleRect.height / 2\n\t\tdragPreview.value = { startX: centerX, startY: centerY, endX: centerX, endY: centerY }\n\t}\n\n\tconst handleMouseMove = (moveEvent: MouseEvent) => {\n\t\tdragPreview.value.endX = moveEvent.clientX\n\t\tdragPreview.value.endY = moveEvent.clientY\n\t}\n\n\tconst handleMouseUp = (upEvent: MouseEvent) => {\n\t\thandleConnectionDrop(upEvent, side)\n\t\tcleanupConnectionDrag(handleMouseMove, handleMouseUp)\n\t}\n\n\tdocument.addEventListener('mousemove', handleMouseMove)\n\tdocument.addEventListener('mouseup', handleMouseUp)\n}\n\nfunction handleConnectionDrop(upEvent: MouseEvent, sourceSide: 'left' | 'right') {\n\tconst targetElement = document.elementFromPoint(upEvent.clientX, upEvent.clientY)\n\tconst targetHandle = targetElement?.closest('.connection-handle')\n\n\tif (\n\t\ttargetHandle &&\n\t\ttargetHandle !== (sourceSide === 'left' ? leftConnectionHandleRef.value : rightConnectionHandleRef.value)\n\t) {\n\t\tconst targetBar = targetHandle.closest('.gantt-bar')\n\n\t\tif (targetBar) {\n\t\t\tconst targetRowIndex = parseInt(targetBar.getAttribute('data-rowindex') || '0')\n\t\t\tconst targetColIndex = parseInt(targetBar.getAttribute('data-colindex') || '0')\n\t\t\tconst targetSide = targetHandle.classList.contains('left-connection-handle') ? 'left' : 'right'\n\t\t\tconst targetBarId = `gantt-bar-row-${targetRowIndex}-col-${targetColIndex}`\n\n\t\t\tconst connection = store.createConnection(\n\t\t\t\t`${barId}-connection-${sourceSide}`,\n\t\t\t\t`${targetBarId}-connection-${targetSide}`\n\t\t\t)\n\n\t\t\tif (connection) {\n\t\t\t\temit('connection:create', connection)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction cleanupConnectionDrag(\n\thandleMouseMove: (event: MouseEvent) => void,\n\thandleMouseUp: (event: MouseEvent) => void\n) {\n\tshowDragPreview.value = false\n\tisLeftConnectionDragging.value = false\n\tisRightConnectionDragging.value = false\n\n\tdocument.removeEventListener('mousemove', handleMouseMove)\n\tdocument.removeEventListener('mouseup', handleMouseUp)\n\n\tif (!barRef.value?.matches(':hover')) {\n\t\thideConnectionHandles()\n\t}\n}\n\ndefineExpose({\n\tbarStyle,\n\tcleanupConnectionDrag,\n\tcurrentEnd,\n\thandleConnectionDrop,\n\tisLeftConnectionDragging,\n\tisLeftConnectionVisible,\n\tisRightConnectionDragging,\n\tisRightConnectionVisible,\n\tshowDragPreview,\n})\n</script>\n\n<style scoped>\n.aganttcell {\n\tbackground-color: #f9f9f9;\n\twidth: 100%;\n\tpadding: 0;\n\theight: 100%;\n}\n\n.gantt-container {\n\tposition: relative;\n\theight: 100%;\n\tbackground-color: #f0f0f0;\n\tborder-radius: 4px;\n\toverflow: visible;\n}\n\n.gantt-bar {\n\tposition: absolute;\n\tborder-radius: 4px;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tcursor: grab;\n\tbox-sizing: border-box;\n\tborder: 1px solid rgba(0, 0, 0, 0.5);\n\ttransition:\n\t\tleft 0.1s ease-out,\n\t\twidth 0.1s ease-out;\n\theight: 80%;\n\ttop: 50%;\n\tz-index: 0;\n\ttransform: translateY(-50%);\n}\n\n.gantt-bar:active {\n\tcursor: grabbing;\n}\n\n.gantt-bar.is-dragging {\n\tz-index: 10;\n}\n\n.gantt-label {\n\tflex: 1;\n\ttext-align: center;\n\tfont-size: 12px;\n\tcolor: #aaaaaa;\n\twhite-space: nowrap;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\tpadding: 0 8px;\n\tuser-select: none;\n}\n\n.resize-handle {\n\tposition: relative;\n\twidth: 12px;\n\theight: 100%;\n\tcursor: ew-resize;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tz-index: 0;\n\tbackground: rgba(0, 0, 0, 0.25);\n}\n\n.left-resize-handle {\n\tborder-right: 1px solid rgba(0, 0, 0, 0.5);\n}\n\n.right-resize-handle {\n\tborder-left: 1px solid rgba(0, 0, 0, 0.5);\n}\n\n.handle-grip {\n\twidth: 4px;\n\theight: 12px;\n\tborder-radius: 2px;\n\tbackground: rgba(0, 0, 0, 0.8);\n}\n\n.resize-handle:hover {\n\tbackground-color: rgba(255, 255, 255, 0.5);\n}\n\n.vertical-indicator {\n\tposition: absolute;\n\twidth: 2px;\n\topacity: 0;\n\tpointer-events: none;\n\ttransition: opacity 0.2s ease;\n\ttop: -100vh;\n\theight: 100vh;\n\tz-index: 5;\n\tbackground-color: v-bind(barColor);\n}\n\n.left-indicator {\n\tleft: 50%;\n\ttransform: translateX(-50%);\n}\n\n.right-indicator {\n\tright: 50%;\n\ttransform: translateX(50%);\n}\n\n.resize-handle.is-dragging .vertical-indicator {\n\topacity: 0.7;\n}\n\n.gantt-container::after {\n\tcontent: '';\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\tright: 0;\n\tbottom: 0;\n\tbackground-size: calc(100% / v-bind(colspan)) 100%;\n\tbackground-image: linear-gradient(to right, rgba(0, 0, 0, 0.1) 1px, transparent 1px);\n\tpointer-events: none;\n\tz-index: 1;\n}\n\n.connection-handle {\n\tposition: absolute;\n\ttop: 50%;\n\ttransform: translateY(-50%);\n\twidth: 16px;\n\theight: 16px;\n\topacity: 0;\n\ttransition: opacity 0.2s ease;\n\tcursor: crosshair;\n\tz-index: 2;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n}\n\n.connection-handle.visible {\n\topacity: 1;\n}\n\n.left-connection-handle {\n\tleft: -16px;\n}\n\n.right-connection-handle {\n\tright: -16px;\n}\n\n.connection-dot {\n\twidth: 8px;\n\theight: 8px;\n\tborder-radius: 50%;\n\tbackground-color: #2196f3;\n\tborder: 2px solid white;\n\tbox-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);\n}\n\n.connection-handle:hover .connection-dot {\n\tbackground-color: #1976d2;\n\ttransform: scale(1.2);\n}\n\n.connection-handle.is-dragging {\n\topacity: 1 !important;\n}\n\n.connection-handle.is-dragging .connection-dot {\n\tbackground-color: #1976d2;\n\ttransform: scale(1.3);\n\tbox-shadow: 0 2px 8px rgba(33, 150, 243, 0.4);\n}\n</style>\n","/**\n * Icon exports for ATable row actions.\n * Icons are exported as raw SVG strings for flexibility in rendering.\n * @packageDocumentation\n */\n\nimport rawAddIcon from './stonecrop-ui-icon-add.svg?raw'\nimport rawDeleteIcon from './stonecrop-ui-icon-delete.svg?raw'\nimport rawDuplicateIcon from './stonecrop-ui-icon-duplicate.svg?raw'\nimport rawInsertAboveIcon from './stonecrop-ui-icon-insert-above.svg?raw'\nimport rawInsertBelowIcon from './stonecrop-ui-icon-insert-below.svg?raw'\nimport rawMoveIcon from './stonecrop-ui-icon-move.svg?raw'\nimport rawOpenIcon from './stonecrop-ui-icon-open.svg?raw'\n\n// Annotated rather than re-exported directly. `?raw` is a Vite import and the .svg files are inlined\n// at build time, so a declaration that infers its type from the import re-states that specifier — and\n// the emitted `dist/src/icons/index.d.ts` then names seven modules the tarball does not contain.\n/** Raw SVG for the add-row action. @public */\nconst AddIcon: string = rawAddIcon\n/** Raw SVG for the delete-row action. @public */\nconst DeleteIcon: string = rawDeleteIcon\n/** Raw SVG for the duplicate-row action. @public */\nconst DuplicateIcon: string = rawDuplicateIcon\n/** Raw SVG for the insert-above action. @public */\nconst InsertAboveIcon: string = rawInsertAboveIcon\n/** Raw SVG for the insert-below action. @public */\nconst InsertBelowIcon: string = rawInsertBelowIcon\n/** Raw SVG for the move action. @public */\nconst MoveIcon: string = rawMoveIcon\n/** Raw SVG for the open-record action. @public */\nconst OpenIcon: string = rawOpenIcon\n\n// Directional move icons are inline (no dedicated SVG asset): simple up/down chevrons.\nconst MoveUpIcon =\n\t'<svg viewBox=\"0 0 16 16\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"><path d=\"M8 13V3.5M4.5 7 8 3.5 11.5 7\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>'\nconst MoveDownIcon =\n\t'<svg viewBox=\"0 0 16 16\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"><path d=\"M8 3v9.5M4.5 9 8 12.5 11.5 9\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>'\n\nexport { AddIcon, DeleteIcon, DuplicateIcon, InsertAboveIcon, InsertBelowIcon, MoveIcon, OpenIcon }\n\n/**\n * Map of action types to their default icons.\n *\n * @public\n */\nexport const actionIcons: Record<string, string> = {\n\tadd: AddIcon,\n\tdelete: DeleteIcon,\n\tduplicate: DuplicateIcon,\n\tinsertAbove: InsertAboveIcon,\n\tinsertBelow: InsertBelowIcon,\n\tmove: MoveIcon,\n\tmoveUp: MoveUpIcon,\n\tmoveDown: MoveDownIcon,\n\topen: OpenIcon,\n}\n","<template>\n\t<td\n\t\tref=\"actionsCell\"\n\t\tclass=\"atable-row-actions\"\n\t\t:class=\"{ 'sticky-column': position === 'before-index', 'dropdown-active': dropdownOpen }\">\n\t\t<!-- Dropdown mode -->\n\t\t<div v-if=\"showDropdown\" class=\"row-actions-dropdown\">\n\t\t\t<button\n\t\t\t\tref=\"toggleButton\"\n\t\t\t\ttype=\"button\"\n\t\t\t\tclass=\"row-actions-toggle\"\n\t\t\t\t:aria-expanded=\"dropdownOpen\"\n\t\t\t\taria-haspopup=\"true\"\n\t\t\t\t@click.stop=\"toggleDropdown\">\n\t\t\t\t<span class=\"dropdown-icon\">⋮</span>\n\t\t\t</button>\n\t\t\t<div\n\t\t\t\tv-show=\"dropdownOpen\"\n\t\t\t\tclass=\"row-actions-menu\"\n\t\t\t\t:class=\"{ 'menu-flipped': dropdownFlipped }\"\n\t\t\t\t:style=\"menuStyle\"\n\t\t\t\trole=\"menu\">\n\t\t\t\t<button\n\t\t\t\t\tv-for=\"action in enabledActions\"\n\t\t\t\t\t:key=\"action.type\"\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"row-action-menu-item\"\n\t\t\t\t\trole=\"menuitem\"\n\t\t\t\t\t:disabled=\"action.disabled\"\n\t\t\t\t\t@click.stop=\"executeAction(action.type, $event)\">\n\t\t\t\t\t<span class=\"action-icon\" v-html=\"action.icon\" />\n\t\t\t\t\t<span class=\"action-label\">{{ action.label }}</span>\n\t\t\t\t</button>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<!-- Icon mode -->\n\t\t<div v-else class=\"row-actions-icons\">\n\t\t\t<button\n\t\t\t\tv-for=\"action in enabledActions\"\n\t\t\t\t:key=\"action.type\"\n\t\t\t\ttype=\"button\"\n\t\t\t\tclass=\"row-action-btn\"\n\t\t\t\t:title=\"action.label\"\n\t\t\t\t:aria-label=\"action.label\"\n\t\t\t\t:disabled=\"action.disabled\"\n\t\t\t\t@click.stop=\"executeAction(action.type, $event)\">\n\t\t\t\t<span class=\"action-icon\" v-html=\"action.icon\" />\n\t\t\t</button>\n\t\t</div>\n\t</td>\n</template>\n\n<script setup lang=\"ts\">\nimport { useResizeObserver, onClickOutside } from '@vueuse/core'\nimport { computed, ref, useTemplateRef } from 'vue'\n\nimport { actionIcons } from '../icons'\nimport { createTableStore } from '../stores/table'\nimport type { RowActionsConfig, RowActionType } from '../types'\n\nconst props = defineProps<{\n\trowIndex: number\n\tstore: ReturnType<typeof createTableStore>\n\tconfig: RowActionsConfig\n\tposition?: 'before-index' | 'after-index' | 'end'\n}>()\n\nconst emit = defineEmits<{\n\taction: [type: RowActionType, rowIndex: number, event?: MouseEvent]\n}>()\n\nconst actionsCellRef = useTemplateRef<HTMLTableCellElement>('actionsCell')\nconst toggleButtonRef = useTemplateRef<HTMLButtonElement>('toggleButton')\nconst cellWidth = ref(0)\nconst dropdownOpen = ref(false)\nconst dropdownFlipped = ref(false)\nconst menuPosition = ref({ top: 0, left: 0 })\n\n// Default labels for actions\nconst defaultLabels: Record<RowActionType, string> = {\n\tadd: 'Add Record',\n\tdelete: 'Delete Record',\n\tduplicate: 'Duplicate Record',\n\tinsertAbove: 'Insert Above',\n\tinsertBelow: 'Insert Below',\n\tmove: 'Move Record',\n\tmoveUp: 'Move Up',\n\tmoveDown: 'Move Down',\n\topen: 'Open Record',\n}\n\n// Determine which actions are enabled\nconst enabledActions = computed(() => {\n\tconst actions: Array<{ type: RowActionType; label: string; icon: string; disabled: boolean }> = []\n\tconst configActions = props.config.actions || {}\n\n\tconst actionTypes: RowActionType[] = [\n\t\t'open',\n\t\t'moveUp',\n\t\t'moveDown',\n\t\t'duplicate',\n\t\t'insertAbove',\n\t\t'insertBelow',\n\t\t'add',\n\t\t'delete',\n\t\t'move',\n\t]\n\n\tfor (const type of actionTypes) {\n\t\tconst actionConfig = configActions[type]\n\n\t\t// Skip if explicitly disabled\n\t\tif (actionConfig === false) continue\n\n\t\t// Skip if not configured and we're being explicit\n\t\tif (actionConfig === undefined) continue\n\n\t\tlet enabled = true\n\t\tlet label = defaultLabels[type]\n\t\tlet icon = actionIcons[type]\n\t\tlet disabled = false\n\n\t\tif (typeof actionConfig === 'object') {\n\t\t\tenabled = actionConfig.enabled !== false\n\t\t\tlabel = actionConfig.label || label\n\t\t\ticon = actionConfig.icon || icon\n\t\t\t// Per-row predicate; reading store state here keeps this computed reactive to row changes.\n\t\t\tif (actionConfig.disabled) disabled = actionConfig.disabled(props.rowIndex, props.store)\n\t\t}\n\n\t\tif (enabled) {\n\t\t\tactions.push({ type, label, icon, disabled })\n\t\t}\n\t}\n\n\treturn actions\n})\n\n// Determine if we should show dropdown mode\nconst showDropdown = computed(() => {\n\tif (props.config.forceDropdown) return true\n\n\tconst threshold = props.config.dropdownThreshold ?? 150\n\tif (threshold === 0) return false\n\n\treturn cellWidth.value > 0 && cellWidth.value < threshold\n})\n\n// Compute menu style for fixed positioning\nconst menuStyle = computed(() => {\n\tif (!dropdownOpen.value) return {}\n\n\tif (dropdownFlipped.value) {\n\t\treturn {\n\t\t\tposition: 'fixed' as const,\n\t\t\tbottom: `${window.innerHeight - menuPosition.value.top}px`,\n\t\t\tleft: `${menuPosition.value.left}px`,\n\t\t\ttop: 'auto',\n\t\t}\n\t}\n\treturn {\n\t\tposition: 'fixed' as const,\n\t\ttop: `${menuPosition.value.top}px`,\n\t\tleft: `${menuPosition.value.left}px`,\n\t}\n})\n\n// Track cell width for responsive behavior\nuseResizeObserver(actionsCellRef, entries => {\n\tconst entry = entries[0]\n\tif (entry) {\n\t\tcellWidth.value = entry.contentRect.width\n\t}\n})\n\n// Toggle dropdown menu\nconst toggleDropdown = () => {\n\tif (!dropdownOpen.value) {\n\t\t// Opening - check if we need to flip\n\t\tcheckDropdownPosition()\n\t}\n\tdropdownOpen.value = !dropdownOpen.value\n}\n\n// Check if dropdown should flip upward and calculate position\nconst checkDropdownPosition = () => {\n\tif (!toggleButtonRef.value) return\n\n\tconst buttonRect = toggleButtonRef.value.getBoundingClientRect()\n\tconst viewportHeight = window.innerHeight\n\tconst viewportWidth = window.innerWidth\n\tconst estimatedMenuHeight = enabledActions.value.length * 40 + 16 // ~40px per item + padding\n\tconst estimatedMenuWidth = 160 // matches min-width: 10rem\n\n\t// Check if menu would extend beyond viewport bottom\n\tconst spaceBelow = viewportHeight - buttonRect.bottom\n\tconst spaceAbove = buttonRect.top\n\n\t// Flip if not enough space below but enough space above\n\tdropdownFlipped.value = spaceBelow < estimatedMenuHeight && spaceAbove > estimatedMenuHeight\n\n\t// Horizontal: anchor the menu's left edge to the button, but right-align it to the button when\n\t// it would overflow the viewport's right edge (e.g. an end-positioned actions column).\n\tlet left = buttonRect.left\n\tif (left + estimatedMenuWidth > viewportWidth) {\n\t\tleft = Math.max(0, buttonRect.right - estimatedMenuWidth)\n\t}\n\n\t// Calculate fixed position\n\tmenuPosition.value = {\n\t\ttop: dropdownFlipped.value ? buttonRect.top : buttonRect.bottom,\n\t\tleft,\n\t}\n}\n\nonClickOutside(actionsCellRef, () => {\n\tdropdownOpen.value = false\n})\n\n// Execute an action\nconst executeAction = (actionType: RowActionType, event?: MouseEvent) => {\n\tdropdownOpen.value = false\n\n\t// Check for custom handler\n\tconst actionConfig = props.config.actions?.[actionType]\n\tif (typeof actionConfig === 'object' && actionConfig.handler) {\n\t\tconst result = actionConfig.handler(props.rowIndex, props.store)\n\t\tif (result === false) {\n\t\t\t// Handler returned false, don't proceed with default behavior\n\t\t\treturn\n\t\t}\n\t}\n\n\t// Emit the action event for parent to handle\n\temit('action', actionType, props.rowIndex, event)\n}\n</script>\n\n<style>\n.atable-row-actions {\n\twidth: 2rem;\n\tmin-width: 2rem;\n\tpadding: 0 0.25rem;\n\tvertical-align: middle;\n\twhite-space: nowrap;\n\tborder-top: 1px solid var(--sc-row-border-color);\n\tbackground: inherit;\n\tuser-select: none;\n\tposition: relative;\n}\n\n.atable-row-actions.dropdown-active {\n\tz-index: 101;\n}\n\n.row-actions-icons {\n\tdisplay: flex;\n\tgap: 0.25rem;\n\talign-items: center;\n\tjustify-content: center;\n}\n\n.row-action-btn {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 1.5rem;\n\theight: 1.5rem;\n\tpadding: 0.125rem;\n\tborder: none;\n\tbackground: transparent;\n\tcursor: pointer;\n\tborder-radius: 0.25rem;\n\ttransition: background-color 0.15s ease;\n}\n\n.row-action-btn:hover {\n\tbackground-color: var(--sc-gray-10);\n}\n\n.row-action-btn:focus {\n\toutline: 2px solid var(--sc-focus-cell-outline);\n\toutline-offset: 1px;\n}\n\n.row-action-btn .action-icon {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 1rem;\n\theight: 1rem;\n}\n\n.row-action-btn .action-icon svg {\n\twidth: 100%;\n\theight: 100%;\n}\n\n/* Dropdown mode styles */\n.row-actions-dropdown {\n\tposition: relative;\n\tdisplay: inline-block;\n}\n.row-actions-dropdown:has(button:focus) {\n\toutline: 2px solid var(--sc-focus-cell-outline);\n\toutline-offset: -2px;\n}\n\n.row-actions-toggle {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 1.5rem;\n\theight: 1.5rem;\n\tpadding: 0;\n\tborder: none;\n\tbackground: transparent;\n\tcursor: pointer;\n\tborder-radius: 0.25rem;\n\tfont-size: 1rem;\n\tfont-weight: bold;\n\ttransition: background-color 0.15s ease;\n}\n\n.row-actions-toggle:hover {\n\tbackground-color: var(--sc-gray-10);\n}\n\n.row-actions-toggle:focus {\n\t/* outline: 2px solid var(--sc-focus-cell-outline);\n\toutline-offset: 1px; */\n}\n\n.dropdown-icon {\n\tline-height: 1;\n}\n\n.row-actions-menu {\n\tposition: fixed;\n\tz-index: 100;\n\tmin-width: 10rem;\n\tpadding: 0.25rem 0;\n\tbackground: var(--sc-overlay-background);\n\tborder: 1px solid var(--sc-row-border-color);\n\tborder-left: 4px solid var(--sc-row-border-color);\n\tborder-radius: 0;\n}\n\n.row-actions-menu.menu-flipped {\n\tbox-shadow:\n\t\t0 -4px 6px -1px rgb(0 0 0 / 0.1),\n\t\t0 -2px 4px -2px rgb(0 0 0 / 0.1);\n}\n\n.row-action-menu-item {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 0.5rem;\n\twidth: 100%;\n\tpadding: 0.5rem 0.75rem;\n\tborder: none;\n\tbackground: transparent;\n\tcursor: pointer;\n\ttext-align: left;\n\tfont-size: 0.875rem;\n\ttransition: background-color 0.15s ease;\n}\n\n.row-action-menu-item:hover {\n\tbackground-color: var(--sc-gray-10);\n}\n\n.row-action-menu-item:focus {\n\toutline: none;\n\tbackground-color: var(--sc-gray-10);\n}\n\n.row-action-menu-item:disabled,\n.row-action-btn:disabled {\n\topacity: 0.4;\n\tcursor: not-allowed;\n}\n\n.row-action-menu-item:disabled:hover,\n.row-action-btn:disabled:hover {\n\tbackground-color: transparent;\n}\n\n.row-action-menu-item .action-icon {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 1rem;\n\theight: 1rem;\n\tflex-shrink: 0;\n}\n\n.row-action-menu-item .action-icon svg {\n\twidth: 100%;\n\theight: 100%;\n}\n\n.row-action-menu-item .action-label {\n\tflex: 1;\n}\n</style>\n","<template>\n\t<td\n\t\tref=\"actionsCell\"\n\t\tclass=\"atable-row-actions\"\n\t\t:class=\"{ 'sticky-column': position === 'before-index', 'dropdown-active': dropdownOpen }\">\n\t\t<!-- Dropdown mode -->\n\t\t<div v-if=\"showDropdown\" class=\"row-actions-dropdown\">\n\t\t\t<button\n\t\t\t\tref=\"toggleButton\"\n\t\t\t\ttype=\"button\"\n\t\t\t\tclass=\"row-actions-toggle\"\n\t\t\t\t:aria-expanded=\"dropdownOpen\"\n\t\t\t\taria-haspopup=\"true\"\n\t\t\t\t@click.stop=\"toggleDropdown\">\n\t\t\t\t<span class=\"dropdown-icon\">⋮</span>\n\t\t\t</button>\n\t\t\t<div\n\t\t\t\tv-show=\"dropdownOpen\"\n\t\t\t\tclass=\"row-actions-menu\"\n\t\t\t\t:class=\"{ 'menu-flipped': dropdownFlipped }\"\n\t\t\t\t:style=\"menuStyle\"\n\t\t\t\trole=\"menu\">\n\t\t\t\t<button\n\t\t\t\t\tv-for=\"action in enabledActions\"\n\t\t\t\t\t:key=\"action.type\"\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"row-action-menu-item\"\n\t\t\t\t\trole=\"menuitem\"\n\t\t\t\t\t:disabled=\"action.disabled\"\n\t\t\t\t\t@click.stop=\"executeAction(action.type, $event)\">\n\t\t\t\t\t<span class=\"action-icon\" v-html=\"action.icon\" />\n\t\t\t\t\t<span class=\"action-label\">{{ action.label }}</span>\n\t\t\t\t</button>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<!-- Icon mode -->\n\t\t<div v-else class=\"row-actions-icons\">\n\t\t\t<button\n\t\t\t\tv-for=\"action in enabledActions\"\n\t\t\t\t:key=\"action.type\"\n\t\t\t\ttype=\"button\"\n\t\t\t\tclass=\"row-action-btn\"\n\t\t\t\t:title=\"action.label\"\n\t\t\t\t:aria-label=\"action.label\"\n\t\t\t\t:disabled=\"action.disabled\"\n\t\t\t\t@click.stop=\"executeAction(action.type, $event)\">\n\t\t\t\t<span class=\"action-icon\" v-html=\"action.icon\" />\n\t\t\t</button>\n\t\t</div>\n\t</td>\n</template>\n\n<script setup lang=\"ts\">\nimport { useResizeObserver, onClickOutside } from '@vueuse/core'\nimport { computed, ref, useTemplateRef } from 'vue'\n\nimport { actionIcons } from '../icons'\nimport { createTableStore } from '../stores/table'\nimport type { RowActionsConfig, RowActionType } from '../types'\n\nconst props = defineProps<{\n\trowIndex: number\n\tstore: ReturnType<typeof createTableStore>\n\tconfig: RowActionsConfig\n\tposition?: 'before-index' | 'after-index' | 'end'\n}>()\n\nconst emit = defineEmits<{\n\taction: [type: RowActionType, rowIndex: number, event?: MouseEvent]\n}>()\n\nconst actionsCellRef = useTemplateRef<HTMLTableCellElement>('actionsCell')\nconst toggleButtonRef = useTemplateRef<HTMLButtonElement>('toggleButton')\nconst cellWidth = ref(0)\nconst dropdownOpen = ref(false)\nconst dropdownFlipped = ref(false)\nconst menuPosition = ref({ top: 0, left: 0 })\n\n// Default labels for actions\nconst defaultLabels: Record<RowActionType, string> = {\n\tadd: 'Add Record',\n\tdelete: 'Delete Record',\n\tduplicate: 'Duplicate Record',\n\tinsertAbove: 'Insert Above',\n\tinsertBelow: 'Insert Below',\n\tmove: 'Move Record',\n\tmoveUp: 'Move Up',\n\tmoveDown: 'Move Down',\n\topen: 'Open Record',\n}\n\n// Determine which actions are enabled\nconst enabledActions = computed(() => {\n\tconst actions: Array<{ type: RowActionType; label: string; icon: string; disabled: boolean }> = []\n\tconst configActions = props.config.actions || {}\n\n\tconst actionTypes: RowActionType[] = [\n\t\t'open',\n\t\t'moveUp',\n\t\t'moveDown',\n\t\t'duplicate',\n\t\t'insertAbove',\n\t\t'insertBelow',\n\t\t'add',\n\t\t'delete',\n\t\t'move',\n\t]\n\n\tfor (const type of actionTypes) {\n\t\tconst actionConfig = configActions[type]\n\n\t\t// Skip if explicitly disabled\n\t\tif (actionConfig === false) continue\n\n\t\t// Skip if not configured and we're being explicit\n\t\tif (actionConfig === undefined) continue\n\n\t\tlet enabled = true\n\t\tlet label = defaultLabels[type]\n\t\tlet icon = actionIcons[type]\n\t\tlet disabled = false\n\n\t\tif (typeof actionConfig === 'object') {\n\t\t\tenabled = actionConfig.enabled !== false\n\t\t\tlabel = actionConfig.label || label\n\t\t\ticon = actionConfig.icon || icon\n\t\t\t// Per-row predicate; reading store state here keeps this computed reactive to row changes.\n\t\t\tif (actionConfig.disabled) disabled = actionConfig.disabled(props.rowIndex, props.store)\n\t\t}\n\n\t\tif (enabled) {\n\t\t\tactions.push({ type, label, icon, disabled })\n\t\t}\n\t}\n\n\treturn actions\n})\n\n// Determine if we should show dropdown mode\nconst showDropdown = computed(() => {\n\tif (props.config.forceDropdown) return true\n\n\tconst threshold = props.config.dropdownThreshold ?? 150\n\tif (threshold === 0) return false\n\n\treturn cellWidth.value > 0 && cellWidth.value < threshold\n})\n\n// Compute menu style for fixed positioning\nconst menuStyle = computed(() => {\n\tif (!dropdownOpen.value) return {}\n\n\tif (dropdownFlipped.value) {\n\t\treturn {\n\t\t\tposition: 'fixed' as const,\n\t\t\tbottom: `${window.innerHeight - menuPosition.value.top}px`,\n\t\t\tleft: `${menuPosition.value.left}px`,\n\t\t\ttop: 'auto',\n\t\t}\n\t}\n\treturn {\n\t\tposition: 'fixed' as const,\n\t\ttop: `${menuPosition.value.top}px`,\n\t\tleft: `${menuPosition.value.left}px`,\n\t}\n})\n\n// Track cell width for responsive behavior\nuseResizeObserver(actionsCellRef, entries => {\n\tconst entry = entries[0]\n\tif (entry) {\n\t\tcellWidth.value = entry.contentRect.width\n\t}\n})\n\n// Toggle dropdown menu\nconst toggleDropdown = () => {\n\tif (!dropdownOpen.value) {\n\t\t// Opening - check if we need to flip\n\t\tcheckDropdownPosition()\n\t}\n\tdropdownOpen.value = !dropdownOpen.value\n}\n\n// Check if dropdown should flip upward and calculate position\nconst checkDropdownPosition = () => {\n\tif (!toggleButtonRef.value) return\n\n\tconst buttonRect = toggleButtonRef.value.getBoundingClientRect()\n\tconst viewportHeight = window.innerHeight\n\tconst viewportWidth = window.innerWidth\n\tconst estimatedMenuHeight = enabledActions.value.length * 40 + 16 // ~40px per item + padding\n\tconst estimatedMenuWidth = 160 // matches min-width: 10rem\n\n\t// Check if menu would extend beyond viewport bottom\n\tconst spaceBelow = viewportHeight - buttonRect.bottom\n\tconst spaceAbove = buttonRect.top\n\n\t// Flip if not enough space below but enough space above\n\tdropdownFlipped.value = spaceBelow < estimatedMenuHeight && spaceAbove > estimatedMenuHeight\n\n\t// Horizontal: anchor the menu's left edge to the button, but right-align it to the button when\n\t// it would overflow the viewport's right edge (e.g. an end-positioned actions column).\n\tlet left = buttonRect.left\n\tif (left + estimatedMenuWidth > viewportWidth) {\n\t\tleft = Math.max(0, buttonRect.right - estimatedMenuWidth)\n\t}\n\n\t// Calculate fixed position\n\tmenuPosition.value = {\n\t\ttop: dropdownFlipped.value ? buttonRect.top : buttonRect.bottom,\n\t\tleft,\n\t}\n}\n\nonClickOutside(actionsCellRef, () => {\n\tdropdownOpen.value = false\n})\n\n// Execute an action\nconst executeAction = (actionType: RowActionType, event?: MouseEvent) => {\n\tdropdownOpen.value = false\n\n\t// Check for custom handler\n\tconst actionConfig = props.config.actions?.[actionType]\n\tif (typeof actionConfig === 'object' && actionConfig.handler) {\n\t\tconst result = actionConfig.handler(props.rowIndex, props.store)\n\t\tif (result === false) {\n\t\t\t// Handler returned false, don't proceed with default behavior\n\t\t\treturn\n\t\t}\n\t}\n\n\t// Emit the action event for parent to handle\n\temit('action', actionType, props.rowIndex, event)\n}\n</script>\n\n<style>\n.atable-row-actions {\n\twidth: 2rem;\n\tmin-width: 2rem;\n\tpadding: 0 0.25rem;\n\tvertical-align: middle;\n\twhite-space: nowrap;\n\tborder-top: 1px solid var(--sc-row-border-color);\n\tbackground: inherit;\n\tuser-select: none;\n\tposition: relative;\n}\n\n.atable-row-actions.dropdown-active {\n\tz-index: 101;\n}\n\n.row-actions-icons {\n\tdisplay: flex;\n\tgap: 0.25rem;\n\talign-items: center;\n\tjustify-content: center;\n}\n\n.row-action-btn {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 1.5rem;\n\theight: 1.5rem;\n\tpadding: 0.125rem;\n\tborder: none;\n\tbackground: transparent;\n\tcursor: pointer;\n\tborder-radius: 0.25rem;\n\ttransition: background-color 0.15s ease;\n}\n\n.row-action-btn:hover {\n\tbackground-color: var(--sc-gray-10);\n}\n\n.row-action-btn:focus {\n\toutline: 2px solid var(--sc-focus-cell-outline);\n\toutline-offset: 1px;\n}\n\n.row-action-btn .action-icon {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 1rem;\n\theight: 1rem;\n}\n\n.row-action-btn .action-icon svg {\n\twidth: 100%;\n\theight: 100%;\n}\n\n/* Dropdown mode styles */\n.row-actions-dropdown {\n\tposition: relative;\n\tdisplay: inline-block;\n}\n.row-actions-dropdown:has(button:focus) {\n\toutline: 2px solid var(--sc-focus-cell-outline);\n\toutline-offset: -2px;\n}\n\n.row-actions-toggle {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 1.5rem;\n\theight: 1.5rem;\n\tpadding: 0;\n\tborder: none;\n\tbackground: transparent;\n\tcursor: pointer;\n\tborder-radius: 0.25rem;\n\tfont-size: 1rem;\n\tfont-weight: bold;\n\ttransition: background-color 0.15s ease;\n}\n\n.row-actions-toggle:hover {\n\tbackground-color: var(--sc-gray-10);\n}\n\n.row-actions-toggle:focus {\n\t/* outline: 2px solid var(--sc-focus-cell-outline);\n\toutline-offset: 1px; */\n}\n\n.dropdown-icon {\n\tline-height: 1;\n}\n\n.row-actions-menu {\n\tposition: fixed;\n\tz-index: 100;\n\tmin-width: 10rem;\n\tpadding: 0.25rem 0;\n\tbackground: var(--sc-overlay-background);\n\tborder: 1px solid var(--sc-row-border-color);\n\tborder-left: 4px solid var(--sc-row-border-color);\n\tborder-radius: 0;\n}\n\n.row-actions-menu.menu-flipped {\n\tbox-shadow:\n\t\t0 -4px 6px -1px rgb(0 0 0 / 0.1),\n\t\t0 -2px 4px -2px rgb(0 0 0 / 0.1);\n}\n\n.row-action-menu-item {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 0.5rem;\n\twidth: 100%;\n\tpadding: 0.5rem 0.75rem;\n\tborder: none;\n\tbackground: transparent;\n\tcursor: pointer;\n\ttext-align: left;\n\tfont-size: 0.875rem;\n\ttransition: background-color 0.15s ease;\n}\n\n.row-action-menu-item:hover {\n\tbackground-color: var(--sc-gray-10);\n}\n\n.row-action-menu-item:focus {\n\toutline: none;\n\tbackground-color: var(--sc-gray-10);\n}\n\n.row-action-menu-item:disabled,\n.row-action-btn:disabled {\n\topacity: 0.4;\n\tcursor: not-allowed;\n}\n\n.row-action-menu-item:disabled:hover,\n.row-action-btn:disabled:hover {\n\tbackground-color: transparent;\n}\n\n.row-action-menu-item .action-icon {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 1rem;\n\theight: 1rem;\n\tflex-shrink: 0;\n}\n\n.row-action-menu-item .action-icon svg {\n\twidth: 100%;\n\theight: 100%;\n}\n\n.row-action-menu-item .action-label {\n\tflex: 1;\n}\n</style>\n","<template>\n\t<tr\n\t\tv-show=\"isRowVisible\"\n\t\tv-bind=\"$attrs\"\n\t\tref=\"rowEl\"\n\t\t:tabindex=\"tabIndex\"\n\t\tclass=\"atable-row\"\n\t\t:class=\"{ 'atable-row-clickable': isClickable }\"\n\t\t@click=\"onRowClick\">\n\t\t<!-- Row actions before index (default position) -->\n\t\t<ARowActions\n\t\t\tv-if=\"showRowActions && actionsPosition === 'before-index'\"\n\t\t\t:row-index=\"rowIndex\"\n\t\t\t:store=\"store\"\n\t\t\t:config=\"rowActionsConfig\"\n\t\t\t:position=\"actionsPosition\"\n\t\t\t@action=\"onRowAction\" />\n\n\t\t<!-- render numbered/tree view index; skip render for uncounted lists -->\n\t\t<slot v-if=\"store.config.view !== 'uncounted'\" name=\"index\">\n\t\t\t<td\n\t\t\t\tv-if=\"store.config.view === 'list'\"\n\t\t\t\t:tabIndex=\"-1\"\n\t\t\t\tclass=\"list-index\"\n\t\t\t\t:class=\"store.hasPinnedColumns ? 'sticky-index' : ''\">\n\t\t\t\t{{ rowIndex + 1 }}\n\t\t\t</td>\n\t\t\t<td\n\t\t\t\tv-else-if=\"store.isTreeView\"\n\t\t\t\t:tabIndex=\"-1\"\n\t\t\t\tclass=\"tree-index\"\n\t\t\t\t:class=\"store.hasPinnedColumns ? 'sticky-index' : ''\"\n\t\t\t\t@click=\"store.toggleRowExpand(rowIndex)\">\n\t\t\t\t{{ rowExpandSymbol }}\n\t\t\t</td>\n\t\t\t<td\n\t\t\t\tv-else-if=\"store.config.view === 'list-expansion'\"\n\t\t\t\t:tabIndex=\"-1\"\n\t\t\t\tclass=\"expansion-index\"\n\t\t\t\t:class=\"store.hasPinnedColumns ? 'sticky-index' : ''\"\n\t\t\t\t@click=\"store.toggleRowExpand(rowIndex)\">\n\t\t\t\t{{ rowExpandSymbol }}\n\t\t\t</td>\n\t\t</slot>\n\n\t\t<!-- Row actions after index -->\n\t\t<ARowActions\n\t\t\tv-if=\"showRowActions && actionsPosition === 'after-index'\"\n\t\t\t:row-index=\"rowIndex\"\n\t\t\t:store=\"store\"\n\t\t\t:config=\"rowActionsConfig\"\n\t\t\t:position=\"actionsPosition\"\n\t\t\t@action=\"onRowAction\" />\n\n\t\t<!-- render cell content -->\n\t\t<slot></slot>\n\n\t\t<!-- Row actions at end -->\n\t\t<ARowActions\n\t\t\tv-if=\"showRowActions && actionsPosition === 'end'\"\n\t\t\t:row-index=\"rowIndex\"\n\t\t\t:store=\"store\"\n\t\t\t:config=\"rowActionsConfig\"\n\t\t\t:position=\"actionsPosition\"\n\t\t\t@action=\"onRowAction\" />\n\t</tr>\n\n\t<!-- list-expansion content panel: a second row spanning the whole width -->\n\t<tr v-if=\"isExpanded\" :tabindex=\"tabIndex\" class=\"atable-expanded-row\">\n\t\t<td :tabIndex=\"-1\" :colspan=\"expandedColspan\" class=\"atable-expanded-content\">\n\t\t\t<slot name=\"content\" :row=\"store.rows[rowIndex]\" :row-index=\"rowIndex\" :store=\"store\" />\n\t\t</td>\n\t</tr>\n</template>\n\n<script setup lang=\"ts\">\nimport { type KeypressHandlers, useKeyboardNav, defaultKeypressHandlers } from '@stonecrop/utilities'\nimport { computed, useTemplateRef } from 'vue'\n\nimport ARowActions from './ARowActions.vue'\nimport { createTableStore } from '../stores/table'\nimport type { RowActionsConfig, RowActionType } from '../types'\n\nconst {\n\trowIndex,\n\tstore,\n\ttabIndex = -1,\n\taddNavigation = false, // default to allowing cell navigation\n} = defineProps<{\n\trowIndex: number\n\tstore: ReturnType<typeof createTableStore>\n\ttabIndex?: number\n\taddNavigation?: boolean | KeypressHandlers\n}>()\n\nconst emit = defineEmits<{\n\t'row:action': [type: RowActionType, rowIndex: number, event?: MouseEvent]\n\t'row:click': [rowIndex: number, event: MouseEvent]\n}>()\n\nconst rowRef = useTemplateRef<HTMLTableRowElement>('rowEl')\n\nconst isRowVisible = computed(() => store.isRowVisible(rowIndex))\nconst rowExpandSymbol = computed(() => store.getRowExpandSymbol(rowIndex))\nconst isClickable = computed(() => store.config.clickable ?? false)\n\n// Row actions configuration\nconst rowActionsConfig = computed((): RowActionsConfig => {\n\treturn store.config.rowActions || { enabled: false }\n})\n\nconst showRowActions = computed(() => {\n\treturn rowActionsConfig.value.enabled\n})\n\nconst actionsPosition = computed(() => {\n\treturn rowActionsConfig.value.position || 'before-index'\n})\n\n// list-expansion: this row owns an expandable content panel (a second <tr>).\nconst isExpanded = computed(() => store.config.view === 'list-expansion' && Boolean(store.display[rowIndex]?.expanded))\n\n// The content panel spans every column the main row occupies: data columns + the\n// index/chevron column (absent only in uncounted) + the row-actions column when enabled.\nconst expandedColspan = computed(() => {\n\tconst indexCol = store.config.view === 'uncounted' ? 0 : 1\n\tconst actionsCol = showRowActions.value ? 1 : 0\n\treturn store.columns.length + indexCol + actionsCol\n})\n\nconst onRowAction = (actionType: RowActionType, index: number, event?: MouseEvent) => {\n\temit('row:action', actionType, index, event)\n}\n\nconst onRowClick = (event: MouseEvent) => {\n\t// Ignore clicks on the row actions cell or an expand/collapse chevron (tree or list-expansion),\n\t// so toggling a chevron never doubles as a row-click navigation.\n\tconst target = event.target as HTMLElement\n\tif (target.closest('.atable-row-actions') || target.closest('.tree-index') || target.closest('.expansion-index'))\n\t\treturn\n\temit('row:click', rowIndex, event)\n}\n\n// A list-expansion row always binds Ctrl+G to toggle its own panel while opt-in\n// cell navigation stays gated on `addNavigation` (default off), so other view\n// types are unchanged.\nconst isListExpansion = store.config.view === 'list-expansion'\n\nif (addNavigation || isListExpansion) {\n\tlet handlers: KeypressHandlers = {}\n\n\tif (addNavigation === true) {\n\t\thandlers = { ...defaultKeypressHandlers }\n\t} else if (typeof addNavigation === 'object') {\n\t\thandlers = { ...defaultKeypressHandlers, ...addNavigation }\n\t}\n\n\tif (isListExpansion && !handlers['keydown.control.g']) {\n\t\thandlers['keydown.control.g'] = (event: KeyboardEvent) => {\n\t\t\tevent.stopPropagation()\n\t\t\tevent.preventDefault()\n\t\t\tstore.toggleRowExpand(rowIndex)\n\t\t}\n\t}\n\n\tuseKeyboardNav([\n\t\t{\n\t\t\tselectors: rowRef,\n\t\t\thandlers: handlers,\n\t\t},\n\t])\n}\n</script>\n\n<style>\n.atable-row {\n\tbackground-color: var(--sc-cell-background);\n}\n\n.atable--zebra tbody .atable-row:nth-child(odd) {\n\tbackground-color: var(--sc-row-color-zebra-light);\n}\n\n.atable--zebra tbody .atable-row:nth-child(even) {\n\tbackground-color: var(--sc-row-color-zebra-dark);\n}\n\n.atable--zebra tbody .atable-row:nth-child(odd) > td {\n\tbackground-color: var(--sc-row-color-zebra-light);\n}\n\n.atable--zebra tbody .atable-row:nth-child(even) > td {\n\tbackground-color: var(--sc-row-color-zebra-dark);\n}\n\n.atable--zebra tbody .atable-row > td:focus,\n.atable--zebra tbody .atable-row > td:focus-within {\n\tbackground-color: var(--sc-focus-cell-background);\n}\n\n.atable-row-clickable {\n\tcursor: pointer;\n}\n\n.atable-row-clickable:hover > td {\n\tbackground-color: var(--sc-row-hover-color);\n}\n\n.atable-row:last-child > td {\n\tborder-bottom: 1px solid var(--sc-row-border-color);\n}\n\n.atable-row > td:first-child {\n\tborder-left: 4px solid var(--sc-row-border-color);\n}\n\n.atable-row > td:last-child {\n\tborder-right: 1px solid var(--sc-row-border-color);\n}\n\n.list-index {\n\tcolor: var(--sc-header-text-color);\n\tfont-weight: bold;\n\tpadding-left: var(--sc-atable-row-padding);\n\tpadding-right: 0.5em;\n\ttext-align: left;\n\tuser-select: none;\n\t/* width: 7ch; */\n\tborder-top: 1px solid var(--sc-row-border-color);\n\ttext-overflow: ellipsis;\n\toverflow: hidden;\n\tbox-sizing: border-box;\n\tpadding-top: var(--sc-atable-row-padding);\n\tpadding-bottom: var(--sc-atable-row-padding);\n}\n\n.tree-index,\n.expansion-index {\n\tcolor: var(--sc-header-text-color);\n\tfont-weight: bold;\n\ttext-align: center;\n\tuser-select: none;\n\twidth: 2ch;\n\tbox-sizing: border-box;\n\tcursor: pointer;\n\tpadding-top: var(--sc-atable-row-padding);\n\tpadding-bottom: var(--sc-atable-row-padding);\n}\n\n.expansion-index {\n\tborder-top: 1px solid var(--sc-row-border-color);\n}\n\n.atable-expanded-content {\n\tbox-sizing: border-box;\n\twidth: 100%;\n\tborder-top: 1px solid var(--sc-row-border-color);\n\tborder-right: 1px solid var(--sc-row-border-color);\n\tborder-bottom: 1px solid var(--sc-row-border-color);\n\tborder-left: 4px solid var(--sc-row-border-color);\n\tpadding: 1.5rem;\n}\n\n.atable-expanded-content > * {\n\tdisplay: block;\n\twidth: 100%;\n\tmax-width: 100%;\n\tbox-sizing: border-box;\n}\n/* sticky cells in modified rows should be a solid color to properly hide non-sticky cells */\n.atable-row:has(td.cell-modified) > td.sticky-column,\n.atable-row:has(td.cell-modified) > th.sticky-column,\n.atable-row:has(td.cell-modified) > td.sticky-index,\n.atable-row:has(td.cell-modified) > th.sticky-index {\n\tbackground: var(--sc-cell-changed-color);\n}\n</style>\n<style scoped>\n.atable-row.changed-row-gradient:has(td.cell-modified) {\n\t--cell-color-start: color-mix(in srgb, var(--sc-cell-changed-color), var(--sc-gray-5) 20%);\n\t--cell-color-end: color-mix(in srgb, var(--sc-cell-changed-color), var(--sc-gray-5) 60%);\n\tbackground: linear-gradient(90deg, var(--cell-color-start), var(--cell-color-end));\n}\n</style>\n","<template>\n\t<tr\n\t\tv-show=\"isRowVisible\"\n\t\tv-bind=\"$attrs\"\n\t\tref=\"rowEl\"\n\t\t:tabindex=\"tabIndex\"\n\t\tclass=\"atable-row\"\n\t\t:class=\"{ 'atable-row-clickable': isClickable }\"\n\t\t@click=\"onRowClick\">\n\t\t<!-- Row actions before index (default position) -->\n\t\t<ARowActions\n\t\t\tv-if=\"showRowActions && actionsPosition === 'before-index'\"\n\t\t\t:row-index=\"rowIndex\"\n\t\t\t:store=\"store\"\n\t\t\t:config=\"rowActionsConfig\"\n\t\t\t:position=\"actionsPosition\"\n\t\t\t@action=\"onRowAction\" />\n\n\t\t<!-- render numbered/tree view index; skip render for uncounted lists -->\n\t\t<slot v-if=\"store.config.view !== 'uncounted'\" name=\"index\">\n\t\t\t<td\n\t\t\t\tv-if=\"store.config.view === 'list'\"\n\t\t\t\t:tabIndex=\"-1\"\n\t\t\t\tclass=\"list-index\"\n\t\t\t\t:class=\"store.hasPinnedColumns ? 'sticky-index' : ''\">\n\t\t\t\t{{ rowIndex + 1 }}\n\t\t\t</td>\n\t\t\t<td\n\t\t\t\tv-else-if=\"store.isTreeView\"\n\t\t\t\t:tabIndex=\"-1\"\n\t\t\t\tclass=\"tree-index\"\n\t\t\t\t:class=\"store.hasPinnedColumns ? 'sticky-index' : ''\"\n\t\t\t\t@click=\"store.toggleRowExpand(rowIndex)\">\n\t\t\t\t{{ rowExpandSymbol }}\n\t\t\t</td>\n\t\t\t<td\n\t\t\t\tv-else-if=\"store.config.view === 'list-expansion'\"\n\t\t\t\t:tabIndex=\"-1\"\n\t\t\t\tclass=\"expansion-index\"\n\t\t\t\t:class=\"store.hasPinnedColumns ? 'sticky-index' : ''\"\n\t\t\t\t@click=\"store.toggleRowExpand(rowIndex)\">\n\t\t\t\t{{ rowExpandSymbol }}\n\t\t\t</td>\n\t\t</slot>\n\n\t\t<!-- Row actions after index -->\n\t\t<ARowActions\n\t\t\tv-if=\"showRowActions && actionsPosition === 'after-index'\"\n\t\t\t:row-index=\"rowIndex\"\n\t\t\t:store=\"store\"\n\t\t\t:config=\"rowActionsConfig\"\n\t\t\t:position=\"actionsPosition\"\n\t\t\t@action=\"onRowAction\" />\n\n\t\t<!-- render cell content -->\n\t\t<slot></slot>\n\n\t\t<!-- Row actions at end -->\n\t\t<ARowActions\n\t\t\tv-if=\"showRowActions && actionsPosition === 'end'\"\n\t\t\t:row-index=\"rowIndex\"\n\t\t\t:store=\"store\"\n\t\t\t:config=\"rowActionsConfig\"\n\t\t\t:position=\"actionsPosition\"\n\t\t\t@action=\"onRowAction\" />\n\t</tr>\n\n\t<!-- list-expansion content panel: a second row spanning the whole width -->\n\t<tr v-if=\"isExpanded\" :tabindex=\"tabIndex\" class=\"atable-expanded-row\">\n\t\t<td :tabIndex=\"-1\" :colspan=\"expandedColspan\" class=\"atable-expanded-content\">\n\t\t\t<slot name=\"content\" :row=\"store.rows[rowIndex]\" :row-index=\"rowIndex\" :store=\"store\" />\n\t\t</td>\n\t</tr>\n</template>\n\n<script setup lang=\"ts\">\nimport { type KeypressHandlers, useKeyboardNav, defaultKeypressHandlers } from '@stonecrop/utilities'\nimport { computed, useTemplateRef } from 'vue'\n\nimport ARowActions from './ARowActions.vue'\nimport { createTableStore } from '../stores/table'\nimport type { RowActionsConfig, RowActionType } from '../types'\n\nconst {\n\trowIndex,\n\tstore,\n\ttabIndex = -1,\n\taddNavigation = false, // default to allowing cell navigation\n} = defineProps<{\n\trowIndex: number\n\tstore: ReturnType<typeof createTableStore>\n\ttabIndex?: number\n\taddNavigation?: boolean | KeypressHandlers\n}>()\n\nconst emit = defineEmits<{\n\t'row:action': [type: RowActionType, rowIndex: number, event?: MouseEvent]\n\t'row:click': [rowIndex: number, event: MouseEvent]\n}>()\n\nconst rowRef = useTemplateRef<HTMLTableRowElement>('rowEl')\n\nconst isRowVisible = computed(() => store.isRowVisible(rowIndex))\nconst rowExpandSymbol = computed(() => store.getRowExpandSymbol(rowIndex))\nconst isClickable = computed(() => store.config.clickable ?? false)\n\n// Row actions configuration\nconst rowActionsConfig = computed((): RowActionsConfig => {\n\treturn store.config.rowActions || { enabled: false }\n})\n\nconst showRowActions = computed(() => {\n\treturn rowActionsConfig.value.enabled\n})\n\nconst actionsPosition = computed(() => {\n\treturn rowActionsConfig.value.position || 'before-index'\n})\n\n// list-expansion: this row owns an expandable content panel (a second <tr>).\nconst isExpanded = computed(() => store.config.view === 'list-expansion' && Boolean(store.display[rowIndex]?.expanded))\n\n// The content panel spans every column the main row occupies: data columns + the\n// index/chevron column (absent only in uncounted) + the row-actions column when enabled.\nconst expandedColspan = computed(() => {\n\tconst indexCol = store.config.view === 'uncounted' ? 0 : 1\n\tconst actionsCol = showRowActions.value ? 1 : 0\n\treturn store.columns.length + indexCol + actionsCol\n})\n\nconst onRowAction = (actionType: RowActionType, index: number, event?: MouseEvent) => {\n\temit('row:action', actionType, index, event)\n}\n\nconst onRowClick = (event: MouseEvent) => {\n\t// Ignore clicks on the row actions cell or an expand/collapse chevron (tree or list-expansion),\n\t// so toggling a chevron never doubles as a row-click navigation.\n\tconst target = event.target as HTMLElement\n\tif (target.closest('.atable-row-actions') || target.closest('.tree-index') || target.closest('.expansion-index'))\n\t\treturn\n\temit('row:click', rowIndex, event)\n}\n\n// A list-expansion row always binds Ctrl+G to toggle its own panel while opt-in\n// cell navigation stays gated on `addNavigation` (default off), so other view\n// types are unchanged.\nconst isListExpansion = store.config.view === 'list-expansion'\n\nif (addNavigation || isListExpansion) {\n\tlet handlers: KeypressHandlers = {}\n\n\tif (addNavigation === true) {\n\t\thandlers = { ...defaultKeypressHandlers }\n\t} else if (typeof addNavigation === 'object') {\n\t\thandlers = { ...defaultKeypressHandlers, ...addNavigation }\n\t}\n\n\tif (isListExpansion && !handlers['keydown.control.g']) {\n\t\thandlers['keydown.control.g'] = (event: KeyboardEvent) => {\n\t\t\tevent.stopPropagation()\n\t\t\tevent.preventDefault()\n\t\t\tstore.toggleRowExpand(rowIndex)\n\t\t}\n\t}\n\n\tuseKeyboardNav([\n\t\t{\n\t\t\tselectors: rowRef,\n\t\t\thandlers: handlers,\n\t\t},\n\t])\n}\n</script>\n\n<style>\n.atable-row {\n\tbackground-color: var(--sc-cell-background);\n}\n\n.atable--zebra tbody .atable-row:nth-child(odd) {\n\tbackground-color: var(--sc-row-color-zebra-light);\n}\n\n.atable--zebra tbody .atable-row:nth-child(even) {\n\tbackground-color: var(--sc-row-color-zebra-dark);\n}\n\n.atable--zebra tbody .atable-row:nth-child(odd) > td {\n\tbackground-color: var(--sc-row-color-zebra-light);\n}\n\n.atable--zebra tbody .atable-row:nth-child(even) > td {\n\tbackground-color: var(--sc-row-color-zebra-dark);\n}\n\n.atable--zebra tbody .atable-row > td:focus,\n.atable--zebra tbody .atable-row > td:focus-within {\n\tbackground-color: var(--sc-focus-cell-background);\n}\n\n.atable-row-clickable {\n\tcursor: pointer;\n}\n\n.atable-row-clickable:hover > td {\n\tbackground-color: var(--sc-row-hover-color);\n}\n\n.atable-row:last-child > td {\n\tborder-bottom: 1px solid var(--sc-row-border-color);\n}\n\n.atable-row > td:first-child {\n\tborder-left: 4px solid var(--sc-row-border-color);\n}\n\n.atable-row > td:last-child {\n\tborder-right: 1px solid var(--sc-row-border-color);\n}\n\n.list-index {\n\tcolor: var(--sc-header-text-color);\n\tfont-weight: bold;\n\tpadding-left: var(--sc-atable-row-padding);\n\tpadding-right: 0.5em;\n\ttext-align: left;\n\tuser-select: none;\n\t/* width: 7ch; */\n\tborder-top: 1px solid var(--sc-row-border-color);\n\ttext-overflow: ellipsis;\n\toverflow: hidden;\n\tbox-sizing: border-box;\n\tpadding-top: var(--sc-atable-row-padding);\n\tpadding-bottom: var(--sc-atable-row-padding);\n}\n\n.tree-index,\n.expansion-index {\n\tcolor: var(--sc-header-text-color);\n\tfont-weight: bold;\n\ttext-align: center;\n\tuser-select: none;\n\twidth: 2ch;\n\tbox-sizing: border-box;\n\tcursor: pointer;\n\tpadding-top: var(--sc-atable-row-padding);\n\tpadding-bottom: var(--sc-atable-row-padding);\n}\n\n.expansion-index {\n\tborder-top: 1px solid var(--sc-row-border-color);\n}\n\n.atable-expanded-content {\n\tbox-sizing: border-box;\n\twidth: 100%;\n\tborder-top: 1px solid var(--sc-row-border-color);\n\tborder-right: 1px solid var(--sc-row-border-color);\n\tborder-bottom: 1px solid var(--sc-row-border-color);\n\tborder-left: 4px solid var(--sc-row-border-color);\n\tpadding: 1.5rem;\n}\n\n.atable-expanded-content > * {\n\tdisplay: block;\n\twidth: 100%;\n\tmax-width: 100%;\n\tbox-sizing: border-box;\n}\n/* sticky cells in modified rows should be a solid color to properly hide non-sticky cells */\n.atable-row:has(td.cell-modified) > td.sticky-column,\n.atable-row:has(td.cell-modified) > th.sticky-column,\n.atable-row:has(td.cell-modified) > td.sticky-index,\n.atable-row:has(td.cell-modified) > th.sticky-index {\n\tbackground: var(--sc-cell-changed-color);\n}\n</style>\n<style scoped>\n.atable-row.changed-row-gradient:has(td.cell-modified) {\n\t--cell-color-start: color-mix(in srgb, var(--sc-cell-changed-color), var(--sc-gray-5) 20%);\n\t--cell-color-end: color-mix(in srgb, var(--sc-cell-changed-color), var(--sc-gray-5) 60%);\n\tbackground: linear-gradient(90deg, var(--cell-color-start), var(--cell-color-end));\n}\n</style>\n","<template>\n\t<div class=\"gantt-connection-overlay\">\n\t\t<svg\n\t\t\tclass=\"connection-svg\"\n\t\t\t:style=\"{\n\t\t\t\tposition: 'absolute',\n\t\t\t\ttop: 0,\n\t\t\t\tleft: 0,\n\t\t\t\twidth: '100%',\n\t\t\t\theight: '100%',\n\t\t\t\tpointerEvents: 'none',\n\t\t\t\tzIndex: 1,\n\t\t\t}\">\n\t\t\t<defs>\n\t\t\t\t<!-- Define arrowhead marker for connections -->\n\t\t\t\t<path id=\"arrowhead\" d=\"M 0 -7 L 20 0 L 0 7Z\" stroke=\"black\" stroke-width=\"1\" fill=\"currentColor\"></path>\n\t\t\t\t<marker\n\t\t\t\t\tid=\"arrowhead-marker\"\n\t\t\t\t\tmarkerWidth=\"10\"\n\t\t\t\t\tmarkerHeight=\"7\"\n\t\t\t\t\trefX=\"5\"\n\t\t\t\t\trefY=\"3.5\"\n\t\t\t\t\torient=\"auto\"\n\t\t\t\t\tmarkerUnits=\"strokeWidth\">\n\t\t\t\t\t<polygon points=\"0 0, 10 3.5, 0 7\" fill=\"currentColor\" />\n\t\t\t\t</marker>\n\t\t\t</defs>\n\n\t\t\t<!-- Invisible wider path for easier double-click interaction -->\n\t\t\t<path\n\t\t\t\tv-for=\"connection in visibleConnections\"\n\t\t\t\t:key=\"`${connection.id}-hitbox`\"\n\t\t\t\t:d=\"getPathData(connection)\"\n\t\t\t\tstroke=\"transparent\"\n\t\t\t\t:stroke-width=\"(connection.style?.width || 2) + 10\"\n\t\t\t\tfill=\"none\"\n\t\t\t\tclass=\"connection-hitbox\"\n\t\t\t\t@dblclick=\"handleConnectionDelete(connection)\" />\n\n\t\t\t<!-- Visible connection path -->\n\t\t\t<path\n\t\t\t\tv-for=\"connection in visibleConnections\"\n\t\t\t\t:id=\"connection.id\"\n\t\t\t\t:key=\"connection.id\"\n\t\t\t\t:d=\"getPathData(connection)\"\n\t\t\t\t:stroke=\"connection.style?.color || '#666'\"\n\t\t\t\t:stroke-width=\"connection.style?.width || 2\"\n\t\t\t\tfill=\"none\"\n\t\t\t\tmarker-mid=\"url(#arrowhead-marker)\"\n\t\t\t\tclass=\"connection-path animated-path\"\n\t\t\t\t@dblclick=\"handleConnectionDelete(connection)\" />\n\t\t</svg>\n\t</div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nimport { createTableStore } from '../stores/table'\nimport type { ConnectionPath } from '../types'\n\nconst { store } = defineProps<{\n\tstore: ReturnType<typeof createTableStore>\n}>()\n\nconst emit = defineEmits<{\n\t'connection:delete': [connection: ConnectionPath]\n}>()\n\nconst BEZIER_CURVE_FACTOR = 0.25 // Control point offset factor for bezier curves\nconst CONNECTION_HANDLE_SIZE = 16 // Width of the connection handles; this should match the handle size in the AGanttCell component\n\nconst visibleConnections = computed(() => {\n\treturn store.connectionPaths.filter(connection => {\n\t\tconst fromBar = store.ganttBars.find(bar => bar.id === connection.from.barId)\n\t\tconst toBar = store.ganttBars.find(bar => bar.id === connection.to.barId)\n\t\treturn fromBar && toBar\n\t})\n})\n\nconst getPathData = (connection: ConnectionPath) => {\n\tconst fromHandle = store.connectionHandles.find(\n\t\thandle => handle.barId === connection.from.barId && handle.side === connection.from.side\n\t)\n\tconst toHandle = store.connectionHandles.find(\n\t\thandle => handle.barId === connection.to.barId && handle.side === connection.to.side\n\t)\n\n\tif (!fromHandle || !toHandle) return ''\n\n\tconst fromX = fromHandle.position.x + CONNECTION_HANDLE_SIZE / 2 // Center of the handle\n\tconst fromY = fromHandle.position.y + CONNECTION_HANDLE_SIZE / 2\n\tconst toX = toHandle.position.x + CONNECTION_HANDLE_SIZE / 2\n\tconst toY = toHandle.position.y + CONNECTION_HANDLE_SIZE / 2\n\n\t// Calculate control points for smooth bezier curve\n\tconst deltaX = Math.abs(toX - fromX)\n\tconst controlPointOffset = Math.max(deltaX * BEZIER_CURVE_FACTOR, 50) // Minimum offset for better curves\n\tconst cp1X = fromX + (connection.from.side === 'left' ? -controlPointOffset : controlPointOffset)\n\tconst cp2X = toX + (connection.to.side === 'left' ? -controlPointOffset : controlPointOffset)\n\n\t// Use cubic bezier curve for smooth connections\n\n\t//calculate the mid point of the curve\n\tconst m0 = { x: 0.5 * fromX + 0.5 * cp1X, y: 0.5 * fromY + 0.5 * fromY }\n\tconst m1 = { x: 0.5 * cp1X + 0.5 * cp2X, y: 0.5 * fromY + 0.5 * toY }\n\tconst m2 = { x: 0.5 * cp2X + 0.5 * toX, y: 0.5 * toY + 0.5 * toY }\n\tconst m3 = { x: 0.5 * m0.x + 0.5 * m1.x, y: 0.5 * m0.y + 0.5 * m1.y }\n\tconst m4 = { x: 0.5 * m1.x + 0.5 * m2.x, y: 0.5 * m1.y + 0.5 * m2.y }\n\tconst midpoint = { x: 0.5 * m3.x + 0.5 * m4.x, y: 0.5 * m3.y + 0.5 * m4.y }\n\n\t// Calculate the bezier curve using two arcs\n\treturn `M ${fromX} ${fromY} Q ${cp1X} ${fromY}, ${midpoint.x} ${midpoint.y} Q ${cp2X} ${toY}, ${toX} ${toY}`\n}\n\nconst handleConnectionDelete = (connection: ConnectionPath) => {\n\tif (store.deleteConnection(connection.id)) {\n\t\temit('connection:delete', connection)\n\t}\n}\n</script>\n\n<style scoped>\n.gantt-connection-overlay {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\twidth: 100%;\n\theight: 100%;\n\tpointer-events: none;\n\tz-index: 15;\n}\n\n.connection-path {\n\ttransition: stroke-width 0.2s ease;\n\tpointer-events: auto;\n\tcursor: pointer;\n\tstroke-dasharray: 5px;\n\tstroke: var(--sc-cell-text-color);\n}\n#arrowhead-marker polygon {\n\tfill: var(--sc-cell-text-color);\n}\n.animated-path {\n\tanimation: animated-dash infinite 1.5s linear;\n}\n\n.connection-path:hover {\n\tstroke-width: 3px;\n}\n\n.connection-hitbox {\n\tpointer-events: auto;\n\tcursor: pointer;\n}\n@keyframes animated-dash {\n\t0% {\n\t\tstroke-dashoffset: 0px;\n\t}\n\t100% {\n\t\tstroke-dashoffset: -10px;\n\t}\n}\n</style>\n","<template>\n\t<div class=\"gantt-connection-overlay\">\n\t\t<svg\n\t\t\tclass=\"connection-svg\"\n\t\t\t:style=\"{\n\t\t\t\tposition: 'absolute',\n\t\t\t\ttop: 0,\n\t\t\t\tleft: 0,\n\t\t\t\twidth: '100%',\n\t\t\t\theight: '100%',\n\t\t\t\tpointerEvents: 'none',\n\t\t\t\tzIndex: 1,\n\t\t\t}\">\n\t\t\t<defs>\n\t\t\t\t<!-- Define arrowhead marker for connections -->\n\t\t\t\t<path id=\"arrowhead\" d=\"M 0 -7 L 20 0 L 0 7Z\" stroke=\"black\" stroke-width=\"1\" fill=\"currentColor\"></path>\n\t\t\t\t<marker\n\t\t\t\t\tid=\"arrowhead-marker\"\n\t\t\t\t\tmarkerWidth=\"10\"\n\t\t\t\t\tmarkerHeight=\"7\"\n\t\t\t\t\trefX=\"5\"\n\t\t\t\t\trefY=\"3.5\"\n\t\t\t\t\torient=\"auto\"\n\t\t\t\t\tmarkerUnits=\"strokeWidth\">\n\t\t\t\t\t<polygon points=\"0 0, 10 3.5, 0 7\" fill=\"currentColor\" />\n\t\t\t\t</marker>\n\t\t\t</defs>\n\n\t\t\t<!-- Invisible wider path for easier double-click interaction -->\n\t\t\t<path\n\t\t\t\tv-for=\"connection in visibleConnections\"\n\t\t\t\t:key=\"`${connection.id}-hitbox`\"\n\t\t\t\t:d=\"getPathData(connection)\"\n\t\t\t\tstroke=\"transparent\"\n\t\t\t\t:stroke-width=\"(connection.style?.width || 2) + 10\"\n\t\t\t\tfill=\"none\"\n\t\t\t\tclass=\"connection-hitbox\"\n\t\t\t\t@dblclick=\"handleConnectionDelete(connection)\" />\n\n\t\t\t<!-- Visible connection path -->\n\t\t\t<path\n\t\t\t\tv-for=\"connection in visibleConnections\"\n\t\t\t\t:id=\"connection.id\"\n\t\t\t\t:key=\"connection.id\"\n\t\t\t\t:d=\"getPathData(connection)\"\n\t\t\t\t:stroke=\"connection.style?.color || '#666'\"\n\t\t\t\t:stroke-width=\"connection.style?.width || 2\"\n\t\t\t\tfill=\"none\"\n\t\t\t\tmarker-mid=\"url(#arrowhead-marker)\"\n\t\t\t\tclass=\"connection-path animated-path\"\n\t\t\t\t@dblclick=\"handleConnectionDelete(connection)\" />\n\t\t</svg>\n\t</div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nimport { createTableStore } from '../stores/table'\nimport type { ConnectionPath } from '../types'\n\nconst { store } = defineProps<{\n\tstore: ReturnType<typeof createTableStore>\n}>()\n\nconst emit = defineEmits<{\n\t'connection:delete': [connection: ConnectionPath]\n}>()\n\nconst BEZIER_CURVE_FACTOR = 0.25 // Control point offset factor for bezier curves\nconst CONNECTION_HANDLE_SIZE = 16 // Width of the connection handles; this should match the handle size in the AGanttCell component\n\nconst visibleConnections = computed(() => {\n\treturn store.connectionPaths.filter(connection => {\n\t\tconst fromBar = store.ganttBars.find(bar => bar.id === connection.from.barId)\n\t\tconst toBar = store.ganttBars.find(bar => bar.id === connection.to.barId)\n\t\treturn fromBar && toBar\n\t})\n})\n\nconst getPathData = (connection: ConnectionPath) => {\n\tconst fromHandle = store.connectionHandles.find(\n\t\thandle => handle.barId === connection.from.barId && handle.side === connection.from.side\n\t)\n\tconst toHandle = store.connectionHandles.find(\n\t\thandle => handle.barId === connection.to.barId && handle.side === connection.to.side\n\t)\n\n\tif (!fromHandle || !toHandle) return ''\n\n\tconst fromX = fromHandle.position.x + CONNECTION_HANDLE_SIZE / 2 // Center of the handle\n\tconst fromY = fromHandle.position.y + CONNECTION_HANDLE_SIZE / 2\n\tconst toX = toHandle.position.x + CONNECTION_HANDLE_SIZE / 2\n\tconst toY = toHandle.position.y + CONNECTION_HANDLE_SIZE / 2\n\n\t// Calculate control points for smooth bezier curve\n\tconst deltaX = Math.abs(toX - fromX)\n\tconst controlPointOffset = Math.max(deltaX * BEZIER_CURVE_FACTOR, 50) // Minimum offset for better curves\n\tconst cp1X = fromX + (connection.from.side === 'left' ? -controlPointOffset : controlPointOffset)\n\tconst cp2X = toX + (connection.to.side === 'left' ? -controlPointOffset : controlPointOffset)\n\n\t// Use cubic bezier curve for smooth connections\n\n\t//calculate the mid point of the curve\n\tconst m0 = { x: 0.5 * fromX + 0.5 * cp1X, y: 0.5 * fromY + 0.5 * fromY }\n\tconst m1 = { x: 0.5 * cp1X + 0.5 * cp2X, y: 0.5 * fromY + 0.5 * toY }\n\tconst m2 = { x: 0.5 * cp2X + 0.5 * toX, y: 0.5 * toY + 0.5 * toY }\n\tconst m3 = { x: 0.5 * m0.x + 0.5 * m1.x, y: 0.5 * m0.y + 0.5 * m1.y }\n\tconst m4 = { x: 0.5 * m1.x + 0.5 * m2.x, y: 0.5 * m1.y + 0.5 * m2.y }\n\tconst midpoint = { x: 0.5 * m3.x + 0.5 * m4.x, y: 0.5 * m3.y + 0.5 * m4.y }\n\n\t// Calculate the bezier curve using two arcs\n\treturn `M ${fromX} ${fromY} Q ${cp1X} ${fromY}, ${midpoint.x} ${midpoint.y} Q ${cp2X} ${toY}, ${toX} ${toY}`\n}\n\nconst handleConnectionDelete = (connection: ConnectionPath) => {\n\tif (store.deleteConnection(connection.id)) {\n\t\temit('connection:delete', connection)\n\t}\n}\n</script>\n\n<style scoped>\n.gantt-connection-overlay {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\twidth: 100%;\n\theight: 100%;\n\tpointer-events: none;\n\tz-index: 15;\n}\n\n.connection-path {\n\ttransition: stroke-width 0.2s ease;\n\tpointer-events: auto;\n\tcursor: pointer;\n\tstroke-dasharray: 5px;\n\tstroke: var(--sc-cell-text-color);\n}\n#arrowhead-marker polygon {\n\tfill: var(--sc-cell-text-color);\n}\n.animated-path {\n\tanimation: animated-dash infinite 1.5s linear;\n}\n\n.connection-path:hover {\n\tstroke-width: 3px;\n}\n\n.connection-hitbox {\n\tpointer-events: auto;\n\tcursor: pointer;\n}\n@keyframes animated-dash {\n\t0% {\n\t\tstroke-dashoffset: 0px;\n\t}\n\t100% {\n\t\tstroke-dashoffset: -10px;\n\t}\n}\n</style>\n","<template>\n\t<div class=\"column-filter\">\n\t\t<input\n\t\t\tv-if=\"resolvedFilterType === 'text'\"\n\t\t\tv-model=\"filterValue\"\n\t\t\ttype=\"text\"\n\t\t\tclass=\"filter-input\"\n\t\t\t@input=\"updateFilter(filterValue)\" />\n\n\t\t<input\n\t\t\tv-else-if=\"resolvedFilterType === 'number'\"\n\t\t\tv-model=\"filterValue\"\n\t\t\ttype=\"number\"\n\t\t\tclass=\"filter-input\"\n\t\t\t@input=\"updateFilter(filterValue)\" />\n\n\t\t<label v-else-if=\"resolvedFilterType === 'checkbox'\" class=\"checkbox-filter\">\n\t\t\t<input v-model=\"filterValue\" type=\"checkbox\" class=\"filter-checkbox\" @change=\"updateFilter(filterValue)\" />\n\t\t\t<span>{{ column.label }}</span>\n\t\t</label>\n\n\t\t<select\n\t\t\tv-else-if=\"resolvedFilterType === 'select'\"\n\t\t\tv-model=\"filterValue\"\n\t\t\tclass=\"filter-select\"\n\t\t\t@change=\"updateFilter(filterValue)\">\n\t\t\t<option value=\"\">All</option>\n\t\t\t<option v-for=\"option in getSelectOptions(column)\" :key=\"option.value || option\" :value=\"option.value || option\">\n\t\t\t\t{{ option.label || option }}\n\t\t\t</option>\n\t\t</select>\n\n\t\t<input\n\t\t\tv-else-if=\"resolvedFilterType === 'date'\"\n\t\t\tv-model=\"filterValue\"\n\t\t\ttype=\"date\"\n\t\t\tclass=\"filter-input\"\n\t\t\t@change=\"updateFilter(filterValue)\" />\n\n\t\t<div v-else-if=\"resolvedFilterType === 'dateRange'\" class=\"date-range-filter\">\n\t\t\t<input\n\t\t\t\tv-model=\"dateFilter.startValue\"\n\t\t\t\ttype=\"date\"\n\t\t\t\tclass=\"filter-input\"\n\t\t\t\t@change=\"updateDateRangeFilter('start', dateFilter.startValue)\" />\n\t\t\t<span class=\"date-separator\">-</span>\n\t\t\t<input\n\t\t\t\tv-model=\"dateFilter.endValue\"\n\t\t\t\ttype=\"date\"\n\t\t\t\tclass=\"filter-input\"\n\t\t\t\t@change=\"updateDateRangeFilter('end', dateFilter.endValue)\" />\n\t\t</div>\n\n\t\t<component\n\t\t\t:is=\"column.filterComponent\"\n\t\t\tv-else-if=\"resolvedFilterType === 'component' && column.filterComponent\"\n\t\t\t:value=\"filterValue\"\n\t\t\t:column=\"column\"\n\t\t\t:col-index=\"colIndex\"\n\t\t\t:store=\"store\"\n\t\t\t@update:value=\"updateFilter($event)\" />\n\n\t\t<button v-if=\"hasActiveFilter\" class=\"clear-btn\" title=\"Clear\" @click=\"clearFilter\">×</button>\n\t</div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, reactive, computed } from 'vue'\n\nimport { createTableStore } from '../stores/table'\nimport { resolveFilterType } from '../resolveFilterType'\nimport type { TableColumn } from '../types'\n\nconst { column, colIndex, store } = defineProps<{\n\tcolumn: TableColumn\n\tcolIndex: number\n\tstore: ReturnType<typeof createTableStore>\n}>()\n\nconst filterValue = ref<any>('')\nconst dateFilter = reactive({\n\tstartValue: '',\n\tendValue: '',\n})\n\nconst resolvedFilterType = computed(() => resolveFilterType(column))\n\nconst getSelectOptions = (col: TableColumn): any[] => {\n\tif (col.filterOptions) return col.filterOptions\n\n\t// Auto-generate options from data\n\tconst uniqueValues = new Set<any>()\n\tstore.rows.forEach(row => {\n\t\tconst value = row[col.name]\n\t\tif (value !== null && value !== undefined && value !== '') {\n\t\t\tuniqueValues.add(value)\n\t\t}\n\t})\n\n\treturn Array.from(uniqueValues).map(value => ({\n\t\tvalue: value,\n\t\tlabel: String(value),\n\t}))\n}\n\nconst hasActiveFilter = computed(() => {\n\treturn !!(filterValue.value || dateFilter.startValue || dateFilter.endValue)\n})\n\n// Filter actions\nconst updateFilter = (value: any) => {\n\tif (!value && resolvedFilterType.value !== 'checkbox') {\n\t\tstore.clearFilter(colIndex)\n\t\tfilterValue.value = ''\n\t} else {\n\t\tfilterValue.value = value\n\t\tstore.setFilter(colIndex, { value })\n\t}\n}\n\nconst updateDateRangeFilter = (rangeType: 'start' | 'end', value: any) => {\n\tif (rangeType === 'start') {\n\t\tdateFilter.startValue = value\n\t} else {\n\t\tdateFilter.endValue = value\n\t}\n\n\tif (!dateFilter.startValue && !dateFilter.endValue) {\n\t\tstore.clearFilter(colIndex)\n\t} else {\n\t\tstore.setFilter(colIndex, {\n\t\t\tvalue: null,\n\t\t\tstartValue: dateFilter.startValue,\n\t\t\tendValue: dateFilter.endValue,\n\t\t})\n\t}\n}\n\nconst clearFilter = () => {\n\tfilterValue.value = ''\n\tdateFilter.startValue = ''\n\tdateFilter.endValue = ''\n\tstore.clearFilter(colIndex)\n}\n</script>\n\n<style scoped>\n.column-filter {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 0.25rem;\n\twidth: 100%;\n}\n\n.filter-input,\n.filter-select {\n\tbackground-color: var(--sc-form-background) !important;\n\tpadding: 0.15rem 0.2rem;\n\tborder: 1px solid var(--sc-form-border);\n\tborder-radius: var(--sc-border-radius);\n\tfont-size: 0.875rem;\n\tcolor: var(--sc-cell-text-color);\n\twidth: 100%;\n\tbox-sizing: border-box;\n}\n\n.filter-input:focus,\n.filter-select:focus {\n\toutline: none;\n\tborder-color: var(--sc-input-active-border-color);\n}\n\n.checkbox-filter {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 0.25rem;\n\tfont-size: 0.875rem;\n\tcolor: var(--sc-cell-text-color);\n\tcursor: pointer;\n}\n\n.filter-checkbox {\n\tmargin: 0;\n}\n\n.date-range-filter {\n\tdisplay: flex;\n\tgap: 0.25rem;\n\talign-items: center;\n\twidth: 100%;\n}\n\n.date-range-filter .filter-input {\n\tflex: 1;\n\tmin-width: 0;\n}\n\n.date-separator {\n\tcolor: var(--sc-gray-50);\n\tfont-weight: 500;\n\tpadding: 0 0.25rem;\n\tflex-shrink: 0;\n}\n\n.clear-btn {\n\tbackground: var(--sc-gray-10);\n\tborder: 1px solid var(--sc-form-border);\n\tborder-radius: var(--sc-border-radius);\n\tcolor: var(--sc-gray-70);\n\tcursor: pointer;\n\tfont-size: 1rem;\n\tpadding: 0.15rem 0.4rem;\n\tline-height: 1;\n\tflex-shrink: 0;\n}\n</style>\n","<template>\n\t<div class=\"column-filter\">\n\t\t<input\n\t\t\tv-if=\"resolvedFilterType === 'text'\"\n\t\t\tv-model=\"filterValue\"\n\t\t\ttype=\"text\"\n\t\t\tclass=\"filter-input\"\n\t\t\t@input=\"updateFilter(filterValue)\" />\n\n\t\t<input\n\t\t\tv-else-if=\"resolvedFilterType === 'number'\"\n\t\t\tv-model=\"filterValue\"\n\t\t\ttype=\"number\"\n\t\t\tclass=\"filter-input\"\n\t\t\t@input=\"updateFilter(filterValue)\" />\n\n\t\t<label v-else-if=\"resolvedFilterType === 'checkbox'\" class=\"checkbox-filter\">\n\t\t\t<input v-model=\"filterValue\" type=\"checkbox\" class=\"filter-checkbox\" @change=\"updateFilter(filterValue)\" />\n\t\t\t<span>{{ column.label }}</span>\n\t\t</label>\n\n\t\t<select\n\t\t\tv-else-if=\"resolvedFilterType === 'select'\"\n\t\t\tv-model=\"filterValue\"\n\t\t\tclass=\"filter-select\"\n\t\t\t@change=\"updateFilter(filterValue)\">\n\t\t\t<option value=\"\">All</option>\n\t\t\t<option v-for=\"option in getSelectOptions(column)\" :key=\"option.value || option\" :value=\"option.value || option\">\n\t\t\t\t{{ option.label || option }}\n\t\t\t</option>\n\t\t</select>\n\n\t\t<input\n\t\t\tv-else-if=\"resolvedFilterType === 'date'\"\n\t\t\tv-model=\"filterValue\"\n\t\t\ttype=\"date\"\n\t\t\tclass=\"filter-input\"\n\t\t\t@change=\"updateFilter(filterValue)\" />\n\n\t\t<div v-else-if=\"resolvedFilterType === 'dateRange'\" class=\"date-range-filter\">\n\t\t\t<input\n\t\t\t\tv-model=\"dateFilter.startValue\"\n\t\t\t\ttype=\"date\"\n\t\t\t\tclass=\"filter-input\"\n\t\t\t\t@change=\"updateDateRangeFilter('start', dateFilter.startValue)\" />\n\t\t\t<span class=\"date-separator\">-</span>\n\t\t\t<input\n\t\t\t\tv-model=\"dateFilter.endValue\"\n\t\t\t\ttype=\"date\"\n\t\t\t\tclass=\"filter-input\"\n\t\t\t\t@change=\"updateDateRangeFilter('end', dateFilter.endValue)\" />\n\t\t</div>\n\n\t\t<component\n\t\t\t:is=\"column.filterComponent\"\n\t\t\tv-else-if=\"resolvedFilterType === 'component' && column.filterComponent\"\n\t\t\t:value=\"filterValue\"\n\t\t\t:column=\"column\"\n\t\t\t:col-index=\"colIndex\"\n\t\t\t:store=\"store\"\n\t\t\t@update:value=\"updateFilter($event)\" />\n\n\t\t<button v-if=\"hasActiveFilter\" class=\"clear-btn\" title=\"Clear\" @click=\"clearFilter\">×</button>\n\t</div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, reactive, computed } from 'vue'\n\nimport { createTableStore } from '../stores/table'\nimport { resolveFilterType } from '../resolveFilterType'\nimport type { TableColumn } from '../types'\n\nconst { column, colIndex, store } = defineProps<{\n\tcolumn: TableColumn\n\tcolIndex: number\n\tstore: ReturnType<typeof createTableStore>\n}>()\n\nconst filterValue = ref<any>('')\nconst dateFilter = reactive({\n\tstartValue: '',\n\tendValue: '',\n})\n\nconst resolvedFilterType = computed(() => resolveFilterType(column))\n\nconst getSelectOptions = (col: TableColumn): any[] => {\n\tif (col.filterOptions) return col.filterOptions\n\n\t// Auto-generate options from data\n\tconst uniqueValues = new Set<any>()\n\tstore.rows.forEach(row => {\n\t\tconst value = row[col.name]\n\t\tif (value !== null && value !== undefined && value !== '') {\n\t\t\tuniqueValues.add(value)\n\t\t}\n\t})\n\n\treturn Array.from(uniqueValues).map(value => ({\n\t\tvalue: value,\n\t\tlabel: String(value),\n\t}))\n}\n\nconst hasActiveFilter = computed(() => {\n\treturn !!(filterValue.value || dateFilter.startValue || dateFilter.endValue)\n})\n\n// Filter actions\nconst updateFilter = (value: any) => {\n\tif (!value && resolvedFilterType.value !== 'checkbox') {\n\t\tstore.clearFilter(colIndex)\n\t\tfilterValue.value = ''\n\t} else {\n\t\tfilterValue.value = value\n\t\tstore.setFilter(colIndex, { value })\n\t}\n}\n\nconst updateDateRangeFilter = (rangeType: 'start' | 'end', value: any) => {\n\tif (rangeType === 'start') {\n\t\tdateFilter.startValue = value\n\t} else {\n\t\tdateFilter.endValue = value\n\t}\n\n\tif (!dateFilter.startValue && !dateFilter.endValue) {\n\t\tstore.clearFilter(colIndex)\n\t} else {\n\t\tstore.setFilter(colIndex, {\n\t\t\tvalue: null,\n\t\t\tstartValue: dateFilter.startValue,\n\t\t\tendValue: dateFilter.endValue,\n\t\t})\n\t}\n}\n\nconst clearFilter = () => {\n\tfilterValue.value = ''\n\tdateFilter.startValue = ''\n\tdateFilter.endValue = ''\n\tstore.clearFilter(colIndex)\n}\n</script>\n\n<style scoped>\n.column-filter {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 0.25rem;\n\twidth: 100%;\n}\n\n.filter-input,\n.filter-select {\n\tbackground-color: var(--sc-form-background) !important;\n\tpadding: 0.15rem 0.2rem;\n\tborder: 1px solid var(--sc-form-border);\n\tborder-radius: var(--sc-border-radius);\n\tfont-size: 0.875rem;\n\tcolor: var(--sc-cell-text-color);\n\twidth: 100%;\n\tbox-sizing: border-box;\n}\n\n.filter-input:focus,\n.filter-select:focus {\n\toutline: none;\n\tborder-color: var(--sc-input-active-border-color);\n}\n\n.checkbox-filter {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 0.25rem;\n\tfont-size: 0.875rem;\n\tcolor: var(--sc-cell-text-color);\n\tcursor: pointer;\n}\n\n.filter-checkbox {\n\tmargin: 0;\n}\n\n.date-range-filter {\n\tdisplay: flex;\n\tgap: 0.25rem;\n\talign-items: center;\n\twidth: 100%;\n}\n\n.date-range-filter .filter-input {\n\tflex: 1;\n\tmin-width: 0;\n}\n\n.date-separator {\n\tcolor: var(--sc-gray-50);\n\tfont-weight: 500;\n\tpadding: 0 0.25rem;\n\tflex-shrink: 0;\n}\n\n.clear-btn {\n\tbackground: var(--sc-gray-10);\n\tborder: 1px solid var(--sc-form-border);\n\tborder-radius: var(--sc-border-radius);\n\tcolor: var(--sc-gray-70);\n\tcursor: pointer;\n\tfont-size: 1rem;\n\tpadding: 0.15rem 0.4rem;\n\tline-height: 1;\n\tflex-shrink: 0;\n}\n</style>\n","<template>\n\t<thead v-if=\"columns.length\">\n\t\t<!-- Header row -->\n\t\t<tr class=\"atable-header-row\" tabindex=\"-1\">\n\t\t\t<!-- Row actions header cell (before-index position) -->\n\t\t\t<th\n\t\t\t\tv-if=\"showRowActionsHeader && rowActionsPosition === 'before-index'\"\n\t\t\t\tclass=\"row-actions-header\"\n\t\t\t\t:class=\"{ 'sticky-column': rowActionsPosition === 'before-index' }\" />\n\t\t\t<th\n\t\t\t\tv-if=\"store.zeroColumn\"\n\t\t\t\tid=\"header-index\"\n\t\t\t\t:class=\"[\n\t\t\t\t\tstore.hasPinnedColumns ? 'sticky-index' : '',\n\t\t\t\t\tstore.isTreeView ? 'tree-index' : '',\n\t\t\t\t\tstore.config.view === 'list-expansion' ? 'list-expansion-index' : '',\n\t\t\t\t]\"\n\t\t\t\tclass=\"list-index\" />\n\t\t\t<!-- Row actions header cell (after-index position) -->\n\t\t\t<th v-if=\"showRowActionsHeader && rowActionsPosition === 'after-index'\" class=\"row-actions-header\" />\n\t\t\t<th\n\t\t\t\tv-for=\"(column, colKey) in columns\"\n\t\t\t\t:key=\"column.name\"\n\t\t\t\tv-resize-observer=\"onResize\"\n\t\t\t\t:data-colindex=\"colKey\"\n\t\t\t\ttabindex=\"-1\"\n\t\t\t\t:style=\"store.getHeaderCellStyle(column)\"\n\t\t\t\t:class=\"`${column.pinned ? 'sticky-column' : ''} ${column.sortable === false ? '' : 'cursor-pointer'}`\"\n\t\t\t\t@click=\"column.sortable !== false ? handleSort(colKey) : undefined\">\n\t\t\t\t<slot>{{ column.label || String.fromCharCode(colKey + 97).toUpperCase() }}</slot>\n\t\t\t</th>\n\t\t\t<!-- Row actions header cell (end position) -->\n\t\t\t<th v-if=\"showRowActionsHeader && rowActionsPosition === 'end'\" class=\"row-actions-header\" />\n\t\t</tr>\n\t\t<!-- Filters row -->\n\t\t<tr v-if=\"filterableColumns.length > 0\" class=\"atable-filters-row\">\n\t\t\t<!-- Row actions filter cell (before-index position) -->\n\t\t\t<th\n\t\t\t\tv-if=\"showRowActionsHeader && rowActionsPosition === 'before-index'\"\n\t\t\t\tclass=\"row-actions-header\"\n\t\t\t\t:class=\"{ 'sticky-column': rowActionsPosition === 'before-index' }\" />\n\t\t\t<th\n\t\t\t\tv-if=\"store.zeroColumn\"\n\t\t\t\t:class=\"[\n\t\t\t\t\tstore.hasPinnedColumns ? 'sticky-index' : '',\n\t\t\t\t\tstore.isTreeView ? 'tree-index' : '',\n\t\t\t\t\tstore.config.view === 'list-expansion' ? 'list-expansion-index' : '',\n\t\t\t\t]\"\n\t\t\t\tclass=\"list-index\" />\n\t\t\t<!-- Row actions filter cell (after-index position) -->\n\t\t\t<th v-if=\"showRowActionsHeader && rowActionsPosition === 'after-index'\" class=\"row-actions-header\" />\n\t\t\t<th\n\t\t\t\tv-for=\"(column, colKey) in columns\"\n\t\t\t\t:key=\"`filter-${column.name}`\"\n\t\t\t\t:class=\"`${column.pinned ? 'sticky-column' : ''}`\"\n\t\t\t\t:style=\"store.getHeaderCellStyle(column)\">\n\t\t\t\t<ATableColumnFilter v-if=\"column.filterable\" :column=\"column\" :col-index=\"colKey\" :store=\"store\" />\n\t\t\t</th>\n\t\t\t<!-- Row actions filter cell (end position) -->\n\t\t\t<th v-if=\"showRowActionsHeader && rowActionsPosition === 'end'\" class=\"row-actions-header\" />\n\t\t</tr>\n\t</thead>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { vResizeObserver } from '@vueuse/components'\nimport ATableColumnFilter from './ATableColumnFilter.vue'\nimport { createTableStore } from '../stores/table'\nimport type { TableColumn } from '../types'\n\nconst { columns, store } = defineProps<{\n\tcolumns: TableColumn[]\n\tstore: ReturnType<typeof createTableStore>\n}>()\n\nconst filterableColumns = computed(() => columns.filter(column => column.filterable))\n\n// Row actions header support — explicit return type resolves Pinia's inference chain\nconst showRowActionsHeader = computed(() => store.config.rowActions?.enabled ?? false)\nconst rowActionsPosition = computed(() => store.config.rowActions?.position ?? 'before-index')\n\nconst handleSort = (colIndex: number) => store.sortByColumn(colIndex)\n\nconst onResize = (entries: ReadonlyArray<ResizeObserverEntry>) => {\n\tfor (const entry of entries) {\n\t\tif (entry.borderBoxSize.length === 0) continue\n\t\tconst observedCell = entry.borderBoxSize[0]\n\t\tconst observedWidth = observedCell.inlineSize\n\t\tconst colIndex = Number((entry.target as HTMLElement).dataset.colindex)\n\t\tconst currentWidth = store.columns[colIndex]?.width\n\n\t\tif (typeof currentWidth === 'number' && currentWidth !== observedWidth) {\n\t\t\tstore.resizeColumn(colIndex, observedWidth)\n\t\t}\n\t}\n}\n</script>\n\n<style>\n.atable-header-row,\n.atable-filters-row {\n\tbackground-color: var(--sc-cell-background);\n}\n.atable-header-row th {\n\tpadding-left: 0.5ch !important;\n\tfont-weight: 700;\n\tmin-width: 3ch;\n\tpadding-top: var(--sc-atable-row-padding);\n\tpadding-bottom: var(--sc-atable-row-padding);\n\tbox-sizing: border-box;\n\tcolor: var(--sc-header-text-color);\n\tposition: relative;\n}\n#header-index {\n\tpadding-left: var(--sc-atable-row-padding);\n\tbox-sizing: border-box;\n\tborder-top: none;\n}\n.tree-index {\n\tpadding-right: 0;\n}\nth {\n\torder: 1;\n}\n.list-expansion-index {\n\twidth: 2ch;\n\tmargin-left: 5px;\n}\n\n.cursor-pointer {\n\tcursor: pointer;\n}\n\n.atable-filters-row th {\n\tpadding: 0.25rem 0.5ch;\n\tvertical-align: top;\n}\n\n.row-actions-header {\n\twidth: 2rem;\n\tmin-width: 2rem;\n\tpadding: 0 0.25rem;\n}\n</style>\n","<template>\n\t<thead v-if=\"columns.length\">\n\t\t<!-- Header row -->\n\t\t<tr class=\"atable-header-row\" tabindex=\"-1\">\n\t\t\t<!-- Row actions header cell (before-index position) -->\n\t\t\t<th\n\t\t\t\tv-if=\"showRowActionsHeader && rowActionsPosition === 'before-index'\"\n\t\t\t\tclass=\"row-actions-header\"\n\t\t\t\t:class=\"{ 'sticky-column': rowActionsPosition === 'before-index' }\" />\n\t\t\t<th\n\t\t\t\tv-if=\"store.zeroColumn\"\n\t\t\t\tid=\"header-index\"\n\t\t\t\t:class=\"[\n\t\t\t\t\tstore.hasPinnedColumns ? 'sticky-index' : '',\n\t\t\t\t\tstore.isTreeView ? 'tree-index' : '',\n\t\t\t\t\tstore.config.view === 'list-expansion' ? 'list-expansion-index' : '',\n\t\t\t\t]\"\n\t\t\t\tclass=\"list-index\" />\n\t\t\t<!-- Row actions header cell (after-index position) -->\n\t\t\t<th v-if=\"showRowActionsHeader && rowActionsPosition === 'after-index'\" class=\"row-actions-header\" />\n\t\t\t<th\n\t\t\t\tv-for=\"(column, colKey) in columns\"\n\t\t\t\t:key=\"column.name\"\n\t\t\t\tv-resize-observer=\"onResize\"\n\t\t\t\t:data-colindex=\"colKey\"\n\t\t\t\ttabindex=\"-1\"\n\t\t\t\t:style=\"store.getHeaderCellStyle(column)\"\n\t\t\t\t:class=\"`${column.pinned ? 'sticky-column' : ''} ${column.sortable === false ? '' : 'cursor-pointer'}`\"\n\t\t\t\t@click=\"column.sortable !== false ? handleSort(colKey) : undefined\">\n\t\t\t\t<slot>{{ column.label || String.fromCharCode(colKey + 97).toUpperCase() }}</slot>\n\t\t\t</th>\n\t\t\t<!-- Row actions header cell (end position) -->\n\t\t\t<th v-if=\"showRowActionsHeader && rowActionsPosition === 'end'\" class=\"row-actions-header\" />\n\t\t</tr>\n\t\t<!-- Filters row -->\n\t\t<tr v-if=\"filterableColumns.length > 0\" class=\"atable-filters-row\">\n\t\t\t<!-- Row actions filter cell (before-index position) -->\n\t\t\t<th\n\t\t\t\tv-if=\"showRowActionsHeader && rowActionsPosition === 'before-index'\"\n\t\t\t\tclass=\"row-actions-header\"\n\t\t\t\t:class=\"{ 'sticky-column': rowActionsPosition === 'before-index' }\" />\n\t\t\t<th\n\t\t\t\tv-if=\"store.zeroColumn\"\n\t\t\t\t:class=\"[\n\t\t\t\t\tstore.hasPinnedColumns ? 'sticky-index' : '',\n\t\t\t\t\tstore.isTreeView ? 'tree-index' : '',\n\t\t\t\t\tstore.config.view === 'list-expansion' ? 'list-expansion-index' : '',\n\t\t\t\t]\"\n\t\t\t\tclass=\"list-index\" />\n\t\t\t<!-- Row actions filter cell (after-index position) -->\n\t\t\t<th v-if=\"showRowActionsHeader && rowActionsPosition === 'after-index'\" class=\"row-actions-header\" />\n\t\t\t<th\n\t\t\t\tv-for=\"(column, colKey) in columns\"\n\t\t\t\t:key=\"`filter-${column.name}`\"\n\t\t\t\t:class=\"`${column.pinned ? 'sticky-column' : ''}`\"\n\t\t\t\t:style=\"store.getHeaderCellStyle(column)\">\n\t\t\t\t<ATableColumnFilter v-if=\"column.filterable\" :column=\"column\" :col-index=\"colKey\" :store=\"store\" />\n\t\t\t</th>\n\t\t\t<!-- Row actions filter cell (end position) -->\n\t\t\t<th v-if=\"showRowActionsHeader && rowActionsPosition === 'end'\" class=\"row-actions-header\" />\n\t\t</tr>\n\t</thead>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { vResizeObserver } from '@vueuse/components'\nimport ATableColumnFilter from './ATableColumnFilter.vue'\nimport { createTableStore } from '../stores/table'\nimport type { TableColumn } from '../types'\n\nconst { columns, store } = defineProps<{\n\tcolumns: TableColumn[]\n\tstore: ReturnType<typeof createTableStore>\n}>()\n\nconst filterableColumns = computed(() => columns.filter(column => column.filterable))\n\n// Row actions header support — explicit return type resolves Pinia's inference chain\nconst showRowActionsHeader = computed(() => store.config.rowActions?.enabled ?? false)\nconst rowActionsPosition = computed(() => store.config.rowActions?.position ?? 'before-index')\n\nconst handleSort = (colIndex: number) => store.sortByColumn(colIndex)\n\nconst onResize = (entries: ReadonlyArray<ResizeObserverEntry>) => {\n\tfor (const entry of entries) {\n\t\tif (entry.borderBoxSize.length === 0) continue\n\t\tconst observedCell = entry.borderBoxSize[0]\n\t\tconst observedWidth = observedCell.inlineSize\n\t\tconst colIndex = Number((entry.target as HTMLElement).dataset.colindex)\n\t\tconst currentWidth = store.columns[colIndex]?.width\n\n\t\tif (typeof currentWidth === 'number' && currentWidth !== observedWidth) {\n\t\t\tstore.resizeColumn(colIndex, observedWidth)\n\t\t}\n\t}\n}\n</script>\n\n<style>\n.atable-header-row,\n.atable-filters-row {\n\tbackground-color: var(--sc-cell-background);\n}\n.atable-header-row th {\n\tpadding-left: 0.5ch !important;\n\tfont-weight: 700;\n\tmin-width: 3ch;\n\tpadding-top: var(--sc-atable-row-padding);\n\tpadding-bottom: var(--sc-atable-row-padding);\n\tbox-sizing: border-box;\n\tcolor: var(--sc-header-text-color);\n\tposition: relative;\n}\n#header-index {\n\tpadding-left: var(--sc-atable-row-padding);\n\tbox-sizing: border-box;\n\tborder-top: none;\n}\n.tree-index {\n\tpadding-right: 0;\n}\nth {\n\torder: 1;\n}\n.list-expansion-index {\n\twidth: 2ch;\n\tmargin-left: 5px;\n}\n\n.cursor-pointer {\n\tcursor: pointer;\n}\n\n.atable-filters-row th {\n\tpadding: 0.25rem 0.5ch;\n\tvertical-align: top;\n}\n\n.row-actions-header {\n\twidth: 2rem;\n\tmin-width: 2rem;\n\tpadding: 0 0.25rem;\n}\n</style>\n","<template>\n\t<div ref=\"amodal\" class=\"amodal\" tabindex=\"-1\" :style=\"amodalStyles\" @click.stop @input.stop>\n\t\t<slot />\n\t</div>\n</template>\n\n<script setup lang=\"ts\">\nimport { useElementBounding } from '@vueuse/core'\nimport { useTemplateRef, computed, type StyleValue } from 'vue'\n\nimport { createTableStore } from '../stores/table'\n\nconst { store } = defineProps<{ store: ReturnType<typeof createTableStore> }>()\n\nconst amodalRef = useTemplateRef('amodal')\nconst { width: modalWidth } = useElementBounding(amodalRef)\n\nconst amodalStyles = computed((): StyleValue => {\n\tif (!(store.modal.height && store.modal.width && store.modal.left && store.modal.bottom)) return {}\n\n\tconst cell = store.modal.cell\n\tif (!cell) return {}\n\n\tconst container = cell.closest('.atable-container') ?? cell.closest('table')\n\tif (!(container instanceof HTMLElement)) return {}\n\n\t// Always open below the cell. Flipping above the field is a combobox anti-pattern here —\n\t// the calendar is taller than a row, so \"fit in the table\" put it over the value.\n\tconst cellRect = cell.getBoundingClientRect()\n\tconst containerRect = container.getBoundingClientRect()\n\tconst modalY = cellRect.bottom - containerRect.top\n\n\tlet modalX = cellRect.left - containerRect.left\n\tconst maxWidth = container.clientWidth || containerRect.width\n\tif (modalWidth.value && modalX + modalWidth.value > maxWidth) {\n\t\tmodalX = Math.max(0, maxWidth - modalWidth.value)\n\t}\n\n\treturn {\n\t\tleft: `${modalX}px`,\n\t\ttop: `${modalY}px`,\n\t}\n})\n</script>\n\n<style>\n.amodal {\n\tposition: absolute;\n\twidth: max-content;\n\tmax-width: 100%;\n\tbox-sizing: border-box;\n\tmargin-top: 0.25rem;\n\tpadding: 10px;\n\tborder: 1px solid var(--sc-input-border-color);\n\tbackground: var(--sc-input-field-background);\n\tz-index: 200;\n}\n</style>\n","<template>\n\t<div ref=\"amodal\" class=\"amodal\" tabindex=\"-1\" :style=\"amodalStyles\" @click.stop @input.stop>\n\t\t<slot />\n\t</div>\n</template>\n\n<script setup lang=\"ts\">\nimport { useElementBounding } from '@vueuse/core'\nimport { useTemplateRef, computed, type StyleValue } from 'vue'\n\nimport { createTableStore } from '../stores/table'\n\nconst { store } = defineProps<{ store: ReturnType<typeof createTableStore> }>()\n\nconst amodalRef = useTemplateRef('amodal')\nconst { width: modalWidth } = useElementBounding(amodalRef)\n\nconst amodalStyles = computed((): StyleValue => {\n\tif (!(store.modal.height && store.modal.width && store.modal.left && store.modal.bottom)) return {}\n\n\tconst cell = store.modal.cell\n\tif (!cell) return {}\n\n\tconst container = cell.closest('.atable-container') ?? cell.closest('table')\n\tif (!(container instanceof HTMLElement)) return {}\n\n\t// Always open below the cell. Flipping above the field is a combobox anti-pattern here —\n\t// the calendar is taller than a row, so \"fit in the table\" put it over the value.\n\tconst cellRect = cell.getBoundingClientRect()\n\tconst containerRect = container.getBoundingClientRect()\n\tconst modalY = cellRect.bottom - containerRect.top\n\n\tlet modalX = cellRect.left - containerRect.left\n\tconst maxWidth = container.clientWidth || containerRect.width\n\tif (modalWidth.value && modalX + modalWidth.value > maxWidth) {\n\t\tmodalX = Math.max(0, maxWidth - modalWidth.value)\n\t}\n\n\treturn {\n\t\tleft: `${modalX}px`,\n\t\ttop: `${modalY}px`,\n\t}\n})\n</script>\n\n<style>\n.amodal {\n\tposition: absolute;\n\twidth: max-content;\n\tmax-width: 100%;\n\tbox-sizing: border-box;\n\tmargin-top: 0.25rem;\n\tpadding: 10px;\n\tborder: 1px solid var(--sc-input-border-color);\n\tbackground: var(--sc-input-field-background);\n\tz-index: 200;\n}\n</style>\n","<template>\n\t<tfoot v-if=\"showFooter\" class=\"atable-pagination\">\n\t\t<tr>\n\t\t\t<td :colspan=\"columnCount\">\n\t\t\t\t<p v-if=\"hasMore\" class=\"truncation-note\">This is a partial list — more records exist on the server.</p>\n\t\t\t\t<p v-else-if=\"showCompleteNote\" class=\"completion-note\">All {{ loadedCount }} records loaded.</p>\n\t\t\t\t<div v-if=\"showControls\" class=\"atable-pagination-controls\">\n\t\t\t\t\t<button type=\"button\" class=\"atable-pagination-btn\" :disabled=\"!hasPrev || loading\" @click=\"prev\">\n\t\t\t\t\t\tPrevious\n\t\t\t\t\t</button>\n\t\t\t\t\t<button type=\"button\" class=\"atable-pagination-btn\" :disabled=\"!hasNext || loading\" @click=\"onNext\">\n\t\t\t\t\t\t{{ hasMore && !hasLocalNext ? 'Load more' : 'Next' }}\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t</td>\n\t\t</tr>\n\t</tfoot>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nconst props = defineProps<{\n\tcolumnCount: number\n\tshowFooter: boolean\n\thasMore: boolean\n\thasPrev: boolean\n\thasNext: boolean\n\thasLocalNext: boolean\n\thasEverHadMore: boolean\n\tloadedCount: number\n\tloading: boolean\n\tnext: () => Promise<void>\n\tprev: () => void\n}>()\n\nconst showCompleteNote = computed(() => !props.hasMore && props.hasEverHadMore)\nconst showControls = computed(() => props.hasMore || props.hasPrev)\n\nconst onNext = () => {\n\tvoid props.next()\n}\n</script>\n\n<style scoped>\n.atable-pagination td {\n\tpadding: 0.75rem 0.5ch;\n\tborder-top: 1px solid var(--sc-row-border-color);\n}\n\n.truncation-note,\n.completion-note {\n\tmargin: 0 0 0.5rem;\n\tfont-size: var(--sc-table-font-size);\n\tcolor: var(--sc-gray-60);\n}\n\n.completion-note {\n\tmargin-bottom: 0;\n}\n\n.atable-pagination-controls {\n\tdisplay: flex;\n\tgap: 0.5rem;\n}\n\n.atable-pagination-btn {\n\tappearance: none;\n\t-webkit-appearance: none;\n\tbox-sizing: border-box;\n\tpadding: 0.5rem 1rem;\n\tbackground: var(--sc-btn-color);\n\tcolor: var(--sc-btn-label-color);\n\tborder: 1px solid var(--sc-btn-border);\n\tborder-radius: var(--sc-border-radius);\n\tcursor: pointer;\n\tfont-family: var(--sc-font-family);\n\tfont-size: var(--sc-table-font-size);\n\tfont-weight: 400;\n\tline-height: 1.2;\n\ttransition: background-color 0.15s ease;\n}\n\n.atable-pagination-btn:hover:not(:disabled) {\n\tbackground: var(--sc-btn-hover);\n}\n\n.atable-pagination-btn:focus-visible {\n\toutline: 2px solid var(--sc-input-active-border-color);\n\toutline-offset: 1px;\n}\n\n.atable-pagination-btn:disabled {\n\tcursor: not-allowed;\n\tbackground: var(--sc-gray-5);\n\tcolor: var(--sc-gray-50);\n\tborder-color: var(--sc-gray-20);\n\topacity: 1;\n}\n</style>\n","<template>\n\t<tfoot v-if=\"showFooter\" class=\"atable-pagination\">\n\t\t<tr>\n\t\t\t<td :colspan=\"columnCount\">\n\t\t\t\t<p v-if=\"hasMore\" class=\"truncation-note\">This is a partial list — more records exist on the server.</p>\n\t\t\t\t<p v-else-if=\"showCompleteNote\" class=\"completion-note\">All {{ loadedCount }} records loaded.</p>\n\t\t\t\t<div v-if=\"showControls\" class=\"atable-pagination-controls\">\n\t\t\t\t\t<button type=\"button\" class=\"atable-pagination-btn\" :disabled=\"!hasPrev || loading\" @click=\"prev\">\n\t\t\t\t\t\tPrevious\n\t\t\t\t\t</button>\n\t\t\t\t\t<button type=\"button\" class=\"atable-pagination-btn\" :disabled=\"!hasNext || loading\" @click=\"onNext\">\n\t\t\t\t\t\t{{ hasMore && !hasLocalNext ? 'Load more' : 'Next' }}\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t</td>\n\t\t</tr>\n\t</tfoot>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nconst props = defineProps<{\n\tcolumnCount: number\n\tshowFooter: boolean\n\thasMore: boolean\n\thasPrev: boolean\n\thasNext: boolean\n\thasLocalNext: boolean\n\thasEverHadMore: boolean\n\tloadedCount: number\n\tloading: boolean\n\tnext: () => Promise<void>\n\tprev: () => void\n}>()\n\nconst showCompleteNote = computed(() => !props.hasMore && props.hasEverHadMore)\nconst showControls = computed(() => props.hasMore || props.hasPrev)\n\nconst onNext = () => {\n\tvoid props.next()\n}\n</script>\n\n<style scoped>\n.atable-pagination td {\n\tpadding: 0.75rem 0.5ch;\n\tborder-top: 1px solid var(--sc-row-border-color);\n}\n\n.truncation-note,\n.completion-note {\n\tmargin: 0 0 0.5rem;\n\tfont-size: var(--sc-table-font-size);\n\tcolor: var(--sc-gray-60);\n}\n\n.completion-note {\n\tmargin-bottom: 0;\n}\n\n.atable-pagination-controls {\n\tdisplay: flex;\n\tgap: 0.5rem;\n}\n\n.atable-pagination-btn {\n\tappearance: none;\n\t-webkit-appearance: none;\n\tbox-sizing: border-box;\n\tpadding: 0.5rem 1rem;\n\tbackground: var(--sc-btn-color);\n\tcolor: var(--sc-btn-label-color);\n\tborder: 1px solid var(--sc-btn-border);\n\tborder-radius: var(--sc-border-radius);\n\tcursor: pointer;\n\tfont-family: var(--sc-font-family);\n\tfont-size: var(--sc-table-font-size);\n\tfont-weight: 400;\n\tline-height: 1.2;\n\ttransition: background-color 0.15s ease;\n}\n\n.atable-pagination-btn:hover:not(:disabled) {\n\tbackground: var(--sc-btn-hover);\n}\n\n.atable-pagination-btn:focus-visible {\n\toutline: 2px solid var(--sc-input-active-border-color);\n\toutline-offset: 1px;\n}\n\n.atable-pagination-btn:disabled {\n\tcursor: not-allowed;\n\tbackground: var(--sc-gray-5);\n\tcolor: var(--sc-gray-50);\n\tborder-color: var(--sc-gray-20);\n\topacity: 1;\n}\n</style>\n","import type { GetRecordsOptions, GetRecordsResult } from '@stonecrop/schema'\nimport { computed, nextTick, ref, toValue, watch, type MaybeRefOrGetter, type Ref } from 'vue'\n\nimport type { TableRow } from '../types'\n\n/**\n * A table row after filter/sort, with its index in the held row list.\n * @public\n */\nexport type FilteredTableRow = TableRow & { originalIndex: number }\n\n/**\n * Options for {@link useTablePagination}.\n * @public\n */\nexport interface UseTablePaginationOptions {\n\t/** Rows after filter and sort — pagination is a window over this list, not part of filtering. */\n\trows: MaybeRefOrGetter<FilteredTableRow[]>\n\t/** When set, slice the held rows into windows of this size. Omit to show the whole held list. */\n\tpageSize?: MaybeRefOrGetter<number | undefined>\n\t/** Fetch the next server page. Typed from schema so ATable need not import Stonecrop. */\n\tgetRecords?: (options?: GetRecordsOptions) => Promise<GetRecordsResult>\n\t/** When this changes, refetch from offset 0. */\n\tsourceKey?: MaybeRefOrGetter<string | undefined>\n}\n\n/**\n * Pagination state and controls returned by {@link useTablePagination}.\n * @public\n */\nexport interface TablePagination {\n\tvisibleRows: Ref<FilteredTableRow[]>\n\thasPrev: Ref<boolean>\n\thasNext: Ref<boolean>\n\t/** Whether the server reported more records beyond what has been fetched. */\n\thasMore: Ref<boolean>\n\tloading: Ref<boolean>\n\tnext: () => Promise<void>\n\tprev: () => void\n\t/** Whether footer chrome should render. */\n\tshowFooter: Ref<boolean>\n\t/** Whether another in-memory window exists before asking the server. */\n\thasLocalNext: Ref<boolean>\n\t/** Rows currently held after filter/sort — useful for a completion summary. */\n\tloadedCount: Ref<number>\n\t/** True once the server reported a further page existed (multi-page fetch). */\n\thasEverHadMore: Ref<boolean>\n}\n\n/**\n * Window rows after filter/sort, and optionally walk {@link @stonecrop/schema#GetRecordsOptions} for the next page.\n * Pagination is not a filter — pass already-filtered rows.\n * @public\n */\nexport function useTablePagination(options: UseTablePaginationOptions): TablePagination {\n\tconst heldRows = computed(() => toValue(options.rows))\n\tconst pageSize = computed(() => toValue(options.pageSize))\n\tconst sourceKey = computed(() => toValue(options.sourceKey))\n\n\tconst windowIndex = ref(0)\n\tconst loading = ref(false)\n\tconst serverHasMore = ref(false)\n\tconst hasEverHadMore = ref(false)\n\tconst lastFetchOffset = ref(0)\n\tconst lastPageLength = ref(0)\n\tconst loadedCount = computed(() => heldRows.value.length)\n\n\tconst effectivePageSize = computed(() => {\n\t\tconst size = pageSize.value\n\t\tif (size != null && size > 0) {\n\t\t\treturn size\n\t\t}\n\t\t// No pageSize: one window over everything held (server list or full child table).\n\t\tconst count = heldRows.value.length\n\t\treturn count > 0 ? count : 1\n\t})\n\n\tconst windowCount = computed(() => Math.max(1, Math.ceil(heldRows.value.length / effectivePageSize.value)))\n\n\tconst visibleRows = computed(() => {\n\t\tconst start = windowIndex.value * effectivePageSize.value\n\t\treturn heldRows.value.slice(start, start + effectivePageSize.value)\n\t})\n\n\tconst hasLocalNext = computed(() => windowIndex.value < windowCount.value - 1)\n\tconst hasPrev = computed(() => windowIndex.value > 0)\n\tconst hasNext = computed(() => hasLocalNext.value || (Boolean(options.getRecords) && serverHasMore.value))\n\tconst hasMore = computed(() => serverHasMore.value)\n\n\tconst showFooter = computed(() => {\n\t\tif (options.getRecords) {\n\t\t\t// Keep the footer after the last \"Load more\" so completion is visible, not silent.\n\t\t\treturn serverHasMore.value || hasPrev.value || loading.value || (hasEverHadMore.value && !serverHasMore.value)\n\t\t}\n\t\tconst size = pageSize.value\n\t\treturn size != null && size > 0 && heldRows.value.length > size\n\t})\n\n\tconst resetWindow = () => {\n\t\twindowIndex.value = 0\n\t\thasEverHadMore.value = false\n\t}\n\n\tconst fetchFromServer = async (fetchOptions?: GetRecordsOptions) => {\n\t\tif (!options.getRecords) {\n\t\t\treturn\n\t\t}\n\t\tloading.value = true\n\t\ttry {\n\t\t\tconst result = await options.getRecords(fetchOptions)\n\t\t\tserverHasMore.value = result.hasMore\n\t\t\tif (result.hasMore) {\n\t\t\t\thasEverHadMore.value = true\n\t\t\t}\n\t\t\tlastFetchOffset.value = fetchOptions?.offset ?? 0\n\t\t\tlastPageLength.value = result.data.length\n\t\t} finally {\n\t\t\tloading.value = false\n\t\t}\n\t}\n\n\twatch(\n\t\t() => sourceKey.value,\n\t\t() => {\n\t\t\tresetWindow()\n\t\t\tif (options.getRecords) {\n\t\t\t\tvoid fetchFromServer()\n\t\t\t}\n\t\t},\n\t\t{ immediate: true }\n\t)\n\n\twatch(heldRows, () => {\n\t\t// Shrinking the held set can leave the window past the end.\n\t\tif (windowIndex.value >= windowCount.value) {\n\t\t\twindowIndex.value = Math.max(0, windowCount.value - 1)\n\t\t}\n\t})\n\n\tconst next = async () => {\n\t\tif (hasLocalNext.value) {\n\t\t\twindowIndex.value += 1\n\t\t\treturn\n\t\t}\n\t\tif (options.getRecords && serverHasMore.value) {\n\t\t\tawait fetchFromServer({ offset: lastFetchOffset.value + lastPageLength.value })\n\t\t\tawait nextTick()\n\t\t\t// Parent/HST grows rows; show the newly appended tail.\n\t\t\twindowIndex.value = Math.max(0, windowCount.value - 1)\n\t\t}\n\t}\n\n\tconst prev = () => {\n\t\tif (windowIndex.value > 0) {\n\t\t\twindowIndex.value -= 1\n\t\t}\n\t}\n\n\treturn {\n\t\tvisibleRows,\n\t\thasPrev,\n\t\thasNext,\n\t\thasMore,\n\t\tloading,\n\t\tnext,\n\t\tprev,\n\t\tshowFooter,\n\t\thasLocalNext,\n\t\tloadedCount,\n\t\thasEverHadMore,\n\t}\n}\n","import { componentCategory } from '@stonecrop/schema'\nimport type { ColumnSchema } from '@stonecrop/schema'\n\nimport type { TableColumn } from './types'\nimport { formatCurrency, formatQuantity } from './utils'\n\n/**\n * Convert an array of doctype field descriptors into ATable column definitions.\n *\n * Fields are excluded when:\n * - `hidden: true` — field should not be visible in any view\n * - no `component` — non-scalar entry (nested table or fieldset), no column equivalent\n *\n * `fieldname` is renamed to `name`; `hidden` is stripped. All other `ColumnSchema` properties\n * spread through automatically.\n *\n * For link fields (those carrying `doctype`) without an explicit `cellComponent`:\n * - `linkDoctype` is set from the field's `doctype` property (used by ACell's async resolver).\n * - A synchronous `format` function is added (unless the field already has one) that handles\n * both bare ID strings and pre-resolved `{ id, displayText }` objects.\n *\n * For quantity fields — those whose `component` carries the `'quantity'` category — without an\n * explicit `format`, a synchronous `format` is added that renders the `{ qty, uom }` value (see\n * `QuantityValue` in `@stonecrop/aform`) as `\"<qty> <uom>\"`.\n *\n * For currency fields — those whose `component` carries the `'currency'` category — without an\n * explicit `format`, a synchronous `format` is added that renders the `{ amount, currency }` value\n * (see `CurrencyValue` in `@stonecrop/aform`) as `\"<amount> <currency>\"`.\n *\n * @public\n */\nexport function schemaToColumns(schema: ColumnSchema[]): TableColumn[] {\n\treturn schema\n\t\t.filter(f => !f.hidden && f.component)\n\t\t.map(({ fieldname, hidden: _hidden, ...rest }) => {\n\t\t\tconst col: TableColumn = Object.assign({ name: fieldname }, rest)\n\n\t\t\t// Link fields: store the linked doctype for async resolution by ACell, and add a sync\n\t\t\t// format that handles pre-resolved AFormLinkValue objects.\n\t\t\tif (rest.doctype && !rest.cellComponent) {\n\t\t\t\tcol.linkDoctype = rest.doctype\n\n\t\t\t\tif (!rest.format) {\n\t\t\t\t\tcol.format = (v: any): string => {\n\t\t\t\t\t\tif (v === null || v === undefined) return ''\n\t\t\t\t\t\tif (typeof v === 'object') {\n\t\t\t\t\t\t\tconst display: unknown = v.displayText ?? v.id ?? ''\n\t\t\t\t\t\t\treturn typeof display === 'string' || typeof display === 'number' ? String(display) : ''\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn String(v)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Quantity fields: render the composite { qty, uom } value as \"<qty> <uom>\".\n\t\t\tif (componentCategory(rest.component) === 'quantity' && !rest.format) {\n\t\t\t\tcol.format = formatQuantity\n\t\t\t}\n\n\t\t\t// Currency fields: render the composite { amount, currency } value as \"<amount> <currency>\".\n\t\t\tif (componentCategory(rest.component) === 'currency' && !rest.format) {\n\t\t\t\tcol.format = formatCurrency\n\t\t\t}\n\n\t\t\treturn col\n\t\t})\n}\n","<template>\n\t<div class=\"atable-container\" style=\"position: relative\" v-on-click-outside=\"store.closeModal\">\n\t\t<!-- Main table view -->\n\t\t<table\n\t\t\tref=\"table\"\n\t\t\tclass=\"atable\"\n\t\t\t:class=\"{ 'atable--zebra': store.config.zebra }\"\n\t\t\t:style=\"{\n\t\t\t\twidth: store.config.fullWidth ? '100%' : 'auto',\n\t\t\t}\">\n\t\t\t<slot name=\"header\" :data=\"store\">\n\t\t\t\t<ATableHeader :columns=\"store.columns\" :store=\"store\" />\n\t\t\t</slot>\n\t\t\t<tbody>\n\t\t\t\t<slot name=\"body\" :data=\"store\">\n\t\t\t\t\t<ARow\n\t\t\t\t\t\tv-for=\"(row, filteredIndex) in visibleRows\"\n\t\t\t\t\t\t:key=\"`${row.originalIndex}-${filteredIndex}`\"\n\t\t\t\t\t\t:row=\"row\"\n\t\t\t\t\t\t:row-index=\"row.originalIndex\"\n\t\t\t\t\t\t:store=\"store\"\n\t\t\t\t\t\t@row:action=\"handleRowAction\"\n\t\t\t\t\t\t@row:click=\"handleRowClick\">\n\t\t\t\t\t\t<template #content=\"slotProps\">\n\t\t\t\t\t\t\t<slot name=\"content\" v-bind=\"slotProps\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t<template v-for=\"(column, colIndex) in getProcessedColumnsForRow(row)\" :key=\"column.name\">\n\t\t\t\t\t\t\t<component\n\t\t\t\t\t\t\t\t:is=\"column.ganttComponent || 'AGanttCell'\"\n\t\t\t\t\t\t\t\tv-if=\"column.isGantt\"\n\t\t\t\t\t\t\t\t:store=\"store\"\n\t\t\t\t\t\t\t\t:columns-count=\"store.columns.length - pinnedColumnCount\"\n\t\t\t\t\t\t\t\t:color=\"row.gantt?.color\"\n\t\t\t\t\t\t\t\t:start=\"row.gantt?.startIndex\"\n\t\t\t\t\t\t\t\t:end=\"row.gantt?.endIndex\"\n\t\t\t\t\t\t\t\t:colspan=\"column.colspan\"\n\t\t\t\t\t\t\t\t:pinned=\"column.pinned\"\n\t\t\t\t\t\t\t\t:row-index=\"row.originalIndex\"\n\t\t\t\t\t\t\t\t:col-index=\"column.originalIndex ?? colIndex\"\n\t\t\t\t\t\t\t\t:style=\"{\n\t\t\t\t\t\t\t\t\ttextAlign: column?.align || 'center',\n\t\t\t\t\t\t\t\t\tminWidth: column?.width || '40ch',\n\t\t\t\t\t\t\t\t\twidth: store.config.fullWidth ? 'auto' : null,\n\t\t\t\t\t\t\t\t}\"\n\t\t\t\t\t\t\t\t@connection:create=\"handleConnectionCreate\" />\n\t\t\t\t\t\t\t<component\n\t\t\t\t\t\t\t\t:is=\"column.cellComponent || 'ACell'\"\n\t\t\t\t\t\t\t\tv-else\n\t\t\t\t\t\t\t\t:store=\"store\"\n\t\t\t\t\t\t\t\t:pinned=\"column.pinned\"\n\t\t\t\t\t\t\t\t:row-index=\"row.originalIndex\"\n\t\t\t\t\t\t\t\t:col-index=\"colIndex\"\n\t\t\t\t\t\t\t\t:style=\"{\n\t\t\t\t\t\t\t\t\ttextAlign: column?.align || 'center',\n\t\t\t\t\t\t\t\t\twidth: store.config.fullWidth ? 'auto' : null,\n\t\t\t\t\t\t\t\t}\"\n\t\t\t\t\t\t\t\tspellcheck=\"false\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t</ARow>\n\t\t\t\t</slot>\n\t\t\t</tbody>\n\n\t\t\t<slot name=\"footer\" :data=\"store\" :page=\"pagination\">\n\t\t\t\t<ATablePaginationFooter\n\t\t\t\t\t:column-count=\"footerColumnCount\"\n\t\t\t\t\t:show-footer=\"showFooter\"\n\t\t\t\t\t:has-more=\"hasMore\"\n\t\t\t\t\t:has-prev=\"hasPrev\"\n\t\t\t\t\t:has-next=\"hasNext\"\n\t\t\t\t\t:has-local-next=\"hasLocalNext\"\n\t\t\t\t\t:has-ever-had-more=\"hasEverHadMore\"\n\t\t\t\t\t:loaded-count=\"loadedCount\"\n\t\t\t\t\t:loading=\"paginationLoading\"\n\t\t\t\t\t:next=\"paginationNext\"\n\t\t\t\t\t:prev=\"paginationPrev\" />\n\t\t\t</slot>\n\t\t</table>\n\n\t\t<!-- Sibling of the table so later rows cannot paint over the picker. -->\n\t\t<slot name=\"modal\" :data=\"store\">\n\t\t\t<ATableModal v-show=\"store.modal.visible\" :store=\"store\">\n\t\t\t\t<template #default>\n\t\t\t\t\t<component\n\t\t\t\t\t\t:is=\"store.modal.component\"\n\t\t\t\t\t\t:key=\"`${store.modal.rowIndex}:${store.modal.colIndex}`\"\n\t\t\t\t\t\t:col-index=\"store.modal.colIndex\"\n\t\t\t\t\t\t:row-index=\"store.modal.rowIndex\"\n\t\t\t\t\t\t:store=\"store\"\n\t\t\t\t\t\tv-bind=\"store.modal.componentProps\" />\n\t\t\t\t</template>\n\t\t\t</ATableModal>\n\t\t</slot>\n\n\t\t<!-- Connection overlay for gantt connections -->\n\t\t<AGanttConnection\n\t\t\tv-if=\"store.isGanttView && store.isDependencyGraphEnabled\"\n\t\t\t:store=\"store\"\n\t\t\t@connection:delete=\"handleConnectionDelete\" />\n\t</div>\n</template>\n\n<script setup lang=\"ts\">\nimport { vOnClickOutside } from '@vueuse/components'\nimport { useMutationObserver } from '@vueuse/core'\nimport { computed, inject, nextTick, onMounted, useTemplateRef, watch } from 'vue'\n\nimport AGanttConnection from './AGanttConnection.vue'\nimport ARow from './ARow.vue'\nimport ATableHeader from './ATableHeader.vue'\nimport ATableModal from './ATableModal.vue'\nimport ATablePaginationFooter from './ATablePaginationFooter.vue'\nimport { useTablePagination } from '../composables/table-pagination'\nimport { createTableStore } from '../stores/table'\nimport type { ColumnSchema, GetRecordsOptions, GetRecordsResult } from '@stonecrop/schema'\n\nimport { schemaToColumns } from '../schemaToColumns'\nimport type {\n\tConnectionEvent,\n\tConnectionPath,\n\tGanttDragEvent,\n\tRowActionType,\n\tRowAddEvent,\n\tRowClickEvent,\n\tRowDeleteEvent,\n\tRowDuplicateEvent,\n\tRowInsertEvent,\n\tRowMoveEvent,\n\tTableColumn,\n\tTableConfig,\n\tTableRow,\n} from '../types'\n\nconst rows = defineModel<TableRow[]>('rows', { required: true })\n// TODO: convert columns from defineModel to a regular prop\nconst columns = defineModel<TableColumn[]>('columns')\n\ntype LinkResolverFn = (doctype: string, id: string) => Promise<string | undefined>\n\nconst {\n\tid = '',\n\tconfig = new Object(),\n\tschema = [],\n\tlinkResolver = undefined,\n\tgetRecords = undefined,\n\tsourceKey = undefined,\n} = defineProps<{\n\tid?: string\n\tconfig?: TableConfig\n\tschema?: ColumnSchema[]\n\tlinkResolver?: LinkResolverFn\n\tgetRecords?: (options?: GetRecordsOptions) => Promise<GetRecordsResult>\n\tsourceKey?: string\n}>()\n\nconst emit = defineEmits<{\n\tcellUpdate: [{ colIndex: number; rowIndex: number; newValue: any; oldValue: any }]\n\t'gantt:drag': [event: GanttDragEvent]\n\t'connection:event': [event: ConnectionEvent]\n\t'columns:update': [columns: TableColumn[]]\n\t'row:add': [event: RowAddEvent]\n\t'row:click': [event: RowClickEvent]\n\t'row:delete': [event: RowDeleteEvent]\n\t'row:duplicate': [event: RowDuplicateEvent]\n\t'row:insert-above': [event: RowInsertEvent]\n\t'row:insert-below': [event: RowInsertEvent]\n\t'row:move': [event: RowMoveEvent]\n\t'row:open': [event: RowClickEvent]\n}>()\n\nconst tableRef = useTemplateRef<HTMLTableElement>('table')\nconst resolvedColumns = columns.value?.length ? columns.value : schemaToColumns(schema ?? [])\nconst injectedLinkResolver = inject<LinkResolverFn | null>('aformLinkResolver', null)\nconst store = createTableStore({\n\tcolumns: resolvedColumns,\n\trows: rows.value,\n\tid,\n\tconfig,\n\tlinkResolver: linkResolver ?? injectedLinkResolver,\n})\n\nconst pagination = useTablePagination({\n\trows: () => store.filteredRows,\n\tpageSize: () => store.config.pageSize,\n\tgetRecords,\n\tsourceKey: () => sourceKey,\n})\n\nconst {\n\tvisibleRows,\n\tshowFooter,\n\thasMore,\n\thasPrev,\n\thasNext,\n\thasLocalNext,\n\thasEverHadMore,\n\tloadedCount,\n\tloading: paginationLoading,\n\tnext: paginationNext,\n\tprev: paginationPrev,\n} = pagination\n\nconst footerColumnCount = computed(() => store.columns.length + (store.zeroColumn ? 1 : 0))\n\nstore.$onAction(({ name, store: storeInstance, args, after }) => {\n\tif (name === 'setCellData' || name === 'setCellText') {\n\t\tconst [colIndex, rowIndex, newValue] = args\n\t\tconst oldValue = storeInstance.getCellData(colIndex, rowIndex)\n\t\tafter(() => {\n\t\t\t// Update rows model to trigger update:rows event\n\t\t\trows.value = [...store.rows]\n\t\t\temit('cellUpdate', { colIndex, rowIndex, newValue, oldValue })\n\t\t})\n\t} else if (name === 'updateGanttBar') {\n\t\tconst [event] = args\n\t\tlet shouldEmit = false\n\t\tif (event.type === 'resize') {\n\t\t\tshouldEmit = event.oldColspan !== event.newColspan\n\t\t} else if (event.type === 'bar') {\n\t\t\tshouldEmit = event.oldStart !== event.newStart || event.oldEnd !== event.newEnd\n\t\t}\n\n\t\tif (shouldEmit) {\n\t\t\tafter(() => {\n\t\t\t\temit('gantt:drag', event)\n\t\t\t})\n\t\t}\n\t} else if (name === 'resizeColumn') {\n\t\tafter(() => {\n\t\t\t// Update columns model\n\t\t\tcolumns.value = [...store.columns]\n\t\t\temit('columns:update', [...store.columns])\n\t\t})\n\t}\n})\n\n// Watch for external changes to rows and sync to store\nwatch(\n\t() => rows.value,\n\tnewRows => {\n\t\t// Only update if the rows have actually changed (avoid infinite loops)\n\t\tif (JSON.stringify(newRows) !== JSON.stringify(store.rows)) {\n\t\t\tstore.rows = [...newRows]\n\t\t}\n\t},\n\t{ deep: true }\n)\n\n// Watch for changes to columns and sync to store\nwatch(\n\tcolumns,\n\tnewColumns => {\n\t\t// The model is optional, so it can be absent — there is nothing to sync from, and the store\n\t\t// keeps the columns it resolved from the schema.\n\t\tif (!newColumns) return\n\t\t// Only update if the columns have actually changed (avoid infinite loops)\n\t\tif (JSON.stringify(newColumns) !== JSON.stringify(store.columns)) {\n\t\t\tstore.columns = [...newColumns]\n\t\t\temit('columns:update', [...newColumns])\n\t\t}\n\t},\n\t{ deep: true }\n)\n\nonMounted(() => {\n\tif (columns.value?.some(column => column.pinned)) {\n\t\tassignStickyCellWidths()\n\n\t\t// in tree views, also add a mutation observer to capture and adjust expanded rows\n\t\tif (store.isTreeView) {\n\t\t\tuseMutationObserver(tableRef, assignStickyCellWidths, { childList: true, subtree: true })\n\t\t}\n\t}\n})\n\nconst pinnedColumnCount = computed(() => {\n\treturn store.columns.filter(column => column.pinned).length\n})\n\nconst assignStickyCellWidths = () => {\n\tconst table = tableRef.value\n\n\t// set header cell width to match sticky cells' width\n\tconst headerRow = table?.rows[0]\n\tconst firstDataRow = table?.rows[1]\n\tconst headerCells = headerRow ? Array.from(headerRow.cells) : []\n\tfor (const [index, headerCell] of headerCells.entries()) {\n\t\tconst rowCell = firstDataRow?.cells[index]\n\t\tif (rowCell) {\n\t\t\theaderCell.style.width = `${rowCell.offsetWidth}px`\n\t\t}\n\t}\n\n\t// pin cells in row that are sticky\n\tfor (const row of table?.rows || []) {\n\t\tlet totalWidth = 0\n\t\tconst pinnedCells: HTMLTableCellElement[] = []\n\n\t\tfor (const column of row.cells) {\n\t\t\tif (column.classList.contains('sticky-column') || column.classList.contains('sticky-index')) {\n\t\t\t\tcolumn.style.left = `${totalWidth}px`\n\t\t\t\ttotalWidth += column.offsetWidth\n\t\t\t\tpinnedCells.push(column)\n\t\t\t}\n\t\t}\n\n\t\tif (pinnedCells.length > 0) {\n\t\t\tconst lastColumn = pinnedCells[pinnedCells.length - 1]\n\t\t\tlastColumn.classList.add('sticky-column-edge')\n\t\t}\n\t}\n}\n\nwindow.addEventListener('keydown', (event: KeyboardEvent) => {\n\tif (event.key === 'Escape') {\n\t\tif (store.modal.visible) {\n\t\t\tstore.modal.visible = false\n\n\t\t\t// focus on the parent cell again\n\t\t\tconst $parent = store.modal.parent\n\t\t\tif ($parent) {\n\t\t\t\t// wait for the modal to close before focusing\n\t\t\t\tvoid nextTick().then(() => {\n\t\t\t\t\treturn $parent.focus()\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}\n})\n\nconst getProcessedColumnsForRow = (row: TableRow) => {\n\tif (!row.gantt || pinnedColumnCount.value === 0) {\n\t\treturn store.columns\n\t}\n\n\t// For Gantt views, first add the pinned columns\n\tconst result: TableColumn[] = []\n\tfor (let i = 0; i < pinnedColumnCount.value; i++) {\n\t\tconst column = { ...store.columns[i] }\n\t\tcolumn.originalIndex = i // Preserve original index\n\t\tresult.push(column)\n\t}\n\n\t// Finally, add the Gantt bar column with either a provided colspan or default to full-width colspan\n\tresult.push({\n\t\t...store.columns[pinnedColumnCount.value],\n\t\tisGantt: true,\n\t\tcolspan: row.gantt?.colspan || store.columns.length - pinnedColumnCount.value,\n\t\toriginalIndex: pinnedColumnCount.value,\n\t\twidth: 'auto', // TODO: refactor to API that can detect when data exists in a cell. Might have be custom and not generalizable\n\t})\n\n\treturn result\n}\n\nconst handleConnectionCreate = (connection: ConnectionPath) => {\n\temit('connection:event', { type: 'create', connection })\n}\n\nconst handleConnectionDelete = (connection: ConnectionPath) => {\n\temit('connection:event', { type: 'delete', connection })\n}\n\n/**\n * Handle row click events from ARow components.\n */\nconst handleRowClick = (rowIndex: number, event: MouseEvent) => {\n\tconst row = store.rows[rowIndex]\n\temit('row:click', { row, rowIndex, event })\n}\n\n/**\n * Handle row action events from ARow components.\n * Performs the default action and emits the appropriate event.\n */\nconst handleRowAction = (actionType: RowActionType, rowIndex: number, event?: MouseEvent) => {\n\tswitch (actionType) {\n\t\tcase 'add': {\n\t\t\t// Add a new row after the current row\n\t\t\tconst newIndex = store.addRow({}, rowIndex + 1)\n\t\t\tconst newRow = store.rows[newIndex]\n\t\t\trows.value = [...store.rows]\n\t\t\temit('row:add', { rowIndex: newIndex, row: newRow })\n\t\t\tbreak\n\t\t}\n\t\tcase 'delete': {\n\t\t\tconst deletedRow = store.deleteRow(rowIndex)\n\t\t\tif (deletedRow) {\n\t\t\t\trows.value = [...store.rows]\n\t\t\t\temit('row:delete', { rowIndex, row: deletedRow })\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t\tcase 'duplicate': {\n\t\t\tconst newIndex = store.duplicateRow(rowIndex)\n\t\t\tif (newIndex >= 0) {\n\t\t\t\tconst newRow = store.rows[newIndex]\n\t\t\t\trows.value = [...store.rows]\n\t\t\t\temit('row:duplicate', { sourceIndex: rowIndex, newIndex, row: newRow })\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t\tcase 'insertAbove': {\n\t\t\tconst newIndex = store.insertRowAbove(rowIndex)\n\t\t\tconst newRow = store.rows[newIndex]\n\t\t\trows.value = [...store.rows]\n\t\t\temit('row:insert-above', { targetIndex: rowIndex, newIndex, row: newRow })\n\t\t\tbreak\n\t\t}\n\t\tcase 'insertBelow': {\n\t\t\tconst newIndex = store.insertRowBelow(rowIndex)\n\t\t\tconst newRow = store.rows[newIndex]\n\t\t\trows.value = [...store.rows]\n\t\t\temit('row:insert-below', { targetIndex: rowIndex, newIndex, row: newRow })\n\t\t\tbreak\n\t\t}\n\t\tcase 'move': {\n\t\t\t// Move action requires a target index - for now, emit an event\n\t\t\t// The consumer should handle showing a UI for selecting the target\n\t\t\temit('row:move', { fromIndex: rowIndex, toIndex: -1 })\n\t\t\tbreak\n\t\t}\n\t\tcase 'moveUp': {\n\t\t\tif (rowIndex > 0 && store.moveRow(rowIndex, rowIndex - 1)) {\n\t\t\t\trows.value = [...store.rows]\n\t\t\t\temit('row:move', { fromIndex: rowIndex, toIndex: rowIndex - 1 })\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t\tcase 'moveDown': {\n\t\t\tif (rowIndex < store.rows.length - 1 && store.moveRow(rowIndex, rowIndex + 1)) {\n\t\t\t\trows.value = [...store.rows]\n\t\t\t\temit('row:move', { fromIndex: rowIndex, toIndex: rowIndex + 1 })\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t\tcase 'open': {\n\t\t\tconst row = store.rows[rowIndex]\n\t\t\temit('row:open', { row, rowIndex, event })\n\t\t\tbreak\n\t\t}\n\t}\n}\n\ndefineExpose({\n\tstore,\n\tpagination,\n\tcreateConnection: store.createConnection,\n\tdeleteConnection: store.deleteConnection,\n\tgetConnectionsForBar: store.getConnectionsForBar,\n\tgetHandlesForBar: store.getHandlesForBar,\n\t// Row action methods\n\taddRow: store.addRow,\n\tdeleteRow: store.deleteRow,\n\tduplicateRow: store.duplicateRow,\n\tinsertRowAbove: store.insertRowAbove,\n\tinsertRowBelow: store.insertRowBelow,\n\tmoveRow: store.moveRow,\n})\n</script>\n\n<style>\n.atable-container {\n\tposition: relative;\n}\n\n.sticky-index {\n\tposition: sticky;\n\tleft: 0px;\n\tz-index: 100;\n\torder: 0;\n}\n\n.sticky-column,\nth.sticky-column,\ntd.sticky-column,\nth.sticky-index,\ntd.sticky-index {\n\tposition: sticky;\n\tz-index: 100;\n\torder: 0;\n\tbackground: inherit;\n}\n\n.sticky-column-edge,\n.atable th.sticky-column-edge {\n\tborder-right: 1px solid var(--sc-row-border-color);\n}\n</style>\n\n<style scoped>\n.atable {\n\tposition: relative;\n\tbackground: var(--sc-cell-background);\n\tfont-family: var(--sc-atable-font-family);\n\t-webkit-font-smoothing: antialiased;\n\t-moz-osx-font-smoothing: grayscale;\n\tfont-size: var(--sc-table-font-size);\n\tborder-collapse: collapse;\n\tbox-sizing: border-box;\n\ttable-layout: auto;\n\twidth: auto;\n\toverflow: clip;\n\theight: 1px;\n\t/* border-left:4px solid var(--sc-form-border); */\n}\n.atable th {\n\tborder-width: 0px;\n\tborder-style: solid;\n\tborder-radius: 0px;\n\tpadding-left: 0.5ch;\n\tpadding-right: 0.5ch;\n\tpadding-top: var(--sc-atable-row-padding);\n\tpadding-bottom: var(--sc-atable-row-padding);\n\tcolor: var(--sc-gray-60);\n\theight: var(--sc-atable-row-height);\n\tfont-weight: 300;\n\tletter-spacing: 0.05rem;\n\torder: 1;\n\tbox-sizing: border-box;\n}\n.atable th:focus {\n\toutline: none;\n}\n</style>\n","<template>\n\t<div class=\"atable-container\" style=\"position: relative\" v-on-click-outside=\"store.closeModal\">\n\t\t<!-- Main table view -->\n\t\t<table\n\t\t\tref=\"table\"\n\t\t\tclass=\"atable\"\n\t\t\t:class=\"{ 'atable--zebra': store.config.zebra }\"\n\t\t\t:style=\"{\n\t\t\t\twidth: store.config.fullWidth ? '100%' : 'auto',\n\t\t\t}\">\n\t\t\t<slot name=\"header\" :data=\"store\">\n\t\t\t\t<ATableHeader :columns=\"store.columns\" :store=\"store\" />\n\t\t\t</slot>\n\t\t\t<tbody>\n\t\t\t\t<slot name=\"body\" :data=\"store\">\n\t\t\t\t\t<ARow\n\t\t\t\t\t\tv-for=\"(row, filteredIndex) in visibleRows\"\n\t\t\t\t\t\t:key=\"`${row.originalIndex}-${filteredIndex}`\"\n\t\t\t\t\t\t:row=\"row\"\n\t\t\t\t\t\t:row-index=\"row.originalIndex\"\n\t\t\t\t\t\t:store=\"store\"\n\t\t\t\t\t\t@row:action=\"handleRowAction\"\n\t\t\t\t\t\t@row:click=\"handleRowClick\">\n\t\t\t\t\t\t<template #content=\"slotProps\">\n\t\t\t\t\t\t\t<slot name=\"content\" v-bind=\"slotProps\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t<template v-for=\"(column, colIndex) in getProcessedColumnsForRow(row)\" :key=\"column.name\">\n\t\t\t\t\t\t\t<component\n\t\t\t\t\t\t\t\t:is=\"column.ganttComponent || 'AGanttCell'\"\n\t\t\t\t\t\t\t\tv-if=\"column.isGantt\"\n\t\t\t\t\t\t\t\t:store=\"store\"\n\t\t\t\t\t\t\t\t:columns-count=\"store.columns.length - pinnedColumnCount\"\n\t\t\t\t\t\t\t\t:color=\"row.gantt?.color\"\n\t\t\t\t\t\t\t\t:start=\"row.gantt?.startIndex\"\n\t\t\t\t\t\t\t\t:end=\"row.gantt?.endIndex\"\n\t\t\t\t\t\t\t\t:colspan=\"column.colspan\"\n\t\t\t\t\t\t\t\t:pinned=\"column.pinned\"\n\t\t\t\t\t\t\t\t:row-index=\"row.originalIndex\"\n\t\t\t\t\t\t\t\t:col-index=\"column.originalIndex ?? colIndex\"\n\t\t\t\t\t\t\t\t:style=\"{\n\t\t\t\t\t\t\t\t\ttextAlign: column?.align || 'center',\n\t\t\t\t\t\t\t\t\tminWidth: column?.width || '40ch',\n\t\t\t\t\t\t\t\t\twidth: store.config.fullWidth ? 'auto' : null,\n\t\t\t\t\t\t\t\t}\"\n\t\t\t\t\t\t\t\t@connection:create=\"handleConnectionCreate\" />\n\t\t\t\t\t\t\t<component\n\t\t\t\t\t\t\t\t:is=\"column.cellComponent || 'ACell'\"\n\t\t\t\t\t\t\t\tv-else\n\t\t\t\t\t\t\t\t:store=\"store\"\n\t\t\t\t\t\t\t\t:pinned=\"column.pinned\"\n\t\t\t\t\t\t\t\t:row-index=\"row.originalIndex\"\n\t\t\t\t\t\t\t\t:col-index=\"colIndex\"\n\t\t\t\t\t\t\t\t:style=\"{\n\t\t\t\t\t\t\t\t\ttextAlign: column?.align || 'center',\n\t\t\t\t\t\t\t\t\twidth: store.config.fullWidth ? 'auto' : null,\n\t\t\t\t\t\t\t\t}\"\n\t\t\t\t\t\t\t\tspellcheck=\"false\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t</ARow>\n\t\t\t\t</slot>\n\t\t\t</tbody>\n\n\t\t\t<slot name=\"footer\" :data=\"store\" :page=\"pagination\">\n\t\t\t\t<ATablePaginationFooter\n\t\t\t\t\t:column-count=\"footerColumnCount\"\n\t\t\t\t\t:show-footer=\"showFooter\"\n\t\t\t\t\t:has-more=\"hasMore\"\n\t\t\t\t\t:has-prev=\"hasPrev\"\n\t\t\t\t\t:has-next=\"hasNext\"\n\t\t\t\t\t:has-local-next=\"hasLocalNext\"\n\t\t\t\t\t:has-ever-had-more=\"hasEverHadMore\"\n\t\t\t\t\t:loaded-count=\"loadedCount\"\n\t\t\t\t\t:loading=\"paginationLoading\"\n\t\t\t\t\t:next=\"paginationNext\"\n\t\t\t\t\t:prev=\"paginationPrev\" />\n\t\t\t</slot>\n\t\t</table>\n\n\t\t<!-- Sibling of the table so later rows cannot paint over the picker. -->\n\t\t<slot name=\"modal\" :data=\"store\">\n\t\t\t<ATableModal v-show=\"store.modal.visible\" :store=\"store\">\n\t\t\t\t<template #default>\n\t\t\t\t\t<component\n\t\t\t\t\t\t:is=\"store.modal.component\"\n\t\t\t\t\t\t:key=\"`${store.modal.rowIndex}:${store.modal.colIndex}`\"\n\t\t\t\t\t\t:col-index=\"store.modal.colIndex\"\n\t\t\t\t\t\t:row-index=\"store.modal.rowIndex\"\n\t\t\t\t\t\t:store=\"store\"\n\t\t\t\t\t\tv-bind=\"store.modal.componentProps\" />\n\t\t\t\t</template>\n\t\t\t</ATableModal>\n\t\t</slot>\n\n\t\t<!-- Connection overlay for gantt connections -->\n\t\t<AGanttConnection\n\t\t\tv-if=\"store.isGanttView && store.isDependencyGraphEnabled\"\n\t\t\t:store=\"store\"\n\t\t\t@connection:delete=\"handleConnectionDelete\" />\n\t</div>\n</template>\n\n<script setup lang=\"ts\">\nimport { vOnClickOutside } from '@vueuse/components'\nimport { useMutationObserver } from '@vueuse/core'\nimport { computed, inject, nextTick, onMounted, useTemplateRef, watch } from 'vue'\n\nimport AGanttConnection from './AGanttConnection.vue'\nimport ARow from './ARow.vue'\nimport ATableHeader from './ATableHeader.vue'\nimport ATableModal from './ATableModal.vue'\nimport ATablePaginationFooter from './ATablePaginationFooter.vue'\nimport { useTablePagination } from '../composables/table-pagination'\nimport { createTableStore } from '../stores/table'\nimport type { ColumnSchema, GetRecordsOptions, GetRecordsResult } from '@stonecrop/schema'\n\nimport { schemaToColumns } from '../schemaToColumns'\nimport type {\n\tConnectionEvent,\n\tConnectionPath,\n\tGanttDragEvent,\n\tRowActionType,\n\tRowAddEvent,\n\tRowClickEvent,\n\tRowDeleteEvent,\n\tRowDuplicateEvent,\n\tRowInsertEvent,\n\tRowMoveEvent,\n\tTableColumn,\n\tTableConfig,\n\tTableRow,\n} from '../types'\n\nconst rows = defineModel<TableRow[]>('rows', { required: true })\n// TODO: convert columns from defineModel to a regular prop\nconst columns = defineModel<TableColumn[]>('columns')\n\ntype LinkResolverFn = (doctype: string, id: string) => Promise<string | undefined>\n\nconst {\n\tid = '',\n\tconfig = new Object(),\n\tschema = [],\n\tlinkResolver = undefined,\n\tgetRecords = undefined,\n\tsourceKey = undefined,\n} = defineProps<{\n\tid?: string\n\tconfig?: TableConfig\n\tschema?: ColumnSchema[]\n\tlinkResolver?: LinkResolverFn\n\tgetRecords?: (options?: GetRecordsOptions) => Promise<GetRecordsResult>\n\tsourceKey?: string\n}>()\n\nconst emit = defineEmits<{\n\tcellUpdate: [{ colIndex: number; rowIndex: number; newValue: any; oldValue: any }]\n\t'gantt:drag': [event: GanttDragEvent]\n\t'connection:event': [event: ConnectionEvent]\n\t'columns:update': [columns: TableColumn[]]\n\t'row:add': [event: RowAddEvent]\n\t'row:click': [event: RowClickEvent]\n\t'row:delete': [event: RowDeleteEvent]\n\t'row:duplicate': [event: RowDuplicateEvent]\n\t'row:insert-above': [event: RowInsertEvent]\n\t'row:insert-below': [event: RowInsertEvent]\n\t'row:move': [event: RowMoveEvent]\n\t'row:open': [event: RowClickEvent]\n}>()\n\nconst tableRef = useTemplateRef<HTMLTableElement>('table')\nconst resolvedColumns = columns.value?.length ? columns.value : schemaToColumns(schema ?? [])\nconst injectedLinkResolver = inject<LinkResolverFn | null>('aformLinkResolver', null)\nconst store = createTableStore({\n\tcolumns: resolvedColumns,\n\trows: rows.value,\n\tid,\n\tconfig,\n\tlinkResolver: linkResolver ?? injectedLinkResolver,\n})\n\nconst pagination = useTablePagination({\n\trows: () => store.filteredRows,\n\tpageSize: () => store.config.pageSize,\n\tgetRecords,\n\tsourceKey: () => sourceKey,\n})\n\nconst {\n\tvisibleRows,\n\tshowFooter,\n\thasMore,\n\thasPrev,\n\thasNext,\n\thasLocalNext,\n\thasEverHadMore,\n\tloadedCount,\n\tloading: paginationLoading,\n\tnext: paginationNext,\n\tprev: paginationPrev,\n} = pagination\n\nconst footerColumnCount = computed(() => store.columns.length + (store.zeroColumn ? 1 : 0))\n\nstore.$onAction(({ name, store: storeInstance, args, after }) => {\n\tif (name === 'setCellData' || name === 'setCellText') {\n\t\tconst [colIndex, rowIndex, newValue] = args\n\t\tconst oldValue = storeInstance.getCellData(colIndex, rowIndex)\n\t\tafter(() => {\n\t\t\t// Update rows model to trigger update:rows event\n\t\t\trows.value = [...store.rows]\n\t\t\temit('cellUpdate', { colIndex, rowIndex, newValue, oldValue })\n\t\t})\n\t} else if (name === 'updateGanttBar') {\n\t\tconst [event] = args\n\t\tlet shouldEmit = false\n\t\tif (event.type === 'resize') {\n\t\t\tshouldEmit = event.oldColspan !== event.newColspan\n\t\t} else if (event.type === 'bar') {\n\t\t\tshouldEmit = event.oldStart !== event.newStart || event.oldEnd !== event.newEnd\n\t\t}\n\n\t\tif (shouldEmit) {\n\t\t\tafter(() => {\n\t\t\t\temit('gantt:drag', event)\n\t\t\t})\n\t\t}\n\t} else if (name === 'resizeColumn') {\n\t\tafter(() => {\n\t\t\t// Update columns model\n\t\t\tcolumns.value = [...store.columns]\n\t\t\temit('columns:update', [...store.columns])\n\t\t})\n\t}\n})\n\n// Watch for external changes to rows and sync to store\nwatch(\n\t() => rows.value,\n\tnewRows => {\n\t\t// Only update if the rows have actually changed (avoid infinite loops)\n\t\tif (JSON.stringify(newRows) !== JSON.stringify(store.rows)) {\n\t\t\tstore.rows = [...newRows]\n\t\t}\n\t},\n\t{ deep: true }\n)\n\n// Watch for changes to columns and sync to store\nwatch(\n\tcolumns,\n\tnewColumns => {\n\t\t// The model is optional, so it can be absent — there is nothing to sync from, and the store\n\t\t// keeps the columns it resolved from the schema.\n\t\tif (!newColumns) return\n\t\t// Only update if the columns have actually changed (avoid infinite loops)\n\t\tif (JSON.stringify(newColumns) !== JSON.stringify(store.columns)) {\n\t\t\tstore.columns = [...newColumns]\n\t\t\temit('columns:update', [...newColumns])\n\t\t}\n\t},\n\t{ deep: true }\n)\n\nonMounted(() => {\n\tif (columns.value?.some(column => column.pinned)) {\n\t\tassignStickyCellWidths()\n\n\t\t// in tree views, also add a mutation observer to capture and adjust expanded rows\n\t\tif (store.isTreeView) {\n\t\t\tuseMutationObserver(tableRef, assignStickyCellWidths, { childList: true, subtree: true })\n\t\t}\n\t}\n})\n\nconst pinnedColumnCount = computed(() => {\n\treturn store.columns.filter(column => column.pinned).length\n})\n\nconst assignStickyCellWidths = () => {\n\tconst table = tableRef.value\n\n\t// set header cell width to match sticky cells' width\n\tconst headerRow = table?.rows[0]\n\tconst firstDataRow = table?.rows[1]\n\tconst headerCells = headerRow ? Array.from(headerRow.cells) : []\n\tfor (const [index, headerCell] of headerCells.entries()) {\n\t\tconst rowCell = firstDataRow?.cells[index]\n\t\tif (rowCell) {\n\t\t\theaderCell.style.width = `${rowCell.offsetWidth}px`\n\t\t}\n\t}\n\n\t// pin cells in row that are sticky\n\tfor (const row of table?.rows || []) {\n\t\tlet totalWidth = 0\n\t\tconst pinnedCells: HTMLTableCellElement[] = []\n\n\t\tfor (const column of row.cells) {\n\t\t\tif (column.classList.contains('sticky-column') || column.classList.contains('sticky-index')) {\n\t\t\t\tcolumn.style.left = `${totalWidth}px`\n\t\t\t\ttotalWidth += column.offsetWidth\n\t\t\t\tpinnedCells.push(column)\n\t\t\t}\n\t\t}\n\n\t\tif (pinnedCells.length > 0) {\n\t\t\tconst lastColumn = pinnedCells[pinnedCells.length - 1]\n\t\t\tlastColumn.classList.add('sticky-column-edge')\n\t\t}\n\t}\n}\n\nwindow.addEventListener('keydown', (event: KeyboardEvent) => {\n\tif (event.key === 'Escape') {\n\t\tif (store.modal.visible) {\n\t\t\tstore.modal.visible = false\n\n\t\t\t// focus on the parent cell again\n\t\t\tconst $parent = store.modal.parent\n\t\t\tif ($parent) {\n\t\t\t\t// wait for the modal to close before focusing\n\t\t\t\tvoid nextTick().then(() => {\n\t\t\t\t\treturn $parent.focus()\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}\n})\n\nconst getProcessedColumnsForRow = (row: TableRow) => {\n\tif (!row.gantt || pinnedColumnCount.value === 0) {\n\t\treturn store.columns\n\t}\n\n\t// For Gantt views, first add the pinned columns\n\tconst result: TableColumn[] = []\n\tfor (let i = 0; i < pinnedColumnCount.value; i++) {\n\t\tconst column = { ...store.columns[i] }\n\t\tcolumn.originalIndex = i // Preserve original index\n\t\tresult.push(column)\n\t}\n\n\t// Finally, add the Gantt bar column with either a provided colspan or default to full-width colspan\n\tresult.push({\n\t\t...store.columns[pinnedColumnCount.value],\n\t\tisGantt: true,\n\t\tcolspan: row.gantt?.colspan || store.columns.length - pinnedColumnCount.value,\n\t\toriginalIndex: pinnedColumnCount.value,\n\t\twidth: 'auto', // TODO: refactor to API that can detect when data exists in a cell. Might have be custom and not generalizable\n\t})\n\n\treturn result\n}\n\nconst handleConnectionCreate = (connection: ConnectionPath) => {\n\temit('connection:event', { type: 'create', connection })\n}\n\nconst handleConnectionDelete = (connection: ConnectionPath) => {\n\temit('connection:event', { type: 'delete', connection })\n}\n\n/**\n * Handle row click events from ARow components.\n */\nconst handleRowClick = (rowIndex: number, event: MouseEvent) => {\n\tconst row = store.rows[rowIndex]\n\temit('row:click', { row, rowIndex, event })\n}\n\n/**\n * Handle row action events from ARow components.\n * Performs the default action and emits the appropriate event.\n */\nconst handleRowAction = (actionType: RowActionType, rowIndex: number, event?: MouseEvent) => {\n\tswitch (actionType) {\n\t\tcase 'add': {\n\t\t\t// Add a new row after the current row\n\t\t\tconst newIndex = store.addRow({}, rowIndex + 1)\n\t\t\tconst newRow = store.rows[newIndex]\n\t\t\trows.value = [...store.rows]\n\t\t\temit('row:add', { rowIndex: newIndex, row: newRow })\n\t\t\tbreak\n\t\t}\n\t\tcase 'delete': {\n\t\t\tconst deletedRow = store.deleteRow(rowIndex)\n\t\t\tif (deletedRow) {\n\t\t\t\trows.value = [...store.rows]\n\t\t\t\temit('row:delete', { rowIndex, row: deletedRow })\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t\tcase 'duplicate': {\n\t\t\tconst newIndex = store.duplicateRow(rowIndex)\n\t\t\tif (newIndex >= 0) {\n\t\t\t\tconst newRow = store.rows[newIndex]\n\t\t\t\trows.value = [...store.rows]\n\t\t\t\temit('row:duplicate', { sourceIndex: rowIndex, newIndex, row: newRow })\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t\tcase 'insertAbove': {\n\t\t\tconst newIndex = store.insertRowAbove(rowIndex)\n\t\t\tconst newRow = store.rows[newIndex]\n\t\t\trows.value = [...store.rows]\n\t\t\temit('row:insert-above', { targetIndex: rowIndex, newIndex, row: newRow })\n\t\t\tbreak\n\t\t}\n\t\tcase 'insertBelow': {\n\t\t\tconst newIndex = store.insertRowBelow(rowIndex)\n\t\t\tconst newRow = store.rows[newIndex]\n\t\t\trows.value = [...store.rows]\n\t\t\temit('row:insert-below', { targetIndex: rowIndex, newIndex, row: newRow })\n\t\t\tbreak\n\t\t}\n\t\tcase 'move': {\n\t\t\t// Move action requires a target index - for now, emit an event\n\t\t\t// The consumer should handle showing a UI for selecting the target\n\t\t\temit('row:move', { fromIndex: rowIndex, toIndex: -1 })\n\t\t\tbreak\n\t\t}\n\t\tcase 'moveUp': {\n\t\t\tif (rowIndex > 0 && store.moveRow(rowIndex, rowIndex - 1)) {\n\t\t\t\trows.value = [...store.rows]\n\t\t\t\temit('row:move', { fromIndex: rowIndex, toIndex: rowIndex - 1 })\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t\tcase 'moveDown': {\n\t\t\tif (rowIndex < store.rows.length - 1 && store.moveRow(rowIndex, rowIndex + 1)) {\n\t\t\t\trows.value = [...store.rows]\n\t\t\t\temit('row:move', { fromIndex: rowIndex, toIndex: rowIndex + 1 })\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t\tcase 'open': {\n\t\t\tconst row = store.rows[rowIndex]\n\t\t\temit('row:open', { row, rowIndex, event })\n\t\t\tbreak\n\t\t}\n\t}\n}\n\ndefineExpose({\n\tstore,\n\tpagination,\n\tcreateConnection: store.createConnection,\n\tdeleteConnection: store.deleteConnection,\n\tgetConnectionsForBar: store.getConnectionsForBar,\n\tgetHandlesForBar: store.getHandlesForBar,\n\t// Row action methods\n\taddRow: store.addRow,\n\tdeleteRow: store.deleteRow,\n\tduplicateRow: store.duplicateRow,\n\tinsertRowAbove: store.insertRowAbove,\n\tinsertRowBelow: store.insertRowBelow,\n\tmoveRow: store.moveRow,\n})\n</script>\n\n<style>\n.atable-container {\n\tposition: relative;\n}\n\n.sticky-index {\n\tposition: sticky;\n\tleft: 0px;\n\tz-index: 100;\n\torder: 0;\n}\n\n.sticky-column,\nth.sticky-column,\ntd.sticky-column,\nth.sticky-index,\ntd.sticky-index {\n\tposition: sticky;\n\tz-index: 100;\n\torder: 0;\n\tbackground: inherit;\n}\n\n.sticky-column-edge,\n.atable th.sticky-column-edge {\n\tborder-right: 1px solid var(--sc-row-border-color);\n}\n</style>\n\n<style scoped>\n.atable {\n\tposition: relative;\n\tbackground: var(--sc-cell-background);\n\tfont-family: var(--sc-atable-font-family);\n\t-webkit-font-smoothing: antialiased;\n\t-moz-osx-font-smoothing: grayscale;\n\tfont-size: var(--sc-table-font-size);\n\tborder-collapse: collapse;\n\tbox-sizing: border-box;\n\ttable-layout: auto;\n\twidth: auto;\n\toverflow: clip;\n\theight: 1px;\n\t/* border-left:4px solid var(--sc-form-border); */\n}\n.atable th {\n\tborder-width: 0px;\n\tborder-style: solid;\n\tborder-radius: 0px;\n\tpadding-left: 0.5ch;\n\tpadding-right: 0.5ch;\n\tpadding-top: var(--sc-atable-row-padding);\n\tpadding-bottom: var(--sc-atable-row-padding);\n\tcolor: var(--sc-gray-60);\n\theight: var(--sc-atable-row-height);\n\tfont-weight: 300;\n\tletter-spacing: 0.05rem;\n\torder: 1;\n\tbox-sizing: border-box;\n}\n.atable th:focus {\n\toutline: none;\n}\n</style>\n","<template>\n\t<div class=\"aloading\">\n\t\t<h2 class=\"aloading-header\">\n\t\t\t<slot></slot>\n\t\t</h2>\n\t\t<div class=\"aloading-bar\"></div>\n\t</div>\n</template>\n\n<style scoped>\n.aloading {\n\twidth: 100%;\n\tborder-top: 1px solid var(--sc-row-border-color);\n\tborder-bottom: 1px solid var(--sc-row-border-color);\n\tdisplay: flex;\n\tborder-left: 4px solid var(--sc-row-border-color);\n\tpadding-left: 0.5ch !important;\n\tpadding-right: 0.5ch;\n\tpadding-top: var(--sc-atable-row-padding);\n\tpadding-bottom: var(--sc-atable-row-padding);\n\talign-items: center;\n\tbox-sizing: border-box;\n\tbackground: var(--sc-focus-cell-background);\n\toverflow: hidden;\n\tposition: relative;\n}\n.aloading-bar {\n\twidth: 100%;\n\theight: 100%;\n\tposition: absolute;\n\tleft: -100%;\n\ttop: 0;\n\tbackground: linear-gradient(\n\t\t90deg,\n\t\trgba(var(--sc-table-loading-color), 0) 0%,\n\t\trgba(var(--sc-table-loading-color), 1) 50%,\n\t\trgba(var(--sc-table-loading-color), 0) 100%\n\t);\n\tanimation: gradient infinite 2s;\n\tz-index: 0;\n}\n.aloading-header {\n\tcolor: var(--sc-cell-text-color);\n\tfont-family: var(--sc-atable-font-family);\n\t-webkit-font-smoothing: antialiased;\n\t-moz-osx-font-smoothing: grayscale;\n\tfont-size: var(--sc-table-font-size);\n\tpadding: 0;\n\tmargin: 0;\n\tfont-weight: normal;\n\tz-index: 1;\n}\n.aloading-header::after {\n\tcontent: '...';\n\tanimation: ellipse 2s;\n\tanimation-iteration-count: infinite;\n}\n\n@keyframes gradient {\n\t0% {\n\t\tleft: -100%;\n\t}\n\t100% {\n\t\tleft: 100%;\n\t}\n}\n\n@keyframes ellipse {\n\t0% {\n\t\tcontent: '';\n\t}\n\t20% {\n\t\tcontent: '';\n\t}\n\t40% {\n\t\tcontent: '.';\n\t}\n\t60% {\n\t\tcontent: '..';\n\t}\n\t80% {\n\t\tcontent: '...';\n\t}\n}\n</style>\n","<template>\n\t<div class=\"aloading\">\n\t\t<h2 class=\"aloading-header\">\n\t\t\t<slot></slot>\n\t\t</h2>\n\t\t<div class=\"aloading-bar\"></div>\n\t</div>\n</template>\n\n<style scoped>\n.aloading {\n\twidth: 100%;\n\tborder-top: 1px solid var(--sc-row-border-color);\n\tborder-bottom: 1px solid var(--sc-row-border-color);\n\tdisplay: flex;\n\tborder-left: 4px solid var(--sc-row-border-color);\n\tpadding-left: 0.5ch !important;\n\tpadding-right: 0.5ch;\n\tpadding-top: var(--sc-atable-row-padding);\n\tpadding-bottom: var(--sc-atable-row-padding);\n\talign-items: center;\n\tbox-sizing: border-box;\n\tbackground: var(--sc-focus-cell-background);\n\toverflow: hidden;\n\tposition: relative;\n}\n.aloading-bar {\n\twidth: 50%;\n\theight: 3px;\n\tposition: absolute;\n\tleft: -100%;\n\tbottom: 0;\n\tbackground: var(--sc-row-border-color);\n\tanimation: bar-left infinite 2s;\n\tz-index: 0;\n}\n.aloading-header {\n\tcolor: var(--sc-cell-text-color);\n\tfont-family: var(--sc-atable-font-family);\n\t-webkit-font-smoothing: antialiased;\n\t-moz-osx-font-smoothing: grayscale;\n\tfont-size: var(--sc-table-font-size);\n\tpadding: 0;\n\tmargin: 0;\n\tfont-weight: normal;\n\tz-index: 1;\n}\n.aloading-header::after {\n\tcontent: '...';\n\tanimation: ellipse 2s;\n\tanimation-iteration-count: infinite;\n}\n\n@keyframes bar-left {\n\t0% {\n\t\tleft: -50%;\n\t}\n\t100% {\n\t\tleft: 100%;\n\t}\n}\n\n@keyframes ellipse {\n\t0% {\n\t\tcontent: '';\n\t}\n\t20% {\n\t\tcontent: '';\n\t}\n\t40% {\n\t\tcontent: '.';\n\t}\n\t60% {\n\t\tcontent: '..';\n\t}\n\t80% {\n\t\tcontent: '...';\n\t}\n}\n</style>\n","import { App } from 'vue'\n\nimport ACell from './components/ACell.vue'\nimport AGanttCell from './components/AGanttCell.vue'\nimport ARow from './components/ARow.vue'\nimport ARowActions from './components/ARowActions.vue'\nimport ATable from './components/ATable.vue'\nimport ATableHeader from './components/ATableHeader.vue'\nimport ATableLoading from './components/ATableLoading.vue'\nimport ATableLoadingBar from './components/ATableLoadingBar.vue'\nimport ATableModal from './components/ATableModal.vue'\nimport ATablePaginationFooter from './components/ATablePaginationFooter.vue'\nexport { createTableStore } from './stores/table'\nexport { useTablePagination } from './composables/table-pagination'\nexport type { FilteredTableRow, TablePagination, UseTablePaginationOptions } from './composables/table-pagination'\nexport type { FilterState, FilterStateRecord } from './stores/table'\nexport type * from './types'\nexport { schemaToColumns } from './schemaToColumns'\n\n// Icon exports\nexport {\n\tAddIcon,\n\tDeleteIcon,\n\tDuplicateIcon,\n\tInsertAboveIcon,\n\tInsertBelowIcon,\n\tMoveIcon,\n\tOpenIcon,\n\tactionIcons,\n} from './icons'\n\n/**\n * Install all ATable components\n * @param app - Vue app instance\n * @public\n */\nfunction install(app: App /* options */) {\n\tapp.component('ACell', ACell)\n\tapp.component('AGanttCell', AGanttCell)\n\tapp.component('ARow', ARow)\n\tapp.component('ARowActions', ARowActions)\n\tapp.component('ATable', ATable)\n\tapp.component('ATableHeader', ATableHeader)\n\tapp.component('ATableLoading', ATableLoading)\n\tapp.component('ATableLoadingBar', ATableLoadingBar)\n\tapp.component('ATableModal', ATableModal)\n\tapp.component('ATablePaginationFooter', ATablePaginationFooter)\n}\n\nexport {\n\tACell,\n\tAGanttCell,\n\tARow,\n\tARowActions,\n\tATable,\n\tATableHeader,\n\tATableLoading,\n\tATableLoadingBar,\n\tATableModal,\n\tATablePaginationFooter,\n\tinstall,\n}\n"],"mappings":"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"}
|