{"version":3,"file":"JGrid.vue2.cjs","sources":["../../../../src/components/atoms/JGrid.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, ref, watch, onMounted, onUnmounted } from 'vue'\nimport { AgGridVue } from 'ag-grid-vue3'\nimport { cn } from '@/lib/utils'\nimport type {\n  ColDef,\n  GridOptions,\n  RowClickedEvent,\n  CellClickedEvent,\n  SelectionChangedEvent,\n  CellValueChangedEvent,\n  RowDoubleClickedEvent,\n  GridReadyEvent,\n  ICellRendererParams,\n} from 'ag-grid-community'\nimport { ModuleRegistry, AllCommunityModule, themeQuartz } from 'ag-grid-community'\n// Enterprise 모듈 import (Grouping, Pivot, Excel Export 등)\nimport { AllEnterpriseModule } from 'ag-grid-enterprise'\n\n// AG Grid 모듈 등록 (Community + Enterprise)\nModuleRegistry.registerModules([AllCommunityModule, AllEnterpriseModule])\n\n// ── 공식 권장: data-ag-theme-mode attribute 기반 다크모드 전환 ─────────────────\n// AG Grid v33 공식 패턴:\n//   1. themeQuartz.withParams({...}, 'light').withParams({...}, 'dark') 로 두 모드 정의\n//   2. data-ag-theme-mode attribute 전환으로 모드 스위칭 (theme 객체 재생성 불필요)\n//   3. CSS --ag-* 변수 오버라이드로 앱 CSS 변수 참조 (getCSSVar 우회 불필요)\nconst jTheme = themeQuartz\n  .withParams({\n    // 공통 사이즈 (라이트/다크 모두 적용)\n    cellHorizontalPaddingScale: 1,\n    columnBorder: true,\n    fontSize: 13,\n    headerFontWeight: 600,\n    headerVerticalPaddingScale: 0.45,\n    iconSize: 14,\n    rowVerticalPaddingScale: 0.4,\n  })\n  .withParams({\n    browserColorScheme: 'light',\n  }, 'light')\n  .withParams({\n    browserColorScheme: 'dark',\n  }, 'dark')\n\n// JLIS는 .dark class 기반 다크모드이므로 MutationObserver로 감지 후 attribute 동기화\nconst isDark = ref(typeof document !== 'undefined' && document.documentElement.classList.contains('dark'))\nconst gridContainerRef = ref<HTMLElement | null>(null)\nlet darkObserver: MutationObserver | null = null\n\n// isDark 변경 → data-ag-theme-mode 동기화 (AG Grid가 내부적으로 반응)\nwatch(isDark, (dark) => {\n  gridContainerRef.value?.setAttribute('data-ag-theme-mode', dark ? 'dark' : 'light')\n})\n\nonMounted(() => {\n  // 초기 attribute 설정\n  gridContainerRef.value?.setAttribute('data-ag-theme-mode', isDark.value ? 'dark' : 'light')\n\n  // 이후 변경 감지\n  darkObserver = new MutationObserver(() => {\n    isDark.value = document.documentElement.classList.contains('dark')\n  })\n  darkObserver.observe(document.documentElement, { attributes: true, attributeFilter: ['class'] })\n})\n\nonUnmounted(() => {\n  darkObserver?.disconnect()\n})\n\n/**\n * Action Button 정의 타입\n */\nexport type ActionButton = {\n  /** 버튼 아이콘 이름 (lucide) - label이 없을 때 기본 텍스트 생성에 사용 */\n  icon?: string\n  /** 버튼 라벨 */\n  label?: string\n  /** 툴팁 텍스트 */\n  tooltip?: string\n  /** 버튼 클릭 핸들러 (rowData 전달) */\n  onClick: (rowData: any) => void\n  /** 버튼 스타일 타입 */\n  styletype?: 'default' | 'primary' | 'secondary' | 'success' | 'warning' | 'danger'\n  /** 조건부 표시 함수 (rowData를 받아 boolean 반환) */\n  show?: (rowData: any) => boolean\n}\n\nconst props = withDefaults(\n  defineProps<{\n    /** 추가 클래스 (외부 커스터마이징용) */\n    class?: string\n    /** 그리드에 표시할 데이터 배열 */\n    rowData: any[]\n    /** 컬럼 정의 배열 */\n    columnDefs: ColDef[]\n    /** 페이지네이션 활성화 여부 */\n    pagination?: boolean\n    /** 체크박스 선택 활성화 여부 */\n    checkbox?: boolean\n    /** 행 번호 표시 여부 (Enterprise) */\n    rowNumbers?: boolean\n    /** 플로팅 필터 표시 여부 */\n    floatingFilters?: boolean\n    /** 플로팅 필터 표시 여부 (하위호환 alias) */\n    floatingFilter?: boolean\n    /** 행 번호 컬럼 너비(px) */\n    rowNumberWidth?: number\n    /** 행별 액션 버튼 목록 */\n    actionButtons?: ActionButton[]\n    /** 요약 컬럼 표시 여부 */\n    summaryColumn?: boolean\n    /** 숨김 컬럼 관리 활성화 여부 */\n    hiddenColumn?: boolean\n    /** 그룹핑 기능 활성화 여부 (Enterprise) */\n    enableGrouping?: boolean\n    /** 피벗 기능 활성화 여부 (Enterprise) */\n    enablePivot?: boolean\n    /** Excel 내보내기 기능 활성화 여부 (Enterprise) */\n    enableExcelExport?: boolean\n    /** Tree Data 기능 활성화 여부 (Enterprise) */\n    enableTreeData?: boolean\n    /** Tree Data 계층 경로를 반환하는 함수 */\n    getDataPath?: (data: any) => (string | number)[]\n    /** Tree Data 그룹 컬럼 정의 */\n    autoGroupColumnDef?: ColDef\n    /** 선택된 행 데이터 배열 (v-model:selected-rows) */\n    selectedRows?: any[]\n    /** 컬럼 호버 하이라이트 활성화 여부 */\n    columnHover?: boolean\n    /** Columns Tool Panel 활성화 여부 (Enterprise) */\n    enableColumnsToolPanel?: boolean\n    /** Status Bar 활성화 여부 (Enterprise) */\n    statusBar?: boolean\n    /** 간소화된 Footer 모드 (Status Bar 제거, Pagination만 표시) */\n    compactFooter?: boolean\n    /** Row Group Panel 표시 여부 ('always' | 'onlyWhenGrouping' | 'never') */\n    rowGroupPanelShow?: 'always' | 'onlyWhenGrouping' | 'never'\n    /** 그룹 기본 확장 레벨 (-1: 모두 닫힘, 0: 첫 레벨만, 1: 2레벨까지...) */\n    groupDefaultExpanded?: number\n    /** Pivot Mode Panel 표시 여부 */\n    pivotPanelShow?: 'always' | 'onlyWhenPivoting' | 'never'\n    /** Pivot Mode 활성화 여부 */\n    pivotMode?: boolean\n    /** Row Drag 관리 모드 (AG Grid 내장 정렬 사용). true 시 pagination 은 강제로 false */\n    rowDragManaged?: boolean\n    /** Row 전체를 드래그 핸들로 사용 (행 어느 곳이든 드래그 시작 가능) */\n    rowDragEntireRow?: boolean\n    /** 다중 행 드래그 허용 (rowSelection='multiRow' 필요) */\n    rowDragMultiRow?: boolean\n    /** rowData 내부 필드 변경(깊은 변이)에 반응할지 여부. 기본 true(기존 동작). */\n    /** managed drag 사용 시 false 로 두어 내부 mutation 으로 인한 전체 재주입(드래그 롤백) 방지 권장. */\n    /** 주의: watcher 의 deep 옵션은 컴포넌트 마운트 시점에 고정됩니다. */\n    reactiveRowData?: boolean\n  }>(),\n  {\n    pagination: true,\n    checkbox: false,\n    rowNumbers: true,\n    floatingFilters: true,\n    floatingFilter: undefined,\n    rowNumberWidth: 38,\n    actionButtons: undefined,\n    summaryColumn: false,\n    hiddenColumn: false,\n    enableGrouping: true,\n    enablePivot: false,\n    enableExcelExport: false,\n    enableTreeData: false,\n    getDataPath: undefined,\n    autoGroupColumnDef: undefined,\n    selectedRows: () => [],\n    columnHover: true,\n    enableColumnsToolPanel: true,\n    statusBar: true,\n    compactFooter: false,\n    rowGroupPanelShow: 'never',\n    groupDefaultExpanded: -1,\n    pivotPanelShow: 'never',\n    pivotMode: false,\n    rowDragManaged: false,\n    rowDragEntireRow: false,\n    rowDragMultiRow: false,\n    reactiveRowData: true,\n  },\n)\n\nconst emit = defineEmits<{\n  /** 행 클릭 이벤트 */\n  rowClicked: [event: RowClickedEvent]\n  /** 행 더블클릭 이벤트 */\n  rowDoubleClicked: [event: RowDoubleClickedEvent]\n  /** 셀 클릭 이벤트 */\n  cellClicked: [event: CellClickedEvent]\n  /** 선택 변경 이벤트 (체크박스 등) */\n  selectionChanged: [event: SelectionChangedEvent]\n  /** 셀 값 변경 이벤트 */\n  cellValueChanged: [event: CellValueChangedEvent]\n  /** 그리드 준비 완료 이벤트 */\n  gridReady: [event: GridReadyEvent]\n  /** 선택된 행 변경 이벤트 (v-model:selected-rows) */\n  'update:selectedRows': [rows: any[]]\n}>()\n\n// ag-Grid 인스턴스 참조\nconst gridApi = ref<any>(null)\nconst gridColumnApi = ref<any>(null)\n\n// Action Buttons Cell Renderer - 함수형으로 DOM 직접 생성\nconst ActionButtonsCellRenderer = (params: ICellRendererParams) => {\n  const buttons = props.actionButtons || []\n  const rowData = params.data\n  \n  // 표시할 버튼 필터링\n  const visibleButtons = buttons.filter(btn => {\n    if (btn.show) {\n      return btn.show(rowData)\n    }\n    return true\n  })\n  \n  if (visibleButtons.length === 0) {\n    return ''\n  }\n  \n  // 컨테이너 div 생성\n  const container = document.createElement('div')\n  container.className = 'flex items-center gap-1'\n  \n  // 각 버튼 생성\n  visibleButtons.forEach((btn) => {\n    const button = document.createElement('button')\n    button.className = btn.styletype === 'danger' ? 'j-action-btn j-action-btn-danger' : 'j-action-btn'\n    \n    // tooltip\n    if (btn.tooltip) {\n      button.title = btn.tooltip\n    }\n    \n    // 라벨 추가 (텍스트 버튼)\n    if (btn.label) {\n      button.textContent = btn.label\n    } else if (btn.icon) {\n      // 라벨이 없으면 기본 텍스트 생성\n      if (btn.icon === 'pencil') {\n        button.textContent = '수정'\n      } else if (btn.icon === 'trash2' || btn.icon === 'trash') {\n        button.textContent = '삭제'\n      } else if (btn.icon === 'eye') {\n        button.textContent = '보기'\n      } else if (btn.icon === 'copy') {\n        button.textContent = '복사'\n      } else if (btn.icon === 'download') {\n        button.textContent = '다운로드'\n      } else if (btn.icon === 'circleX') {\n        button.textContent = '비활성화'\n      } else if (btn.icon === 'circleCheckBig') {\n        button.textContent = '활성화'\n      } else {\n        button.textContent = btn.icon\n      }\n    }\n    \n    // 클릭 이벤트\n    button.addEventListener('click', (e) => {\n      e.stopPropagation()\n      btn.onClick(rowData)\n    })\n    \n    container.appendChild(button)\n  })\n  \n  return container\n}\n\n// Action Buttons 컬럼 정의\nconst actionButtonsColumn = computed<ColDef | null>(() => {\n  if (!props.actionButtons || props.actionButtons.length === 0) {\n    return null\n  }\n  \n  return {\n    colId: 'actionButtons',\n    headerName: '작업',\n    field: '_actions',\n    width: 120,\n    minWidth: 80,\n    maxWidth: 200,\n    lockPosition: 'left' as const,\n    sortable: false,\n    filter: false,\n    resizable: true,\n    suppressNavigable: true,\n    suppressHeaderMenuButton: true,\n    cellRenderer: ActionButtonsCellRenderer,\n    cellStyle: { display: 'flex', justifyContent: 'center', alignItems: 'center' },\n  }\n})\n\n// checkbox 활성화 및 추가 컬럼 처리\nconst processedColumnDefs = computed(() => {\n  const columns: ColDef[] = []\n  \n  // 1. Checkbox 컬럼 (최우선)\n  if (props.checkbox) {\n    columns.push({\n      colId: 'rowSelection',\n      headerName: '',\n      // field와 valueGetter 제거 - AG Grid 공식 방식\n      width: 40,\n      minWidth: 40,\n      maxWidth: 40,\n      lockPosition: 'left' as const,\n      checkboxSelection: true,\n      headerCheckboxSelection: true,\n      sortable: false,\n      filter: false,\n      resizable: false,\n      suppressNavigable: true,\n      suppressHeaderMenuButton: true,\n      cellStyle: { display: 'flex', justifyContent: 'center', alignItems: 'center' },\n      // 체크박스 셀 클릭 시 토글 (checkbox 아이콘 클릭은 AG Grid 기본 처리)\n      onCellClicked: (params: CellClickedEvent) => {\n        const target = (params.event as MouseEvent)?.target as HTMLElement\n        if (target && !target.closest('.ag-checkbox-input-wrapper')) {\n          params.node.setSelected(!params.node.isSelected())\n        }\n      },\n    })\n  }\n  \n  // 2. Action Buttons 컬럼\n  if (actionButtonsColumn.value) {\n    columns.push(actionButtonsColumn.value)\n  }\n  \n  // 3. 사용자 정의 컬럼들 (Row Numbers는 AG Grid가 자동으로 추가)\n  columns.push(...props.columnDefs)\n  \n  return columns\n})\n\n// Grid 옵션 설정\nconst gridOptions = computed<GridOptions>(() => {\n  const useFloatingFilters = props.floatingFilter ?? props.floatingFilters\n  // rowDragManaged 와 pagination 은 AG Grid 런타임에서 충돌 경고(및 managed drag 무효화)를 발생시키므로,\n  // managed drag 가 켜지면 pagination 은 강제로 비활성화한다.\n  const effectivePagination = props.rowDragManaged ? false : props.pagination\n  if (props.rowDragManaged && props.pagination) {\n    console.warn('[JGrid] rowDragManaged=true 이므로 pagination 은 자동으로 false 로 강제됩니다.')\n  }\n  const options: GridOptions = {\n    theme: jTheme,\n    pagination: effectivePagination,\n    tooltipShowDelay: 500,\n    tooltipHideDelay: 2000,\n    overlayNoRowsTemplate: '<span class=\"j-grid-no-rows\">데이터가 없습니다</span>',\n    defaultColDef: {\n      filter: true,\n      floatingFilter: useFloatingFilters,\n    },\n    // AG Grid v32.2+ 권장 오브젝트 형태로 rowSelection 구성\n    //   - 'multiple' (string) 및 suppressRowClickSelection 은 v32.2부터 deprecated\n    //   - 체크박스만으로 선택을 제어하려면 enableClickSelection: false\n    rowSelection: props.checkbox\n      ? { mode: 'multiRow', enableClickSelection: false }\n      : undefined,\n\n    // Row Numbers (Enterprise) - AG Grid 표준 방식\n    rowNumbers: props.rowNumbers\n      ? ({\n          minWidth: props.rowNumberWidth,\n          width: props.rowNumberWidth,\n        } as any)\n      : false,\n\n    // Column Hover Highlight\n    columnHoverHighlight: props.columnHover,\n\n    // Enterprise 기능 옵션\n    sideBar: props.enableColumnsToolPanel || props.enableGrouping || props.enablePivot ? {\n      toolPanels: [\n        {\n          id: 'columns',\n          labelDefault: 'Columns',\n          labelKey: 'columns',\n          iconKey: 'columns',\n          toolPanel: 'agColumnsToolPanel',\n          toolPanelParams: {\n            suppressRowGroups: !props.enableGrouping,\n            suppressValues: !props.enablePivot,\n            suppressPivots: !props.enablePivot,\n            suppressPivotMode: !props.enablePivot,\n          },\n        },\n      ],\n      defaultToolPanel: '', // 초기에는 접힌 상태\n    } : undefined,\n\n    // Status Bar (Enterprise)\n    // compactFooter 모드에서는 Status Bar 비활성화\n    statusBar: (props.statusBar && !props.compactFooter) ? {\n      statusPanels: [\n        { statusPanel: 'agTotalAndFilteredRowCountComponent', align: 'left' as const },\n        { statusPanel: 'agSelectedRowCountComponent', align: 'left' as const },\n        { statusPanel: 'agAggregationComponent', align: 'right' as const },\n      ],\n    } : undefined,\n\n    // Row Group Panel 설정 (Enterprise) - 그리드 상단에 드래그 영역 표시\n    rowGroupPanelShow: props.rowGroupPanelShow !== 'never' ? props.rowGroupPanelShow : undefined,\n\n    // Pivot Panel 설정 (Enterprise) - 피벗 모드용 드래그 영역\n    pivotPanelShow: props.pivotPanelShow !== 'never' ? props.pivotPanelShow : undefined,\n    \n    // Pivot Mode 활성화\n    pivotMode: props.pivotMode,\n\n    // 그룹핑 기본 설정\n    groupDefaultExpanded: props.groupDefaultExpanded,\n    suppressAggFuncInHeader: false,\n\n    // Tree Data 설정 (Enterprise)\n    treeData: props.enableTreeData || undefined,\n    getDataPath: props.enableTreeData\n      ? (props.getDataPath || ((data: any) => data.path || []))\n      : undefined,\n    autoGroupColumnDef: props.enableTreeData && props.autoGroupColumnDef\n      ? props.autoGroupColumnDef\n      : undefined,\n\n    // Row Drag 설정 (기본값 false 이므로 전달하지 않음 → AG Grid 기본 동작 유지)\n    rowDragManaged: props.rowDragManaged || undefined,\n    rowDragEntireRow: props.rowDragEntireRow || undefined,\n    rowDragMultiRow: props.rowDragMultiRow || undefined,\n  }\n\n  return options\n})\n\n// Excel 내보내기 함수 (외부에서 사용 가능하도록 expose)\nconst exportToExcel = () => {\n  if (gridApi.value && props.enableExcelExport) {\n    gridApi.value.exportDataAsExcel({\n      fileName: 'grid-export.xlsx',\n    })\n  }\n}\n\n// 그리드 API를 외부에 노출\ndefineExpose({\n  gridApi,\n  gridColumnApi,\n  exportToExcel,\n})\n\n// Grid ready 이벤트 핸들러\nconst onGridReady = (params: GridReadyEvent) => {\n  gridApi.value = params.api\n  gridColumnApi.value = params.api // v34에서 columnApi는 deprecated\n  emit('gridReady', params)\n}\n\n// 행 클릭 이벤트 핸들러\nconst onRowClicked = (event: RowClickedEvent) => {\n  emit('rowClicked', event)\n}\n\n// 행 더블클릭 이벤트 핸들러\nconst onRowDoubleClicked = (event: RowDoubleClickedEvent) => {\n  emit('rowDoubleClicked', event)\n}\n\n// 셀 클릭 이벤트 핸들러\nconst onCellClicked = (event: CellClickedEvent) => {\n  emit('cellClicked', event)\n}\n\n// 선택 변경 이벤트 핸들러\nconst onSelectionChanged = (event: SelectionChangedEvent) => {\n  emit('selectionChanged', event)\n  emit('update:selectedRows', event.api.getSelectedRows())\n}\n\n// 셀 값 변경 이벤트 핸들러\nconst onCellValueChanged = (event: CellValueChangedEvent) => {\n  emit('cellValueChanged', event)\n}\n\n// columnDefs 변경 감지\nwatch(\n  () => props.columnDefs,\n  () => {\n    if (gridApi.value) {\n      gridApi.value.setGridOption('columnDefs', processedColumnDefs.value)\n    }\n  },\n  { deep: true },\n)\n\n// rowData 변경 감지\n// reactiveRowData=true(기본): 내부 필드 변이까지 감지하여 AG Grid 에 rowData 재주입(기존 동작)\n// reactiveRowData=false      : 배열 참조 교체 시에만 재주입. managed drag 와 함께 사용 시 드래그 중 롤백 방지.\n// 주의: deep 옵션은 watcher 생성 시점에 고정되므로 런타임 토글은 지원하지 않음.\nwatch(\n  () => props.rowData,\n  () => {\n    if (gridApi.value) {\n      gridApi.value.setGridOption('rowData', props.rowData)\n    }\n  },\n  { deep: props.reactiveRowData },\n)\n</script>\n\n<template>\n  <div ref=\"gridContainerRef\" :class=\"cn('ag-grid-container', props.class)\">\n    <AgGridVue\n      :column-defs=\"processedColumnDefs\"\n      :row-data=\"rowData\"\n      :grid-options=\"gridOptions\"\n      style=\"height: 100%; width: 100%\"\n      @grid-ready=\"onGridReady\"\n      @row-clicked=\"onRowClicked\"\n      @row-double-clicked=\"onRowDoubleClicked\"\n      @cell-clicked=\"onCellClicked\"\n      @selection-changed=\"onSelectionChanged\"\n      @cell-value-changed=\"onCellValueChanged\"\n    />\n  </div>\n</template>\n\n<style scoped>\n.ag-grid-container {\n  width: 100%;\n  height: 100%;\n  min-height: 200px;\n\n  /*\n   * App CSS 변수 → AG Grid CSS 변수 브릿지\n   * CSS 변수는 런타임 해소 → .dark 클래스 전환 시 라이트/다크 자동 대응\n   * AG Grid v33 공식 CSS variable 명칭 사용\n   */\n  --ag-background-color:              hsl(var(--background));\n  --ag-foreground-color:              hsl(var(--foreground));\n  --ag-border-color:                  hsl(var(--border));\n  --ag-header-background-color:       hsl(var(--muted));\n  --ag-header-foreground-color:       hsl(var(--foreground));\n  --ag-odd-row-background-color:      hsl(var(--card));\n  --ag-row-hover-color:               hsl(var(--accent));\n  --ag-selected-row-background-color: hsl(var(--primary) / 0.18);\n  --ag-accent-color:                  hsl(var(--primary));\n  --ag-header-height:                 var(--j-grid-header-h);\n  --ag-row-height:                    var(--j-grid-row-h);\n}\n\n/* ============================================\n   COMPACT FOOTER: Status Bar + Pagination 통합\n   ============================================ */\n\n/* Status Bar 높이 줄이기 */\n:deep(.ag-status-bar) {\n  min-height: var(--j-grid-footer-h) !important;\n  height: var(--j-grid-footer-h) !important;\n  padding: 0 8px !important;\n  border-top: 1px solid var(--ag-border-color);\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  font-size: 0.6875rem;\n}\n\n/* Status Bar 컴포넌트들 높이 조정 */\n:deep(.ag-status-bar-left),\n:deep(.ag-status-bar-center),\n:deep(.ag-status-bar-right) {\n  height: var(--j-grid-footer-h);\n  display: flex;\n  align-items: center;\n  gap: 8px;\n}\n\n/* Status Bar 패널들 간격 조정 */\n:deep(.ag-status-panel) {\n  padding: 0;\n  height: var(--j-grid-footer-h);\n  display: flex;\n  align-items: center;\n}\n\n/* Pagination Panel 정렬 */\n:deep(.ag-paging-panel) {\n  display: flex !important;\n  align-items: center !important;\n  justify-content: flex-end !important;\n  gap: 15px !important;\n  height: auto !important;\n  padding: 4px 10px !important;\n  border-top: 1px solid var(--ag-border-color);\n  font-size: 0.6875rem;\n}\n\n/* Page Size 영역 정렬 */\n:deep(.ag-paging-page-size) {\n  display: inline-flex !important;\n  align-items: center !important;\n  margin: 0 !important;\n}\n\n:deep(.ag-paging-page-size .ag-picker-field-wrapper) {\n  height: 24px !important;\n  min-height: 24px !important;\n  display: inline-flex !important;\n  align-items: center !important;\n  margin: 0 5px !important;\n}\n\n:deep(.ag-paging-page-size .ag-label) {\n  margin: 0 !important;\n  display: inline-flex !important;\n  align-items: center !important;\n}\n\n/* Row Summary 정렬 */\n:deep(.ag-paging-row-summary-panel) {\n  display: inline-flex !important;\n  align-items: center !important;\n  margin: 0 !important;\n}\n\n/* Page Summary (버튼 그룹) 정렬 */\n:deep(.ag-paging-page-summary-panel) {\n  display: inline-flex !important;\n  align-items: center !important;\n  margin: 0 !important;\n  gap: 5px !important;\n}\n\n/* Pagination 버튼 높이 통일 */\n:deep(.ag-paging-page-summary-panel .ag-paging-button) {\n  display: inline-flex !important;\n  align-items: center !important;\n  justify-content: center !important;\n  height: 24px !important;\n  margin: 0 !important;\n}\n\n/* ========================================\n   패턴 9: AG-Grid 스타일 향상\n   ======================================== */\n\n:deep(.ag-root-wrapper) {\n  border: 1px solid hsl(var(--border));\n  border-radius: 0.375rem;\n}\n\n/* ── Header ──────────────────────────────────────────────────────────── */\n:deep(.ag-header) {\n  border-bottom: 1px solid hsl(var(--border));\n  font-weight: 600;\n}\n\n:deep(.ag-header-row:not(.ag-floating-filter)) {\n  min-height: var(--j-grid-header-h) !important;\n  height: var(--j-grid-header-h) !important;\n}\n\n:deep(.ag-header-cell) {\n  color: hsl(var(--foreground));\n  font-size: 0.75rem;\n  padding: 0 0.5rem;\n  display: flex;\n  align-items: center;\n}\n\n/* Floating Filter: 헤더와 명확히 구분되는 입력 영역 */\n:deep(.ag-header-row.ag-floating-filter) {\n  min-height: var(--j-grid-filter-h) !important;\n  height: var(--j-grid-filter-h) !important;\n  background-color: hsl(var(--card));\n  border-top: 1px solid hsl(var(--border) / 0.5);\n}\n\n:deep(.ag-floating-filter-body) {\n  min-height: var(--j-grid-filter-h);\n}\n\n:deep(.ag-floating-filter-body input),\n:deep(.ag-floating-filter-body .ag-input-field-input),\n:deep(.ag-floating-filter-body .ag-picker-field-wrapper) {\n  height: 20px !important;\n  min-height: 20px !important;\n  font-size: 0.75rem;\n  background-color: hsl(var(--background)) !important;\n  border: 1px solid hsl(var(--border)) !important;\n  border-radius: 3px !important;\n  padding: 0 4px !important;\n  color: hsl(var(--foreground)) !important;\n}\n\n:deep(.ag-floating-filter-body input:focus),\n:deep(.ag-floating-filter-body .ag-input-field-input:focus) {\n  border-color: hsl(var(--primary)) !important;\n  outline: none !important;\n}\n\n/* ── Rows ────────────────────────────────────────────────────────────── */\n:deep(.ag-row) {\n  min-height: var(--j-grid-row-h) !important;\n  height: var(--j-grid-row-h) !important;\n  transition: background-color 0.15s ease, box-shadow 0.15s ease;\n  cursor: pointer;\n}\n\n/* 선택된 행: 왼쪽 accent 기둥으로 명확한 시각적 선택 표시 (라이트/다크 모두) */\n:deep(.ag-row-selected) {\n  box-shadow: inset 4px 0 0 hsl(var(--primary));\n}\n\n/* ── Cells ───────────────────────────────────────────────────────────── */\n:deep(.ag-cell) {\n  line-height: 1.2;\n  padding: 0 0.5rem;\n  font-size: 0.75rem;\n  border-bottom: 1px solid hsl(var(--border) / 0.5);\n}\n\n:deep(.ag-cell-wrapper) {\n  align-items: center;\n}\n\n:deep(.ag-cell-value) {\n  display: flex;\n  align-items: center;\n  min-height: 100%;\n}\n\n/* 행 클릭 시 row number 셀에 보이는 강한 포커스 음영 제거 */\n:deep(.ag-cell.ag-row-number-cell.ag-cell-focus),\n:deep(.ag-cell.ag-row-number-cell:focus-within) {\n  box-shadow: none !important;\n  outline: none !important;\n}\n\n/* 셀 포커스 */\n:deep(.ag-cell.ag-cell-focus) {\n  box-shadow: inset 0 0 0 1px hsl(var(--ring) / 0.5) !important;\n}\n\n/* 인라인 편집 셀 */\n:deep(.ag-cell-inline-editing) {\n  padding: 0 !important;\n  border: none !important;\n  box-shadow: inset 0 0 0 1px hsl(var(--primary)) !important;\n  background-color: hsl(var(--background)) !important;\n}\n\n:deep(.ag-cell-inline-editing .ag-cell-editor),\n:deep(.ag-cell-inline-editing .ag-text-field-input-wrapper),\n:deep(.ag-cell-inline-editing .ag-input-field) {\n  height: 100% !important;\n  border: none !important;\n  outline: none !important;\n  background: transparent !important;\n  box-shadow: none !important;\n}\n\n:deep(.ag-cell-inline-editing input) {\n  height: 100% !important;\n  width: 100% !important;\n  padding: 0 0.5rem !important;\n  border: none !important;\n  outline: none !important;\n  background: transparent !important;\n  box-shadow: none !important;\n  font-size: 0.75rem !important;\n  color: hsl(var(--foreground)) !important;\n}\n\n/* ── Checkbox 셀 중앙정렬 (col-id 속성 선택자 — 신뢰할 수 있는 접근) ── */\n:deep(.ag-cell[col-id=\"rowSelection\"]) {\n  display: flex !important;\n  justify-content: center !important;\n  align-items: center !important;\n  padding: 0 !important;\n}\n:deep(.ag-cell[col-id=\"rowSelection\"] .ag-cell-wrapper) {\n  width: auto !important;\n  flex: none !important;\n}\n:deep(.ag-header-cell[col-id=\"rowSelection\"] .ag-header-cell-comp-wrapper) {\n  justify-content: center !important;\n}\n\n/* ── Action Buttons (JS 렌더러 — CSS variable 브릿지) ─────────────────── */\n:deep(.j-action-btn) {\n  padding: 1px 8px;\n  font-size: 0.75rem;\n  border: 1px solid hsl(var(--border));\n  border-radius: 3px;\n  background-color: hsl(var(--card));\n  color: hsl(var(--foreground));\n  cursor: pointer;\n  transition: all 0.15s ease;\n  white-space: nowrap;\n}\n\n:deep(.j-action-btn:hover) {\n  background-color: hsl(var(--accent));\n  border-color: hsl(var(--primary) / 0.3);\n}\n\n:deep(.j-action-btn-danger) {\n  border-color: hsl(var(--destructive) / 0.4);\n  background-color: hsl(var(--destructive) / 0.06);\n  color: hsl(var(--destructive));\n}\n\n:deep(.j-action-btn-danger:hover) {\n  background-color: hsl(var(--destructive) / 0.15);\n}\n\n/* ── No-Rows 오버레이 (한글) ──────────────────────────────────────── */\n:deep(.j-grid-no-rows) {\n  color: hsl(var(--muted-foreground));\n  font-size: 0.75rem;\n}\n</style>\n"],"names":["ModuleRegistry","AllCommunityModule","AllEnterpriseModule","jTheme","themeQuartz","isDark","ref","gridContainerRef","darkObserver","watch","dark","onMounted","onUnmounted","props","__props","emit","__emit","gridApi","gridColumnApi","ActionButtonsCellRenderer","params","buttons","rowData","visibleButtons","btn","container","button","e","actionButtonsColumn","computed","processedColumnDefs","columns","target","gridOptions","useFloatingFilters","effectivePagination","data","__expose","onGridReady","onRowClicked","event","onRowDoubleClicked","onCellClicked","onSelectionChanged","onCellValueChanged","_createElementBlock","_normalizeClass","_unref","cn","_createVNode","AgGridVue"],"mappings":"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"}