open-grid 1.0.1 → 1.0.6

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.
@@ -1 +0,0 @@
1
- {"version":3,"file":"open-grid-react.cjs","sources":["../src/react/OpenGrid.tsx"],"sourcesContent":["import React, { useRef, useEffect, useCallback, CSSProperties } from 'react';\nimport { OpenGrid } from '../core/OpenGrid.js';\nimport type { GridOptions, ColumnDef, OpenGridInstance } from '../core/types.js';\nimport '../styles/base.css';\n\nexport interface OpenGridProps<T extends Record<string, any> = any> {\n data?: T[];\n columns: ColumnDef<T>[];\n height?: number | string;\n width?: number | string;\n editable?: boolean;\n sortable?: boolean;\n filterable?: boolean;\n rowNumber?: boolean;\n checkColumn?: boolean;\n frozenColumns?: number;\n theme?: string;\n options?: Partial<GridOptions<T>>;\n style?: CSSProperties;\n className?: string;\n\n stateColumn?: boolean;\n draggable?: boolean;\n\n onReady?: (grid: OpenGridInstance<T>) => void;\n onDataChange?: (data: T[]) => void;\n onCellClick?: (e: any) => void;\n onRowClick?: (e: any) => void;\n onEditEnd?: (e: any) => void;\n onSortChange?: (e: any) => void;\n onFilterChange?: (e: any) => void;\n onRowDrop?: (e: { fromIndex: number; toIndex: number }) => void;\n}\n\nexport function OpenGridReact<T extends Record<string, any> = any>({\n data,\n columns,\n height = 400,\n width = '100%',\n editable = false,\n sortable = true,\n filterable = true,\n rowNumber = false,\n checkColumn = false,\n stateColumn = false,\n draggable = false,\n frozenColumns = 0,\n theme = 'default',\n options,\n style,\n className,\n onReady,\n onDataChange,\n onCellClick,\n onRowClick,\n onEditEnd,\n onSortChange,\n onFilterChange,\n onRowDrop,\n}: OpenGridProps<T>) {\n const containerRef = useRef<HTMLDivElement>(null);\n const gridRef = useRef<OpenGridInstance<T> | null>(null);\n\n const containerStyle: CSSProperties = {\n height: typeof height === 'number' ? `${height}px` : height,\n width: typeof width === 'number' ? `${width}px` : width,\n display: 'block',\n boxSizing: 'border-box',\n ...style,\n };\n\n useEffect(() => {\n if (!containerRef.current) return;\n\n const gridOptions: GridOptions<T> = {\n columns,\n height: '100%',\n width: '100%',\n editable,\n sortable,\n filterable,\n rowNumber,\n checkColumn,\n stateColumn,\n draggable,\n frozenColumns,\n theme,\n ...options,\n\n onReady: (grid) => {\n gridRef.current = grid;\n if (data?.length) grid.setData(data);\n onReady?.(grid);\n },\n ...(onDataChange && { onDataChange }),\n ...(onCellClick && { onCellClick }),\n ...(onRowClick && { onRowClick }),\n ...(onEditEnd && { onEditEnd }),\n ...(onSortChange && { onSortChange }),\n ...(onFilterChange && { onFilterChange }),\n ...(onRowDrop && { onRowDrop }),\n };\n\n const grid = new OpenGrid<T>(containerRef.current, gridOptions);\n gridRef.current = grid;\n\n return () => {\n grid.destroy();\n gridRef.current = null;\n };\n // theme은 별도 effect에서 처리하므로 deps에서 제외\n }, [columns, editable, sortable, filterable, rowNumber, checkColumn, stateColumn, draggable, frozenColumns]);\n\n // data 변경 감지\n useEffect(() => {\n if (gridRef.current && data) {\n gridRef.current.setData(data);\n }\n }, [data]);\n\n // theme 변경 감지 (그리드 재생성 없이 setTheme만 호출)\n useEffect(() => {\n if (gridRef.current) gridRef.current.setTheme(theme);\n }, [theme]);\n\n return (\n <div\n ref={containerRef}\n style={containerStyle}\n className={className}\n />\n );\n}\n\n// ref forwarder (외부에서 grid 인스턴스 접근)\nexport const OpenGridWithRef = React.forwardRef<\n OpenGridInstance,\n OpenGridProps\n>((props, ref) => {\n const innerRef = useRef<HTMLDivElement>(null);\n const gridRef = useRef<OpenGridInstance | null>(null);\n\n useEffect(() => {\n if (gridRef.current && ref) {\n if (typeof ref === 'function') ref(gridRef.current);\n else (ref as React.MutableRefObject<OpenGridInstance | null>).current = gridRef.current;\n }\n });\n\n return <OpenGridReact {...props} />;\n});\n\nOpenGridWithRef.displayName = 'OpenGrid';\n"],"names":["OpenGridReact","data","columns","height","width","editable","sortable","filterable","rowNumber","checkColumn","stateColumn","draggable","frozenColumns","theme","options","style","className","onReady","onDataChange","onCellClick","onRowClick","onEditEnd","onSortChange","onFilterChange","onRowDrop","containerRef","useRef","gridRef","containerStyle","useEffect","gridOptions","grid","OpenGrid","jsx","OpenGridWithRef","React","props","ref"],"mappings":"6KAkCO,SAASA,EAAmD,CACjE,KAAAC,EACA,QAAAC,EACA,OAAAC,EAAS,IACT,MAAAC,EAAQ,OACR,SAAAC,EAAW,GACX,SAAAC,EAAW,GACX,WAAAC,EAAa,GACb,UAAAC,EAAY,GACZ,YAAAC,EAAc,GACd,YAAAC,EAAc,GACd,UAAAC,EAAY,GACZ,cAAAC,EAAgB,EAChB,MAAAC,EAAQ,UACR,QAAAC,EACA,MAAAC,EACA,UAAAC,EACA,QAAAC,EACA,aAAAC,EACA,YAAAC,EACA,WAAAC,EACA,UAAAC,EACA,aAAAC,EACA,eAAAC,EACA,UAAAC,CACF,EAAqB,CACnB,MAAMC,EAAeC,EAAAA,OAAuB,IAAI,EAC1CC,EAAUD,EAAAA,OAAmC,IAAI,EAEjDE,EAAgC,CACpC,OAAQ,OAAOzB,GAAW,SAAW,GAAGA,CAAM,KAAOA,EACrD,MAAO,OAAOC,GAAU,SAAW,GAAGA,CAAK,KAAOA,EAClD,QAAS,QACT,UAAW,aACX,GAAGW,CAAA,EAGLc,OAAAA,EAAAA,UAAU,IAAM,CACd,GAAI,CAACJ,EAAa,QAAS,OAE3B,MAAMK,EAA8B,CAClC,QAAA5B,EACA,OAAQ,OACR,MAAO,OACP,SAAAG,EACA,SAAAC,EACA,WAAAC,EACA,UAAAC,EACA,YAAAC,EACA,YAAAC,EACA,UAAAC,EACA,cAAAC,EACA,MAAAC,EACA,GAAGC,EAEH,QAAUiB,GAAS,CACjBJ,EAAQ,QAAUI,EACd9B,GAAA,MAAAA,EAAM,QAAQ8B,EAAK,QAAQ9B,CAAI,EACnCgB,GAAA,MAAAA,EAAUc,EACZ,EACA,GAAIb,GAAgB,CAAE,aAAAA,CAAA,EACtB,GAAIC,GAAe,CAAE,YAAAA,CAAA,EACrB,GAAIC,GAAc,CAAE,WAAAA,CAAA,EACpB,GAAIC,GAAa,CAAE,UAAAA,CAAA,EACnB,GAAIC,GAAgB,CAAE,aAAAA,CAAA,EACtB,GAAIC,GAAkB,CAAE,eAAAA,CAAA,EACxB,GAAIC,GAAa,CAAE,UAAAA,CAAA,CAAU,EAGzBO,EAAO,IAAIC,EAAAA,SAAYP,EAAa,QAASK,CAAW,EAC9D,OAAAH,EAAQ,QAAUI,EAEX,IAAM,CACXA,EAAK,QAAA,EACLJ,EAAQ,QAAU,IACpB,CAEF,EAAG,CAACzB,EAASG,EAAUC,EAAUC,EAAYC,EAAWC,EAAaC,EAAaC,EAAWC,CAAa,CAAC,EAG3GiB,EAAAA,UAAU,IAAM,CACVF,EAAQ,SAAW1B,GACrB0B,EAAQ,QAAQ,QAAQ1B,CAAI,CAEhC,EAAG,CAACA,CAAI,CAAC,EAGT4B,EAAAA,UAAU,IAAM,CACVF,EAAQ,SAASA,EAAQ,QAAQ,SAASd,CAAK,CACrD,EAAG,CAACA,CAAK,CAAC,EAGRoB,EAAAA,IAAC,MAAA,CACC,IAAKR,EACL,MAAOG,EACP,UAAAZ,CAAA,CAAA,CAGN,CAGO,MAAMkB,EAAkBC,EAAM,WAGnC,CAACC,EAAOC,IAAQ,CACCX,EAAAA,OAAuB,IAAI,EAC5C,MAAMC,EAAUD,EAAAA,OAAgC,IAAI,EAEpDG,OAAAA,EAAAA,UAAU,IAAM,CACVF,EAAQ,SAAWU,IACjB,OAAOA,GAAQ,WAAYA,EAAIV,EAAQ,OAAO,EAC5CU,EAAwD,QAAUV,EAAQ,QAEpF,CAAC,EAEMM,MAACjC,EAAA,CAAe,GAAGoC,CAAA,CAAO,CACnC,CAAC,EAEDF,EAAgB,YAAc"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"open-grid-react.js","sources":["../src/react/OpenGrid.tsx"],"sourcesContent":["import React, { useRef, useEffect, useCallback, CSSProperties } from 'react';\nimport { OpenGrid } from '../core/OpenGrid.js';\nimport type { GridOptions, ColumnDef, OpenGridInstance } from '../core/types.js';\nimport '../styles/base.css';\n\nexport interface OpenGridProps<T extends Record<string, any> = any> {\n data?: T[];\n columns: ColumnDef<T>[];\n height?: number | string;\n width?: number | string;\n editable?: boolean;\n sortable?: boolean;\n filterable?: boolean;\n rowNumber?: boolean;\n checkColumn?: boolean;\n frozenColumns?: number;\n theme?: string;\n options?: Partial<GridOptions<T>>;\n style?: CSSProperties;\n className?: string;\n\n stateColumn?: boolean;\n draggable?: boolean;\n\n onReady?: (grid: OpenGridInstance<T>) => void;\n onDataChange?: (data: T[]) => void;\n onCellClick?: (e: any) => void;\n onRowClick?: (e: any) => void;\n onEditEnd?: (e: any) => void;\n onSortChange?: (e: any) => void;\n onFilterChange?: (e: any) => void;\n onRowDrop?: (e: { fromIndex: number; toIndex: number }) => void;\n}\n\nexport function OpenGridReact<T extends Record<string, any> = any>({\n data,\n columns,\n height = 400,\n width = '100%',\n editable = false,\n sortable = true,\n filterable = true,\n rowNumber = false,\n checkColumn = false,\n stateColumn = false,\n draggable = false,\n frozenColumns = 0,\n theme = 'default',\n options,\n style,\n className,\n onReady,\n onDataChange,\n onCellClick,\n onRowClick,\n onEditEnd,\n onSortChange,\n onFilterChange,\n onRowDrop,\n}: OpenGridProps<T>) {\n const containerRef = useRef<HTMLDivElement>(null);\n const gridRef = useRef<OpenGridInstance<T> | null>(null);\n\n const containerStyle: CSSProperties = {\n height: typeof height === 'number' ? `${height}px` : height,\n width: typeof width === 'number' ? `${width}px` : width,\n display: 'block',\n boxSizing: 'border-box',\n ...style,\n };\n\n useEffect(() => {\n if (!containerRef.current) return;\n\n const gridOptions: GridOptions<T> = {\n columns,\n height: '100%',\n width: '100%',\n editable,\n sortable,\n filterable,\n rowNumber,\n checkColumn,\n stateColumn,\n draggable,\n frozenColumns,\n theme,\n ...options,\n\n onReady: (grid) => {\n gridRef.current = grid;\n if (data?.length) grid.setData(data);\n onReady?.(grid);\n },\n ...(onDataChange && { onDataChange }),\n ...(onCellClick && { onCellClick }),\n ...(onRowClick && { onRowClick }),\n ...(onEditEnd && { onEditEnd }),\n ...(onSortChange && { onSortChange }),\n ...(onFilterChange && { onFilterChange }),\n ...(onRowDrop && { onRowDrop }),\n };\n\n const grid = new OpenGrid<T>(containerRef.current, gridOptions);\n gridRef.current = grid;\n\n return () => {\n grid.destroy();\n gridRef.current = null;\n };\n // theme은 별도 effect에서 처리하므로 deps에서 제외\n }, [columns, editable, sortable, filterable, rowNumber, checkColumn, stateColumn, draggable, frozenColumns]);\n\n // data 변경 감지\n useEffect(() => {\n if (gridRef.current && data) {\n gridRef.current.setData(data);\n }\n }, [data]);\n\n // theme 변경 감지 (그리드 재생성 없이 setTheme만 호출)\n useEffect(() => {\n if (gridRef.current) gridRef.current.setTheme(theme);\n }, [theme]);\n\n return (\n <div\n ref={containerRef}\n style={containerStyle}\n className={className}\n />\n );\n}\n\n// ref forwarder (외부에서 grid 인스턴스 접근)\nexport const OpenGridWithRef = React.forwardRef<\n OpenGridInstance,\n OpenGridProps\n>((props, ref) => {\n const innerRef = useRef<HTMLDivElement>(null);\n const gridRef = useRef<OpenGridInstance | null>(null);\n\n useEffect(() => {\n if (gridRef.current && ref) {\n if (typeof ref === 'function') ref(gridRef.current);\n else (ref as React.MutableRefObject<OpenGridInstance | null>).current = gridRef.current;\n }\n });\n\n return <OpenGridReact {...props} />;\n});\n\nOpenGridWithRef.displayName = 'OpenGrid';\n"],"names":["OpenGridReact","data","columns","height","width","editable","sortable","filterable","rowNumber","checkColumn","stateColumn","draggable","frozenColumns","theme","options","style","className","onReady","onDataChange","onCellClick","onRowClick","onEditEnd","onSortChange","onFilterChange","onRowDrop","containerRef","useRef","gridRef","containerStyle","useEffect","gridOptions","grid","OpenGrid","jsx","OpenGridWithRef","React","props","ref"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"open-grid-vue.cjs","sources":["../src/vue/OpenGrid.vue"],"sourcesContent":["<template>\n <div ref=\"containerRef\" class=\"og-vue-wrapper\" :style=\"containerStyle\" />\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, onMounted, onUnmounted, watch, shallowRef, computed } from 'vue';\nimport { OpenGrid } from '../core/OpenGrid.js';\nimport type { GridOptions, OpenGridInstance } from '../core/types.js';\nimport type { OpenGridProps, OpenGridEmits } from './types.js';\nimport '../styles/base.css';\n\nconst props = withDefaults(defineProps<OpenGridProps>(), {\n data: () => [],\n height: 400,\n width: '100%',\n editable: false,\n sortable: true,\n filterable: true,\n rowNumber: false,\n checkColumn: false,\n stateColumn: false,\n draggable: false,\n frozenColumns: 0,\n theme: 'default',\n});\n\nconst emit = defineEmits<OpenGridEmits>();\n\nconst containerRef = ref<HTMLElement>();\nconst gridInstance = shallowRef<OpenGridInstance | null>(null);\n\n// dataChange 루프 방지: 그리드에서 발행한 데이터를 watch가 다시 setData하지 않도록 추적\nlet _lastEmittedData: any[] | null = null;\n\nconst containerStyle = computed(() => ({\n height: typeof props.height === 'number' ? `${props.height}px` : props.height,\n width: typeof props.width === 'number' ? `${props.width}px` : props.width,\n}));\n\nonMounted(() => {\n if (!containerRef.value) return;\n\n const options: GridOptions = {\n columns: props.columns,\n height: '100%',\n width: '100%',\n editable: props.editable,\n sortable: props.sortable,\n filterable: props.filterable,\n rowNumber: props.rowNumber,\n checkColumn: props.checkColumn,\n stateColumn: props.stateColumn,\n draggable: props.draggable,\n frozenColumns: props.frozenColumns,\n theme: props.theme,\n ...props.options,\n\n onReady: (grid) => {\n if (props.data?.length) grid.setData(props.data);\n emit('ready', grid);\n },\n onCellClick: (e) => emit('cell-click', e),\n onRowClick: (e) => emit('row-click', e),\n onEditEnd: (e) => emit('edit-end', e),\n onSortChange: (e) => emit('sort-change', e),\n onFilterChange: (e) => emit('filter-change', e),\n onDataChange: (data) => {\n _lastEmittedData = data;\n emit('update:data', data);\n },\n };\n\n gridInstance.value = new OpenGrid(containerRef.value, options);\n});\n\n// data prop 변경 감지 → 그리드 갱신 (그리드 자신이 발행한 데이터는 무시하여 루프 방지)\nwatch(() => props.data, (newData) => {\n if (!gridInstance.value || !newData) return;\n if (newData === _lastEmittedData) return;\n gridInstance.value.setData(newData);\n}, { deep: false });\n\n// theme prop 변경 감지 → setTheme 호출\nwatch(() => props.theme, (newTheme) => {\n if (gridInstance.value && newTheme) {\n gridInstance.value.setTheme(newTheme);\n }\n});\n\n// columns 변경 감지\nwatch(() => props.columns, (newCols) => {\n if (gridInstance.value) {\n gridInstance.value.applyColumns(newCols);\n }\n}, { deep: false });\n\nonUnmounted(() => {\n gridInstance.value?.destroy();\n gridInstance.value = null;\n});\n\n// 그리드 인스턴스 외부 노출\ndefineExpose({ grid: gridInstance });\n</script>\n\n<style scoped>\n.og-vue-wrapper {\n display: block;\n box-sizing: border-box;\n}\n</style>\n"],"names":["props","__props","emit","__emit","containerRef","ref","gridInstance","shallowRef","_lastEmittedData","containerStyle","computed","onMounted","options","grid","_a","e","data","OpenGrid","watch","newData","newTheme","newCols","onUnmounted","__expose","_createElementBlock"],"mappings":"6sBAWA,MAAMA,EAAQC,EAeRC,EAAOC,EAEPC,EAAeC,EAAAA,IAAA,EACfC,EAAeC,EAAAA,WAAoC,IAAI,EAG7D,IAAIC,EAAiC,KAErC,MAAMC,EAAiBC,EAAAA,SAAS,KAAO,CACrC,OAAQ,OAAOV,EAAM,QAAW,SAAW,GAAGA,EAAM,MAAM,KAAOA,EAAM,OACvE,MAAO,OAAOA,EAAM,OAAU,SAAW,GAAGA,EAAM,KAAK,KAAOA,EAAM,KAAA,EACpE,EAEFW,OAAAA,EAAAA,UAAU,IAAM,CACd,GAAI,CAACP,EAAa,MAAO,OAEzB,MAAMQ,EAAuB,CAC3B,QAASZ,EAAM,QACf,OAAQ,OACR,MAAO,OACP,SAAUA,EAAM,SAChB,SAAUA,EAAM,SAChB,WAAYA,EAAM,WAClB,UAAWA,EAAM,UACjB,YAAaA,EAAM,YACnB,YAAaA,EAAM,YACnB,UAAWA,EAAM,UACjB,cAAeA,EAAM,cACrB,MAAOA,EAAM,MACb,GAAGA,EAAM,QAET,QAAUa,GAAS,QACbC,EAAAd,EAAM,OAAN,MAAAc,EAAY,QAAQD,EAAK,QAAQb,EAAM,IAAI,EAC/CE,EAAK,QAASW,CAAI,CACpB,EACA,YAAcE,GAAMb,EAAK,aAAca,CAAC,EACxC,WAAaA,GAAMb,EAAK,YAAaa,CAAC,EACtC,UAAYA,GAAMb,EAAK,WAAYa,CAAC,EACpC,aAAeA,GAAMb,EAAK,cAAea,CAAC,EAC1C,eAAiBA,GAAMb,EAAK,gBAAiBa,CAAC,EAC9C,aAAeC,GAAS,CACtBR,EAAmBQ,EACnBd,EAAK,cAAec,CAAI,CAC1B,CAAA,EAGFV,EAAa,MAAQ,IAAIW,EAAAA,SAASb,EAAa,MAAOQ,CAAO,CAC/D,CAAC,EAGDM,EAAAA,MAAM,IAAMlB,EAAM,KAAOmB,GAAY,CAC/B,CAACb,EAAa,OAAS,CAACa,GACxBA,IAAYX,GAChBF,EAAa,MAAM,QAAQa,CAAO,CACpC,EAAG,CAAE,KAAM,GAAO,EAGlBD,EAAAA,MAAM,IAAMlB,EAAM,MAAQoB,GAAa,CACjCd,EAAa,OAASc,GACxBd,EAAa,MAAM,SAASc,CAAQ,CAExC,CAAC,EAGDF,EAAAA,MAAM,IAAMlB,EAAM,QAAUqB,GAAY,CAClCf,EAAa,OACfA,EAAa,MAAM,aAAae,CAAO,CAE3C,EAAG,CAAE,KAAM,GAAO,EAElBC,EAAAA,YAAY,IAAM,QAChBR,EAAAR,EAAa,QAAb,MAAAQ,EAAoB,UACpBR,EAAa,MAAQ,IACvB,CAAC,EAGDiB,EAAa,CAAE,KAAMjB,EAAc,wBArGjCkB,EAAAA,mBAAyE,MAAA,SAAhE,eAAJ,IAAIpB,EAAe,MAAM,iBAAkB,uBAAOK,EAAA,KAAc,CAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"open-grid-vue.js","sources":["../src/vue/OpenGrid.vue"],"sourcesContent":["<template>\n <div ref=\"containerRef\" class=\"og-vue-wrapper\" :style=\"containerStyle\" />\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, onMounted, onUnmounted, watch, shallowRef, computed } from 'vue';\nimport { OpenGrid } from '../core/OpenGrid.js';\nimport type { GridOptions, OpenGridInstance } from '../core/types.js';\nimport type { OpenGridProps, OpenGridEmits } from './types.js';\nimport '../styles/base.css';\n\nconst props = withDefaults(defineProps<OpenGridProps>(), {\n data: () => [],\n height: 400,\n width: '100%',\n editable: false,\n sortable: true,\n filterable: true,\n rowNumber: false,\n checkColumn: false,\n stateColumn: false,\n draggable: false,\n frozenColumns: 0,\n theme: 'default',\n});\n\nconst emit = defineEmits<OpenGridEmits>();\n\nconst containerRef = ref<HTMLElement>();\nconst gridInstance = shallowRef<OpenGridInstance | null>(null);\n\n// dataChange 루프 방지: 그리드에서 발행한 데이터를 watch가 다시 setData하지 않도록 추적\nlet _lastEmittedData: any[] | null = null;\n\nconst containerStyle = computed(() => ({\n height: typeof props.height === 'number' ? `${props.height}px` : props.height,\n width: typeof props.width === 'number' ? `${props.width}px` : props.width,\n}));\n\nonMounted(() => {\n if (!containerRef.value) return;\n\n const options: GridOptions = {\n columns: props.columns,\n height: '100%',\n width: '100%',\n editable: props.editable,\n sortable: props.sortable,\n filterable: props.filterable,\n rowNumber: props.rowNumber,\n checkColumn: props.checkColumn,\n stateColumn: props.stateColumn,\n draggable: props.draggable,\n frozenColumns: props.frozenColumns,\n theme: props.theme,\n ...props.options,\n\n onReady: (grid) => {\n if (props.data?.length) grid.setData(props.data);\n emit('ready', grid);\n },\n onCellClick: (e) => emit('cell-click', e),\n onRowClick: (e) => emit('row-click', e),\n onEditEnd: (e) => emit('edit-end', e),\n onSortChange: (e) => emit('sort-change', e),\n onFilterChange: (e) => emit('filter-change', e),\n onDataChange: (data) => {\n _lastEmittedData = data;\n emit('update:data', data);\n },\n };\n\n gridInstance.value = new OpenGrid(containerRef.value, options);\n});\n\n// data prop 변경 감지 → 그리드 갱신 (그리드 자신이 발행한 데이터는 무시하여 루프 방지)\nwatch(() => props.data, (newData) => {\n if (!gridInstance.value || !newData) return;\n if (newData === _lastEmittedData) return;\n gridInstance.value.setData(newData);\n}, { deep: false });\n\n// theme prop 변경 감지 → setTheme 호출\nwatch(() => props.theme, (newTheme) => {\n if (gridInstance.value && newTheme) {\n gridInstance.value.setTheme(newTheme);\n }\n});\n\n// columns 변경 감지\nwatch(() => props.columns, (newCols) => {\n if (gridInstance.value) {\n gridInstance.value.applyColumns(newCols);\n }\n}, { deep: false });\n\nonUnmounted(() => {\n gridInstance.value?.destroy();\n gridInstance.value = null;\n});\n\n// 그리드 인스턴스 외부 노출\ndefineExpose({ grid: gridInstance });\n</script>\n\n<style scoped>\n.og-vue-wrapper {\n display: block;\n box-sizing: border-box;\n}\n</style>\n"],"names":["props","__props","emit","__emit","containerRef","ref","gridInstance","shallowRef","_lastEmittedData","containerStyle","computed","onMounted","options","grid","_a","e","data","OpenGrid","watch","newData","newTheme","newCols","onUnmounted","__expose","_createElementBlock"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAWA,UAAMA,IAAQC,GAeRC,IAAOC,GAEPC,IAAeC,EAAA,GACfC,IAAeC,EAAoC,IAAI;AAG7D,QAAIC,IAAiC;AAErC,UAAMC,IAAiBC,EAAS,OAAO;AAAA,MACrC,QAAQ,OAAOV,EAAM,UAAW,WAAW,GAAGA,EAAM,MAAM,OAAOA,EAAM;AAAA,MACvE,OAAO,OAAOA,EAAM,SAAU,WAAW,GAAGA,EAAM,KAAK,OAAOA,EAAM;AAAA,IAAA,EACpE;AAEF,WAAAW,EAAU,MAAM;AACd,UAAI,CAACP,EAAa,MAAO;AAEzB,YAAMQ,IAAuB;AAAA,QAC3B,SAASZ,EAAM;AAAA,QACf,QAAQ;AAAA,QACR,OAAO;AAAA,QACP,UAAUA,EAAM;AAAA,QAChB,UAAUA,EAAM;AAAA,QAChB,YAAYA,EAAM;AAAA,QAClB,WAAWA,EAAM;AAAA,QACjB,aAAaA,EAAM;AAAA,QACnB,aAAaA,EAAM;AAAA,QACnB,WAAWA,EAAM;AAAA,QACjB,eAAeA,EAAM;AAAA,QACrB,OAAOA,EAAM;AAAA,QACb,GAAGA,EAAM;AAAA,QAET,SAAS,CAACa,MAAS;;AACjB,WAAIC,IAAAd,EAAM,SAAN,QAAAc,EAAY,UAAQD,EAAK,QAAQb,EAAM,IAAI,GAC/CE,EAAK,SAASW,CAAI;AAAA,QACpB;AAAA,QACA,aAAa,CAACE,MAAMb,EAAK,cAAca,CAAC;AAAA,QACxC,YAAY,CAACA,MAAMb,EAAK,aAAaa,CAAC;AAAA,QACtC,WAAW,CAACA,MAAMb,EAAK,YAAYa,CAAC;AAAA,QACpC,cAAc,CAACA,MAAMb,EAAK,eAAea,CAAC;AAAA,QAC1C,gBAAgB,CAACA,MAAMb,EAAK,iBAAiBa,CAAC;AAAA,QAC9C,cAAc,CAACC,MAAS;AACtB,UAAAR,IAAmBQ,GACnBd,EAAK,eAAec,CAAI;AAAA,QAC1B;AAAA,MAAA;AAGF,MAAAV,EAAa,QAAQ,IAAIW,EAASb,EAAa,OAAOQ,CAAO;AAAA,IAC/D,CAAC,GAGDM,EAAM,MAAMlB,EAAM,MAAM,CAACmB,MAAY;AACnC,MAAI,CAACb,EAAa,SAAS,CAACa,KACxBA,MAAYX,KAChBF,EAAa,MAAM,QAAQa,CAAO;AAAA,IACpC,GAAG,EAAE,MAAM,IAAO,GAGlBD,EAAM,MAAMlB,EAAM,OAAO,CAACoB,MAAa;AACrC,MAAId,EAAa,SAASc,KACxBd,EAAa,MAAM,SAASc,CAAQ;AAAA,IAExC,CAAC,GAGDF,EAAM,MAAMlB,EAAM,SAAS,CAACqB,MAAY;AACtC,MAAIf,EAAa,SACfA,EAAa,MAAM,aAAae,CAAO;AAAA,IAE3C,GAAG,EAAE,MAAM,IAAO,GAElBC,EAAY,MAAM;;AAChB,OAAAR,IAAAR,EAAa,UAAb,QAAAQ,EAAoB,WACpBR,EAAa,QAAQ;AAAA,IACvB,CAAC,GAGDiB,EAAa,EAAE,MAAMjB,GAAc,mBArGjCkB,EAAyE,OAAA;AAAA,eAAhE;AAAA,MAAJ,KAAIpB;AAAA,MAAe,OAAM;AAAA,MAAkB,SAAOK,EAAA,KAAc;AAAA,IAAA;;;;;;;;"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"open-grid.cjs","sources":["../src/core/GridShuttle.ts","../src/core/OrgChart.ts","../src/core/XmlConverter.ts"],"sourcesContent":["// ============================================================\n// 그리드 셔틀 — 두 그리드 사이에 화살표 버튼을 두고\n// \"체크된 행\"을 드래그 없이 버튼으로 이동(move)시킨다.\n// 이동 자체는 grid.moveCheckedTo() 를 호출 → crossGridMapping(필드 매핑)과\n// 3단계 이벤트가 드래그 이동과 100% 동일하게 적용된다.\n// ============================================================\nimport type { OpenGridInstance } from './types.js';\n\nexport interface GridShuttleOptions {\n /** 버튼 배치 방향 (기본 'vertical') */\n layout?: 'vertical' | 'horizontal';\n /** 전체 이동(≫ ≪) 버튼도 표시 (기본 false) */\n includeAll?: boolean;\n /** 버튼 라벨 커스터마이즈 */\n labels?: { toRight?: string; toLeft?: string; allRight?: string; allLeft?: string };\n}\n\nexport class GridShuttle {\n private _el: HTMLElement;\n\n constructor(\n private _left: OpenGridInstance,\n private _right: OpenGridInstance,\n mount: HTMLElement,\n opts: GridShuttleOptions = {},\n ) {\n const wrap = document.createElement('div');\n wrap.className = 'og-shuttle';\n wrap.style.cssText =\n `display:flex;gap:6px;align-items:center;justify-content:center;` +\n `flex-direction:${opts.layout === 'horizontal' ? 'row' : 'column'};`;\n\n const mk = (label: string, title: string, fn: () => void): HTMLButtonElement => {\n const b = document.createElement('button');\n b.type = 'button';\n b.className = 'og-shuttle-btn';\n b.textContent = label;\n b.title = title;\n b.style.cssText =\n 'min-width:34px;height:30px;padding:0 8px;border:1px solid #bbb;border-radius:7px;' +\n 'background:#fff;cursor:pointer;font-size:14px;color:#444;line-height:1;' +\n 'box-shadow:0 1px 2px rgba(0,0,0,0.06);';\n b.addEventListener('mouseover', () => { b.style.background = '#f0f6ff'; b.style.borderColor = '#1976d2'; });\n b.addEventListener('mouseout', () => { b.style.background = '#fff'; b.style.borderColor = '#bbb'; });\n b.addEventListener('click', fn);\n return b;\n };\n\n const L = opts.labels ?? {};\n wrap.appendChild(mk(L.toRight ?? '▶', '체크한 행을 오른쪽 그리드로 이동',\n () => { void this._left.moveCheckedTo(this._right); }));\n wrap.appendChild(mk(L.toLeft ?? '◀', '체크한 행을 왼쪽 그리드로 이동',\n () => { void this._right.moveCheckedTo(this._left); }));\n\n if (opts.includeAll) {\n wrap.appendChild(mk(L.allRight ?? '⏩', '왼쪽 전체를 오른쪽으로 이동',\n () => { void this._moveAll(this._left, this._right); }));\n wrap.appendChild(mk(L.allLeft ?? '⏪', '오른쪽 전체를 왼쪽으로 이동',\n () => { void this._moveAll(this._right, this._left); }));\n }\n\n mount.appendChild(wrap);\n this._el = wrap;\n }\n\n private _moveAll(from: OpenGridInstance, to: OpenGridInstance): void {\n const n = from.getData().length;\n if (n > 0) void from.moveRowsTo(to, Array.from({ length: n }, (_, i) => i));\n }\n\n destroy(): void { this._el.remove(); }\n}\n\n/** 두 그리드 사이에 셔틀(화살표 이동) 버튼을 만든다 */\nexport function createGridShuttle(\n left: OpenGridInstance,\n right: OpenGridInstance,\n mount: HTMLElement,\n opts?: GridShuttleOptions,\n): GridShuttle {\n return new GridShuttle(left, right, mount, opts);\n}\n","import { buildTree, TreeNode } from './TreeEngine.js';\n\nexport interface OrgChartColumnDef {\n field: string;\n className?: string;\n style?: string | ((value: any, row: Record<string, any>) => string);\n renderer?: (value: any, row: Record<string, any>) => HTMLElement | string;\n}\n\nexport interface OrgChartOptions {\n idField: string;\n parentIdField: string;\n columns: OrgChartColumnDef[];\n nodeWidth?: number;\n nodeHeight?: number;\n levelGap?: number;\n siblingGap?: number;\n expandOnLoad?: boolean;\n onNodeClick?: (id: any, data: Record<string, any>) => void;\n}\n\ninterface LayoutInfo { x: number; y: number; }\n\nexport class OrgChart {\n private _container: HTMLElement;\n private _opts: Required<OrgChartOptions>;\n private _data: Record<string, any>[] = [];\n private _roots: TreeNode<any>[] = [];\n private _expandedKeys = new Set<any>();\n private _selectedId: any = null;\n\n constructor(selector: string | HTMLElement, opts: OrgChartOptions) {\n this._container = typeof selector === 'string'\n ? (document.querySelector(selector) as HTMLElement)\n : selector;\n this._opts = {\n nodeWidth: 160, nodeHeight: 72, levelGap: 52, siblingGap: 20,\n expandOnLoad: true, onNodeClick: () => {},\n ...opts,\n };\n this._container.classList.add('og-orgchart');\n }\n\n setData(data: Record<string, any>[]): void {\n this._data = data;\n const { idField, parentIdField, expandOnLoad } = this._opts;\n if (expandOnLoad && this._expandedKeys.size === 0) {\n data.forEach(r => this._expandedKeys.add(r[idField]));\n }\n this._roots = buildTree(data, { idField, parentIdField }, this._expandedKeys);\n this._render();\n }\n\n setTheme(theme: string): void {\n this._container.setAttribute('data-og-theme', theme);\n }\n\n expandAll(): void {\n const collect = (nodes: TreeNode<any>[]) => {\n for (const n of nodes) {\n this._expandedKeys.add(n._treeId);\n if (n.children.length) collect(n.children);\n }\n };\n collect(this._roots);\n this._rebuild();\n }\n\n collapseAll(): void {\n this._expandedKeys.clear();\n this._rebuild();\n }\n\n private _toggle(id: any): void {\n if (this._expandedKeys.has(id)) this._expandedKeys.delete(id);\n else this._expandedKeys.add(id);\n this._rebuild();\n }\n\n private _rebuild(): void {\n const { idField, parentIdField } = this._opts;\n this._roots = buildTree(this._data, { idField, parentIdField }, this._expandedKeys);\n this._render();\n }\n\n // ── 레이아웃 계산 (post-order: 리프부터 배치, 부모는 자식 중앙) ──\n private _calcLayout(): { layout: Map<any, LayoutInfo>; totalW: number; totalH: number } {\n const { nodeWidth, nodeHeight, levelGap, siblingGap } = this._opts;\n const layout = new Map<any, LayoutInfo>();\n let nextX = 0;\n\n const place = (node: TreeNode<any>): { minX: number; maxX: number } => {\n const y = node._depth * (nodeHeight + levelGap);\n const vis = node._expanded ? node.children : [];\n\n if (!vis.length) {\n const x = nextX;\n nextX += nodeWidth + siblingGap;\n layout.set(node._treeId, { x, y });\n return { minX: x, maxX: x };\n }\n\n let firstX = Infinity, lastX = -Infinity;\n for (const child of vis) {\n const { minX, maxX } = place(child);\n if (minX < firstX) firstX = minX;\n if (maxX > lastX) lastX = maxX;\n }\n // 자식들의 span 중앙에 부모 배치\n const x = firstX + (lastX - firstX + nodeWidth) / 2 - nodeWidth / 2;\n layout.set(node._treeId, { x, y });\n return { minX: firstX, maxX: lastX };\n };\n\n for (const root of this._roots) place(root);\n\n let maxX = 0, maxY = 0;\n for (const { x, y } of layout.values()) {\n if (x + nodeWidth > maxX) maxX = x + nodeWidth;\n if (y + nodeHeight > maxY) maxY = y + nodeHeight;\n }\n return { layout, totalW: maxX + siblingGap, totalH: maxY + levelGap + 16 };\n }\n\n // ── SVG 직선 헬퍼 ──\n private _line(svg: SVGSVGElement, x1: number, y1: number, x2: number, y2: number): void {\n const el = document.createElementNS('http://www.w3.org/2000/svg', 'line');\n el.setAttribute('x1', String(x1));\n el.setAttribute('y1', String(y1));\n el.setAttribute('x2', String(x2));\n el.setAttribute('y2', String(y2));\n el.setAttribute('class', 'og-orgchart-line');\n svg.appendChild(el);\n }\n\n // ── 렌더 ──\n private _render(): void {\n const { nodeWidth, nodeHeight, levelGap, columns } = this._opts;\n const { layout, totalW, totalH } = this._calcLayout();\n\n this._container.innerHTML = '';\n\n const wrap = document.createElement('div');\n wrap.className = 'og-orgchart-wrap';\n wrap.style.cssText = `width:${totalW}px;height:${totalH}px;`;\n\n // ① SVG 연결선\n const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');\n svg.setAttribute('width', String(totalW));\n svg.setAttribute('height', String(totalH));\n svg.style.cssText = 'position:absolute;top:0;left:0;pointer-events:none;overflow:visible;';\n\n const drawLines = (nodes: TreeNode<any>[]): void => {\n for (const node of nodes) {\n if (!node._expanded || !node.children.length) continue;\n const p = layout.get(node._treeId)!;\n const px = p.x + nodeWidth / 2;\n const py = p.y + nodeHeight;\n const midY = py + levelGap / 2;\n const vis = node.children;\n\n // 부모 → midY\n this._line(svg, px, py, px, midY);\n\n if (vis.length > 1) {\n const c0 = layout.get(vis[0]._treeId)!;\n const cn = layout.get(vis[vis.length - 1]._treeId)!;\n // 수평 브래킷\n this._line(svg, c0.x + nodeWidth / 2, midY, cn.x + nodeWidth / 2, midY);\n }\n for (const child of vis) {\n const ci = layout.get(child._treeId)!;\n const cx = ci.x + nodeWidth / 2;\n // midY → 자식 상단\n this._line(svg, cx, midY, cx, ci.y);\n }\n drawLines(vis);\n }\n };\n drawLines(this._roots);\n wrap.appendChild(svg);\n\n // ② 카드 렌더\n const renderNodes = (nodes: TreeNode<any>[]): void => {\n for (const node of nodes) {\n const info = layout.get(node._treeId);\n if (!info) continue;\n\n const card = document.createElement('div');\n card.className = 'og-orgchart-node';\n if (node._hasChildren) card.classList.add('og-orgchart-node--branch');\n if (node._expanded) card.classList.add('og-orgchart-node--expanded');\n if (this._selectedId === node._treeId) card.classList.add('og-orgchart-node--selected');\n card.style.cssText = `left:${info.x}px;top:${info.y}px;width:${nodeWidth}px;height:${nodeHeight}px;`;\n\n // 컬럼 렌더\n const content = document.createElement('div');\n content.className = 'og-orgchart-node-content';\n for (const col of columns) {\n const val = node.data[col.field];\n const div = document.createElement('div');\n div.className = 'og-orgchart-col' + (col.className ? ' ' + col.className : '');\n if (col.style) {\n const s = typeof col.style === 'function' ? col.style(val, node.data) : col.style;\n div.setAttribute('style', s);\n }\n if (col.renderer) {\n const out = col.renderer(val, node.data);\n if (typeof out === 'string') div.innerHTML = out;\n else div.appendChild(out);\n } else {\n div.textContent = val ?? '';\n }\n content.appendChild(div);\n }\n card.appendChild(content);\n\n // 확장/축소 토글 버튼 (카드 하단 중앙)\n if (node._hasChildren) {\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.className = 'og-orgchart-toggle';\n btn.setAttribute('aria-expanded', node._expanded ? 'true' : 'false');\n btn.setAttribute('aria-label', node._expanded ? '접기' : '펼치기');\n const icon = document.createElement('i');\n icon.setAttribute('aria-hidden', 'true');\n icon.className = node._expanded ? 'bi bi-dash-circle' : 'bi bi-plus-circle';\n btn.appendChild(icon);\n btn.addEventListener('click', (e) => {\n e.stopPropagation();\n this._toggle(node._treeId);\n });\n card.appendChild(btn);\n }\n\n card.addEventListener('click', () => {\n this._selectedId = node._treeId;\n this._opts.onNodeClick(node._treeId, node.data);\n // 선택 하이라이트만 갱신 (전체 재렌더 최소화)\n this._container.querySelectorAll('.og-orgchart-node--selected')\n .forEach(el => el.classList.remove('og-orgchart-node--selected'));\n card.classList.add('og-orgchart-node--selected');\n });\n\n wrap.appendChild(card);\n\n if (node._expanded && node.children.length) renderNodes(node.children);\n }\n };\n renderNodes(this._roots);\n\n this._container.appendChild(wrap);\n }\n}\n","/**\n * XmlConverter — XML ↔ 그리드 데이터 양방향 변환 유틸리티.\n *\n * 지원 포맷:\n * A. Element 방식 <row><name>홍길동</name></row>\n * B. Attribute 방식 <row name=\"홍길동\" />\n * C. SAP BAPI XML 응답 <RETURN><TYPE>S</TYPE><BELNR>...</BELNR></RETURN>\n * D. SAP IDoc XML <IDOC><E1HEADER SEGMENT=\"1\"><BUKRS>1000</BUKRS></IDOC>\n *\n * 외부 의존성 없음 — 브라우저 내장 DOMParser 사용.\n */\n\n// ─── 파싱 옵션 ────────────────────────────────────────────────\nexport interface XmlParseOptions {\n /** 루트 엘리먼트 태그명 (생략 시 문서 루트 자동 사용) */\n rootTag?: string;\n /** 행 엘리먼트 태그명 (생략 시 루트의 첫 번째 자식 자동 감지) */\n rowTag?: string;\n /** 값 추출 방식: 'element' | 'attribute' | 'auto'(기본) */\n mode?: 'element' | 'attribute' | 'auto';\n /** XML 태그명 → 그리드 field명 매핑 (생략 시 태그명 그대로 사용) */\n fieldMap?: Record<string, string>;\n /** 텍스트 값 앞뒤 공백 제거 (기본 true) */\n trim?: boolean;\n}\n\n// ─── 직렬화 옵션 ─────────────────────────────────────────────\nexport interface XmlStringifyOptions {\n /** 루트 태그명 (기본 'rows') */\n rootTag?: string;\n /** 행 태그명 (기본 'row') */\n rowTag?: string;\n /** 출력 방식: 'element'(기본) | 'attribute' */\n mode?: 'element' | 'attribute';\n /** 그리드 field명 → XML 태그명 매핑 */\n fieldMap?: Record<string, string>;\n /** XML 선언부 포함 여부 (기본 true) */\n declaration?: boolean;\n /** 들여쓰기 공백 수 (기본 2) */\n indent?: number;\n /** null/undefined 처리 문자열 (기본 '') */\n nullAs?: string;\n /** 출력에서 제외할 필드 목록 */\n excludeFields?: string[];\n}\n\n// ─── SAP 파싱 결과 ────────────────────────────────────────────\nexport interface SapParseResult {\n header: Record<string, string>;\n items: Record<string, string>[];\n returns: Record<string, string>[];\n raw?: Document;\n}\n\n// ─── 메인 클래스 ─────────────────────────────────────────────\nexport class XmlConverter {\n\n // ── 1. XML → 데이터 배열 ────────────────────────────────────\n /**\n * XML 문자열을 파싱하여 그리드 데이터 배열로 변환.\n * Element / Attribute 방식 자동 감지.\n *\n * @throws XML 파싱 오류 시 Error 발생\n */\n static parse(xml: string, options: XmlParseOptions = {}): Record<string, any>[] {\n const { fieldMap = {}, trim = true } = options;\n\n const parser = new DOMParser();\n const doc = parser.parseFromString(xml.trim(), 'text/xml');\n\n const errNode = doc.querySelector('parsererror');\n if (errNode) throw new Error(`XML 파싱 오류: ${errNode.textContent?.trim()}`);\n\n const root = doc.documentElement;\n\n // rowTag 자동 감지: 명시 → rootTag의 첫 자식 → 루트의 첫 자식\n let rowTag = options.rowTag;\n if (!rowTag) {\n const rootEl = options.rootTag ? doc.querySelector(options.rootTag) : root;\n rowTag = rootEl?.children[0]?.tagName ?? 'row';\n }\n\n const rowEls = doc.getElementsByTagName(rowTag);\n const rows: Record<string, any>[] = [];\n\n for (let i = 0; i < rowEls.length; i++) {\n const el = rowEls[i]!;\n const row: Record<string, any> = {};\n\n // Attribute 방식\n for (const attr of Array.from(el.attributes)) {\n const field = fieldMap[attr.name] ?? attr.name;\n row[field] = trim ? attr.value.trim() : attr.value;\n }\n\n // Element 방식 (자식 태그가 있으면 우선)\n for (const child of Array.from(el.children)) {\n const field = fieldMap[child.tagName] ?? child.tagName;\n const text = child.textContent ?? '';\n row[field] = trim ? text.trim() : text;\n }\n\n rows.push(row);\n }\n\n return rows;\n }\n\n // ── 2. 데이터 배열 → XML ─────────────────────────────────────\n /**\n * 그리드 데이터 배열을 XML 문자열로 직렬화.\n */\n static stringify(data: Record<string, any>[], options: XmlStringifyOptions = {}): string {\n const {\n rootTag = 'rows',\n rowTag = 'row',\n mode = 'element',\n fieldMap = {},\n declaration = true,\n indent = 2,\n nullAs = '',\n excludeFields = [],\n } = options;\n\n const pad = ' '.repeat(indent);\n const lines: string[] = [];\n\n if (declaration) lines.push('<?xml version=\"1.0\" encoding=\"UTF-8\"?>');\n lines.push(`<${rootTag}>`);\n\n for (const item of data) {\n const entries = Object.entries(item).filter(([k]) => !excludeFields.includes(k));\n\n if (mode === 'attribute') {\n const attrs = entries\n .map(([k, v]) => {\n const tag = fieldMap[k] ?? k;\n const val = v == null ? nullAs : String(v);\n return `${tag}=\"${this._escAttr(val)}\"`;\n })\n .join(' ');\n lines.push(`${pad}<${rowTag}${attrs ? ' ' + attrs : ''} />`);\n } else {\n lines.push(`${pad}<${rowTag}>`);\n for (const [k, v] of entries) {\n const tag = fieldMap[k] ?? k;\n const val = v == null ? nullAs : String(v);\n lines.push(`${pad}${pad}<${tag}>${this._escText(val)}</${tag}>`);\n }\n lines.push(`${pad}</${rowTag}>`);\n }\n }\n\n lines.push(`</${rootTag}>`);\n return lines.join('\\n');\n }\n\n // ── 3. SAP BAPI XML 응답 파싱 ────────────────────────────────\n /**\n * SAP BAPI XML 응답을 파싱하여 { header, items, returns } 구조로 반환.\n *\n * 지원 패턴:\n * <DOCUMENTHEADER>...</DOCUMENTHEADER>\n * <ACCOUNTGL><ITEM>...</ITEM></ACCOUNTGL>\n * <RETURN><TYPE>S</TYPE><MESSAGE>...</MESSAGE></RETURN>\n */\n static parseSap(xml: string): SapParseResult {\n const parser = new DOMParser();\n const doc = parser.parseFromString(xml.trim(), 'text/xml');\n\n const result: SapParseResult = { header: {}, items: [], returns: [], raw: doc };\n\n // DOCUMENTHEADER\n const headerEl = doc.getElementsByTagName('DOCUMENTHEADER')[0];\n if (headerEl) {\n for (const child of Array.from(headerEl.children)) {\n result.header[child.tagName] = child.textContent?.trim() ?? '';\n }\n }\n\n // RETURN (복수 지원)\n const returnEls = doc.getElementsByTagName('RETURN');\n for (const r of Array.from(returnEls)) {\n const ret: Record<string, string> = {};\n for (const child of Array.from(r.children)) {\n ret[child.tagName] = child.textContent?.trim() ?? '';\n }\n result.returns.push(ret);\n }\n\n // 라인 아이템 — 순서대로 시도\n const itemParentTags = ['ACCOUNTGL', 'ACCOUNTRECEIVABLE', 'ACCOUNTPAYABLE', 'ITEMS'];\n for (const parentTag of itemParentTags) {\n const parentEl = doc.getElementsByTagName(parentTag)[0];\n if (!parentEl) continue;\n\n // <ITEM> 자식이 있으면 ITEM 단위로, 없으면 parentEl 자체를 1개 아이템으로\n const itemEls = parentEl.getElementsByTagName('ITEM');\n const targets = itemEls.length > 0 ? Array.from(itemEls) : [parentEl];\n\n for (const el of targets) {\n const row: Record<string, string> = {};\n for (const child of Array.from(el.children)) {\n row[child.tagName] = child.textContent?.trim() ?? '';\n }\n result.items.push(row);\n }\n break;\n }\n\n // IDoc 패턴: <SEGMENT> 속성이 있는 최상위 자식들\n if (result.items.length === 0) {\n const root = doc.documentElement;\n const segments = Array.from(root.children).filter(el => el.hasAttribute('SEGMENT'));\n for (const seg of segments) {\n if (seg.tagName === 'EDI_DC40') continue; // 제어 레코드 제외\n const row: Record<string, string> = {};\n for (const child of Array.from(seg.children)) {\n row[child.tagName] = child.textContent?.trim() ?? '';\n }\n if (Object.keys(row).length > 0) result.items.push(row);\n }\n }\n\n return result;\n }\n\n // ── 4. SAP BAPI 페이로드 → XML 직렬화 ───────────────────────\n /**\n * BAPI 페이로드 객체를 SAP XML 형식으로 직렬화.\n * sapGenPayload()의 결과 또는 단일 document 객체를 받음.\n */\n static stringifySap(payload: {\n BAPI_FUNCTION?: string;\n DOCUMENTHEADER?: Record<string, any>;\n ACCOUNTGL?: Record<string, any>[];\n [key: string]: any;\n }): string {\n const lines: string[] = [\n '<?xml version=\"1.0\" encoding=\"UTF-8\"?>',\n '<BAPI_CALL>',\n ];\n\n if (payload.BAPI_FUNCTION) {\n lines.push(` <FUNCTION>${this._escText(payload.BAPI_FUNCTION)}</FUNCTION>`);\n }\n\n if (payload.DOCUMENTHEADER && typeof payload.DOCUMENTHEADER === 'object') {\n lines.push(' <DOCUMENTHEADER>');\n for (const [k, v] of Object.entries(payload.DOCUMENTHEADER)) {\n if (v != null && v !== '') {\n lines.push(` <${k}>${this._escText(String(v))}</${k}>`);\n }\n }\n lines.push(' </DOCUMENTHEADER>');\n }\n\n // 배열 타입 필드를 ACCOUNTGL로 처리\n const itemsKey = Object.keys(payload).find(\n k => Array.isArray(payload[k]) && !k.startsWith('_')\n );\n if (itemsKey) {\n lines.push(` <${itemsKey}>`);\n for (const item of (payload[itemsKey] as Record<string, any>[])) {\n lines.push(' <ITEM>');\n for (const [k, v] of Object.entries(item)) {\n if (v != null && v !== '' && !k.startsWith('_')) {\n lines.push(` <${k}>${this._escText(String(v))}</${k}>`);\n }\n }\n lines.push(' </ITEM>');\n }\n lines.push(` </${itemsKey}>`);\n }\n\n lines.push('</BAPI_CALL>');\n return lines.join('\\n');\n }\n\n // ── 5. 다건 documents 배열 → XML (sapGenPayload 결과 전체) ───\n /**\n * sapGenPayload()의 { totalDocuments, documents[] } 결과를\n * 다건 BAPI XML로 직렬화.\n */\n static stringifySapBatch(payload: { documents: any[] }): string {\n const lines: string[] = [\n '<?xml version=\"1.0\" encoding=\"UTF-8\"?>',\n `<BAPI_BATCH total=\"${payload.documents.length}\">`,\n ];\n payload.documents.forEach((doc, i) => {\n lines.push(` <BAPI_CALL seq=\"${i + 1}\">`);\n const inner = this.stringifySap(doc)\n .split('\\n')\n .filter(l => !l.startsWith('<?xml'))\n .map(l => ' ' + l)\n .join('\\n');\n lines.push(inner);\n lines.push(' </BAPI_CALL>');\n });\n lines.push('</BAPI_BATCH>');\n return lines.join('\\n');\n }\n\n // ── 내부 이스케이프 헬퍼 ─────────────────────────────────────\n private static _escText(s: string): string {\n return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\n }\n\n private static _escAttr(s: string): string {\n return this._escText(s).replace(/\"/g, '&quot;').replace(/'/g, '&apos;');\n }\n}\n"],"names":["GridShuttle","_left","_right","mount","opts","wrap","mk","label","title","fn","b","L","from","to","n","_","i","createGridShuttle","left","right","OrgChart","selector","data","idField","parentIdField","expandOnLoad","buildTree","theme","collect","nodes","id","nodeWidth","nodeHeight","levelGap","siblingGap","layout","nextX","place","node","y","vis","x","firstX","lastX","child","minX","maxX","root","maxY","svg","x1","y1","x2","y2","el","columns","totalW","totalH","drawLines","p","px","py","midY","c0","cn","ci","cx","renderNodes","info","card","content","col","val","div","s","out","btn","icon","e","XmlConverter","xml","options","fieldMap","trim","doc","errNode","_a","rowTag","rootEl","_b","rowEls","rows","row","attr","field","text","rootTag","mode","declaration","indent","nullAs","excludeFields","pad","lines","item","entries","k","attrs","v","tag","result","headerEl","returnEls","r","ret","itemParentTags","parentTag","parentEl","itemEls","targets","_c","segments","seg","_d","payload","itemsKey","inner","l"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"open-grid.js","sources":["../src/core/GridShuttle.ts","../src/core/OrgChart.ts","../src/core/XmlConverter.ts"],"sourcesContent":["// ============================================================\n// 그리드 셔틀 — 두 그리드 사이에 화살표 버튼을 두고\n// \"체크된 행\"을 드래그 없이 버튼으로 이동(move)시킨다.\n// 이동 자체는 grid.moveCheckedTo() 를 호출 → crossGridMapping(필드 매핑)과\n// 3단계 이벤트가 드래그 이동과 100% 동일하게 적용된다.\n// ============================================================\nimport type { OpenGridInstance } from './types.js';\n\nexport interface GridShuttleOptions {\n /** 버튼 배치 방향 (기본 'vertical') */\n layout?: 'vertical' | 'horizontal';\n /** 전체 이동(≫ ≪) 버튼도 표시 (기본 false) */\n includeAll?: boolean;\n /** 버튼 라벨 커스터마이즈 */\n labels?: { toRight?: string; toLeft?: string; allRight?: string; allLeft?: string };\n}\n\nexport class GridShuttle {\n private _el: HTMLElement;\n\n constructor(\n private _left: OpenGridInstance,\n private _right: OpenGridInstance,\n mount: HTMLElement,\n opts: GridShuttleOptions = {},\n ) {\n const wrap = document.createElement('div');\n wrap.className = 'og-shuttle';\n wrap.style.cssText =\n `display:flex;gap:6px;align-items:center;justify-content:center;` +\n `flex-direction:${opts.layout === 'horizontal' ? 'row' : 'column'};`;\n\n const mk = (label: string, title: string, fn: () => void): HTMLButtonElement => {\n const b = document.createElement('button');\n b.type = 'button';\n b.className = 'og-shuttle-btn';\n b.textContent = label;\n b.title = title;\n b.style.cssText =\n 'min-width:34px;height:30px;padding:0 8px;border:1px solid #bbb;border-radius:7px;' +\n 'background:#fff;cursor:pointer;font-size:14px;color:#444;line-height:1;' +\n 'box-shadow:0 1px 2px rgba(0,0,0,0.06);';\n b.addEventListener('mouseover', () => { b.style.background = '#f0f6ff'; b.style.borderColor = '#1976d2'; });\n b.addEventListener('mouseout', () => { b.style.background = '#fff'; b.style.borderColor = '#bbb'; });\n b.addEventListener('click', fn);\n return b;\n };\n\n const L = opts.labels ?? {};\n wrap.appendChild(mk(L.toRight ?? '▶', '체크한 행을 오른쪽 그리드로 이동',\n () => { void this._left.moveCheckedTo(this._right); }));\n wrap.appendChild(mk(L.toLeft ?? '◀', '체크한 행을 왼쪽 그리드로 이동',\n () => { void this._right.moveCheckedTo(this._left); }));\n\n if (opts.includeAll) {\n wrap.appendChild(mk(L.allRight ?? '⏩', '왼쪽 전체를 오른쪽으로 이동',\n () => { void this._moveAll(this._left, this._right); }));\n wrap.appendChild(mk(L.allLeft ?? '⏪', '오른쪽 전체를 왼쪽으로 이동',\n () => { void this._moveAll(this._right, this._left); }));\n }\n\n mount.appendChild(wrap);\n this._el = wrap;\n }\n\n private _moveAll(from: OpenGridInstance, to: OpenGridInstance): void {\n const n = from.getData().length;\n if (n > 0) void from.moveRowsTo(to, Array.from({ length: n }, (_, i) => i));\n }\n\n destroy(): void { this._el.remove(); }\n}\n\n/** 두 그리드 사이에 셔틀(화살표 이동) 버튼을 만든다 */\nexport function createGridShuttle(\n left: OpenGridInstance,\n right: OpenGridInstance,\n mount: HTMLElement,\n opts?: GridShuttleOptions,\n): GridShuttle {\n return new GridShuttle(left, right, mount, opts);\n}\n","import { buildTree, TreeNode } from './TreeEngine.js';\n\nexport interface OrgChartColumnDef {\n field: string;\n className?: string;\n style?: string | ((value: any, row: Record<string, any>) => string);\n renderer?: (value: any, row: Record<string, any>) => HTMLElement | string;\n}\n\nexport interface OrgChartOptions {\n idField: string;\n parentIdField: string;\n columns: OrgChartColumnDef[];\n nodeWidth?: number;\n nodeHeight?: number;\n levelGap?: number;\n siblingGap?: number;\n expandOnLoad?: boolean;\n onNodeClick?: (id: any, data: Record<string, any>) => void;\n}\n\ninterface LayoutInfo { x: number; y: number; }\n\nexport class OrgChart {\n private _container: HTMLElement;\n private _opts: Required<OrgChartOptions>;\n private _data: Record<string, any>[] = [];\n private _roots: TreeNode<any>[] = [];\n private _expandedKeys = new Set<any>();\n private _selectedId: any = null;\n\n constructor(selector: string | HTMLElement, opts: OrgChartOptions) {\n this._container = typeof selector === 'string'\n ? (document.querySelector(selector) as HTMLElement)\n : selector;\n this._opts = {\n nodeWidth: 160, nodeHeight: 72, levelGap: 52, siblingGap: 20,\n expandOnLoad: true, onNodeClick: () => {},\n ...opts,\n };\n this._container.classList.add('og-orgchart');\n }\n\n setData(data: Record<string, any>[]): void {\n this._data = data;\n const { idField, parentIdField, expandOnLoad } = this._opts;\n if (expandOnLoad && this._expandedKeys.size === 0) {\n data.forEach(r => this._expandedKeys.add(r[idField]));\n }\n this._roots = buildTree(data, { idField, parentIdField }, this._expandedKeys);\n this._render();\n }\n\n setTheme(theme: string): void {\n this._container.setAttribute('data-og-theme', theme);\n }\n\n expandAll(): void {\n const collect = (nodes: TreeNode<any>[]) => {\n for (const n of nodes) {\n this._expandedKeys.add(n._treeId);\n if (n.children.length) collect(n.children);\n }\n };\n collect(this._roots);\n this._rebuild();\n }\n\n collapseAll(): void {\n this._expandedKeys.clear();\n this._rebuild();\n }\n\n private _toggle(id: any): void {\n if (this._expandedKeys.has(id)) this._expandedKeys.delete(id);\n else this._expandedKeys.add(id);\n this._rebuild();\n }\n\n private _rebuild(): void {\n const { idField, parentIdField } = this._opts;\n this._roots = buildTree(this._data, { idField, parentIdField }, this._expandedKeys);\n this._render();\n }\n\n // ── 레이아웃 계산 (post-order: 리프부터 배치, 부모는 자식 중앙) ──\n private _calcLayout(): { layout: Map<any, LayoutInfo>; totalW: number; totalH: number } {\n const { nodeWidth, nodeHeight, levelGap, siblingGap } = this._opts;\n const layout = new Map<any, LayoutInfo>();\n let nextX = 0;\n\n const place = (node: TreeNode<any>): { minX: number; maxX: number } => {\n const y = node._depth * (nodeHeight + levelGap);\n const vis = node._expanded ? node.children : [];\n\n if (!vis.length) {\n const x = nextX;\n nextX += nodeWidth + siblingGap;\n layout.set(node._treeId, { x, y });\n return { minX: x, maxX: x };\n }\n\n let firstX = Infinity, lastX = -Infinity;\n for (const child of vis) {\n const { minX, maxX } = place(child);\n if (minX < firstX) firstX = minX;\n if (maxX > lastX) lastX = maxX;\n }\n // 자식들의 span 중앙에 부모 배치\n const x = firstX + (lastX - firstX + nodeWidth) / 2 - nodeWidth / 2;\n layout.set(node._treeId, { x, y });\n return { minX: firstX, maxX: lastX };\n };\n\n for (const root of this._roots) place(root);\n\n let maxX = 0, maxY = 0;\n for (const { x, y } of layout.values()) {\n if (x + nodeWidth > maxX) maxX = x + nodeWidth;\n if (y + nodeHeight > maxY) maxY = y + nodeHeight;\n }\n return { layout, totalW: maxX + siblingGap, totalH: maxY + levelGap + 16 };\n }\n\n // ── SVG 직선 헬퍼 ──\n private _line(svg: SVGSVGElement, x1: number, y1: number, x2: number, y2: number): void {\n const el = document.createElementNS('http://www.w3.org/2000/svg', 'line');\n el.setAttribute('x1', String(x1));\n el.setAttribute('y1', String(y1));\n el.setAttribute('x2', String(x2));\n el.setAttribute('y2', String(y2));\n el.setAttribute('class', 'og-orgchart-line');\n svg.appendChild(el);\n }\n\n // ── 렌더 ──\n private _render(): void {\n const { nodeWidth, nodeHeight, levelGap, columns } = this._opts;\n const { layout, totalW, totalH } = this._calcLayout();\n\n this._container.innerHTML = '';\n\n const wrap = document.createElement('div');\n wrap.className = 'og-orgchart-wrap';\n wrap.style.cssText = `width:${totalW}px;height:${totalH}px;`;\n\n // ① SVG 연결선\n const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');\n svg.setAttribute('width', String(totalW));\n svg.setAttribute('height', String(totalH));\n svg.style.cssText = 'position:absolute;top:0;left:0;pointer-events:none;overflow:visible;';\n\n const drawLines = (nodes: TreeNode<any>[]): void => {\n for (const node of nodes) {\n if (!node._expanded || !node.children.length) continue;\n const p = layout.get(node._treeId)!;\n const px = p.x + nodeWidth / 2;\n const py = p.y + nodeHeight;\n const midY = py + levelGap / 2;\n const vis = node.children;\n\n // 부모 → midY\n this._line(svg, px, py, px, midY);\n\n if (vis.length > 1) {\n const c0 = layout.get(vis[0]._treeId)!;\n const cn = layout.get(vis[vis.length - 1]._treeId)!;\n // 수평 브래킷\n this._line(svg, c0.x + nodeWidth / 2, midY, cn.x + nodeWidth / 2, midY);\n }\n for (const child of vis) {\n const ci = layout.get(child._treeId)!;\n const cx = ci.x + nodeWidth / 2;\n // midY → 자식 상단\n this._line(svg, cx, midY, cx, ci.y);\n }\n drawLines(vis);\n }\n };\n drawLines(this._roots);\n wrap.appendChild(svg);\n\n // ② 카드 렌더\n const renderNodes = (nodes: TreeNode<any>[]): void => {\n for (const node of nodes) {\n const info = layout.get(node._treeId);\n if (!info) continue;\n\n const card = document.createElement('div');\n card.className = 'og-orgchart-node';\n if (node._hasChildren) card.classList.add('og-orgchart-node--branch');\n if (node._expanded) card.classList.add('og-orgchart-node--expanded');\n if (this._selectedId === node._treeId) card.classList.add('og-orgchart-node--selected');\n card.style.cssText = `left:${info.x}px;top:${info.y}px;width:${nodeWidth}px;height:${nodeHeight}px;`;\n\n // 컬럼 렌더\n const content = document.createElement('div');\n content.className = 'og-orgchart-node-content';\n for (const col of columns) {\n const val = node.data[col.field];\n const div = document.createElement('div');\n div.className = 'og-orgchart-col' + (col.className ? ' ' + col.className : '');\n if (col.style) {\n const s = typeof col.style === 'function' ? col.style(val, node.data) : col.style;\n div.setAttribute('style', s);\n }\n if (col.renderer) {\n const out = col.renderer(val, node.data);\n if (typeof out === 'string') div.innerHTML = out;\n else div.appendChild(out);\n } else {\n div.textContent = val ?? '';\n }\n content.appendChild(div);\n }\n card.appendChild(content);\n\n // 확장/축소 토글 버튼 (카드 하단 중앙)\n if (node._hasChildren) {\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.className = 'og-orgchart-toggle';\n btn.setAttribute('aria-expanded', node._expanded ? 'true' : 'false');\n btn.setAttribute('aria-label', node._expanded ? '접기' : '펼치기');\n const icon = document.createElement('i');\n icon.setAttribute('aria-hidden', 'true');\n icon.className = node._expanded ? 'bi bi-dash-circle' : 'bi bi-plus-circle';\n btn.appendChild(icon);\n btn.addEventListener('click', (e) => {\n e.stopPropagation();\n this._toggle(node._treeId);\n });\n card.appendChild(btn);\n }\n\n card.addEventListener('click', () => {\n this._selectedId = node._treeId;\n this._opts.onNodeClick(node._treeId, node.data);\n // 선택 하이라이트만 갱신 (전체 재렌더 최소화)\n this._container.querySelectorAll('.og-orgchart-node--selected')\n .forEach(el => el.classList.remove('og-orgchart-node--selected'));\n card.classList.add('og-orgchart-node--selected');\n });\n\n wrap.appendChild(card);\n\n if (node._expanded && node.children.length) renderNodes(node.children);\n }\n };\n renderNodes(this._roots);\n\n this._container.appendChild(wrap);\n }\n}\n","/**\n * XmlConverter — XML ↔ 그리드 데이터 양방향 변환 유틸리티.\n *\n * 지원 포맷:\n * A. Element 방식 <row><name>홍길동</name></row>\n * B. Attribute 방식 <row name=\"홍길동\" />\n * C. SAP BAPI XML 응답 <RETURN><TYPE>S</TYPE><BELNR>...</BELNR></RETURN>\n * D. SAP IDoc XML <IDOC><E1HEADER SEGMENT=\"1\"><BUKRS>1000</BUKRS></IDOC>\n *\n * 외부 의존성 없음 — 브라우저 내장 DOMParser 사용.\n */\n\n// ─── 파싱 옵션 ────────────────────────────────────────────────\nexport interface XmlParseOptions {\n /** 루트 엘리먼트 태그명 (생략 시 문서 루트 자동 사용) */\n rootTag?: string;\n /** 행 엘리먼트 태그명 (생략 시 루트의 첫 번째 자식 자동 감지) */\n rowTag?: string;\n /** 값 추출 방식: 'element' | 'attribute' | 'auto'(기본) */\n mode?: 'element' | 'attribute' | 'auto';\n /** XML 태그명 → 그리드 field명 매핑 (생략 시 태그명 그대로 사용) */\n fieldMap?: Record<string, string>;\n /** 텍스트 값 앞뒤 공백 제거 (기본 true) */\n trim?: boolean;\n}\n\n// ─── 직렬화 옵션 ─────────────────────────────────────────────\nexport interface XmlStringifyOptions {\n /** 루트 태그명 (기본 'rows') */\n rootTag?: string;\n /** 행 태그명 (기본 'row') */\n rowTag?: string;\n /** 출력 방식: 'element'(기본) | 'attribute' */\n mode?: 'element' | 'attribute';\n /** 그리드 field명 → XML 태그명 매핑 */\n fieldMap?: Record<string, string>;\n /** XML 선언부 포함 여부 (기본 true) */\n declaration?: boolean;\n /** 들여쓰기 공백 수 (기본 2) */\n indent?: number;\n /** null/undefined 처리 문자열 (기본 '') */\n nullAs?: string;\n /** 출력에서 제외할 필드 목록 */\n excludeFields?: string[];\n}\n\n// ─── SAP 파싱 결과 ────────────────────────────────────────────\nexport interface SapParseResult {\n header: Record<string, string>;\n items: Record<string, string>[];\n returns: Record<string, string>[];\n raw?: Document;\n}\n\n// ─── 메인 클래스 ─────────────────────────────────────────────\nexport class XmlConverter {\n\n // ── 1. XML → 데이터 배열 ────────────────────────────────────\n /**\n * XML 문자열을 파싱하여 그리드 데이터 배열로 변환.\n * Element / Attribute 방식 자동 감지.\n *\n * @throws XML 파싱 오류 시 Error 발생\n */\n static parse(xml: string, options: XmlParseOptions = {}): Record<string, any>[] {\n const { fieldMap = {}, trim = true } = options;\n\n const parser = new DOMParser();\n const doc = parser.parseFromString(xml.trim(), 'text/xml');\n\n const errNode = doc.querySelector('parsererror');\n if (errNode) throw new Error(`XML 파싱 오류: ${errNode.textContent?.trim()}`);\n\n const root = doc.documentElement;\n\n // rowTag 자동 감지: 명시 → rootTag의 첫 자식 → 루트의 첫 자식\n let rowTag = options.rowTag;\n if (!rowTag) {\n const rootEl = options.rootTag ? doc.querySelector(options.rootTag) : root;\n rowTag = rootEl?.children[0]?.tagName ?? 'row';\n }\n\n const rowEls = doc.getElementsByTagName(rowTag);\n const rows: Record<string, any>[] = [];\n\n for (let i = 0; i < rowEls.length; i++) {\n const el = rowEls[i]!;\n const row: Record<string, any> = {};\n\n // Attribute 방식\n for (const attr of Array.from(el.attributes)) {\n const field = fieldMap[attr.name] ?? attr.name;\n row[field] = trim ? attr.value.trim() : attr.value;\n }\n\n // Element 방식 (자식 태그가 있으면 우선)\n for (const child of Array.from(el.children)) {\n const field = fieldMap[child.tagName] ?? child.tagName;\n const text = child.textContent ?? '';\n row[field] = trim ? text.trim() : text;\n }\n\n rows.push(row);\n }\n\n return rows;\n }\n\n // ── 2. 데이터 배열 → XML ─────────────────────────────────────\n /**\n * 그리드 데이터 배열을 XML 문자열로 직렬화.\n */\n static stringify(data: Record<string, any>[], options: XmlStringifyOptions = {}): string {\n const {\n rootTag = 'rows',\n rowTag = 'row',\n mode = 'element',\n fieldMap = {},\n declaration = true,\n indent = 2,\n nullAs = '',\n excludeFields = [],\n } = options;\n\n const pad = ' '.repeat(indent);\n const lines: string[] = [];\n\n if (declaration) lines.push('<?xml version=\"1.0\" encoding=\"UTF-8\"?>');\n lines.push(`<${rootTag}>`);\n\n for (const item of data) {\n const entries = Object.entries(item).filter(([k]) => !excludeFields.includes(k));\n\n if (mode === 'attribute') {\n const attrs = entries\n .map(([k, v]) => {\n const tag = fieldMap[k] ?? k;\n const val = v == null ? nullAs : String(v);\n return `${tag}=\"${this._escAttr(val)}\"`;\n })\n .join(' ');\n lines.push(`${pad}<${rowTag}${attrs ? ' ' + attrs : ''} />`);\n } else {\n lines.push(`${pad}<${rowTag}>`);\n for (const [k, v] of entries) {\n const tag = fieldMap[k] ?? k;\n const val = v == null ? nullAs : String(v);\n lines.push(`${pad}${pad}<${tag}>${this._escText(val)}</${tag}>`);\n }\n lines.push(`${pad}</${rowTag}>`);\n }\n }\n\n lines.push(`</${rootTag}>`);\n return lines.join('\\n');\n }\n\n // ── 3. SAP BAPI XML 응답 파싱 ────────────────────────────────\n /**\n * SAP BAPI XML 응답을 파싱하여 { header, items, returns } 구조로 반환.\n *\n * 지원 패턴:\n * <DOCUMENTHEADER>...</DOCUMENTHEADER>\n * <ACCOUNTGL><ITEM>...</ITEM></ACCOUNTGL>\n * <RETURN><TYPE>S</TYPE><MESSAGE>...</MESSAGE></RETURN>\n */\n static parseSap(xml: string): SapParseResult {\n const parser = new DOMParser();\n const doc = parser.parseFromString(xml.trim(), 'text/xml');\n\n const result: SapParseResult = { header: {}, items: [], returns: [], raw: doc };\n\n // DOCUMENTHEADER\n const headerEl = doc.getElementsByTagName('DOCUMENTHEADER')[0];\n if (headerEl) {\n for (const child of Array.from(headerEl.children)) {\n result.header[child.tagName] = child.textContent?.trim() ?? '';\n }\n }\n\n // RETURN (복수 지원)\n const returnEls = doc.getElementsByTagName('RETURN');\n for (const r of Array.from(returnEls)) {\n const ret: Record<string, string> = {};\n for (const child of Array.from(r.children)) {\n ret[child.tagName] = child.textContent?.trim() ?? '';\n }\n result.returns.push(ret);\n }\n\n // 라인 아이템 — 순서대로 시도\n const itemParentTags = ['ACCOUNTGL', 'ACCOUNTRECEIVABLE', 'ACCOUNTPAYABLE', 'ITEMS'];\n for (const parentTag of itemParentTags) {\n const parentEl = doc.getElementsByTagName(parentTag)[0];\n if (!parentEl) continue;\n\n // <ITEM> 자식이 있으면 ITEM 단위로, 없으면 parentEl 자체를 1개 아이템으로\n const itemEls = parentEl.getElementsByTagName('ITEM');\n const targets = itemEls.length > 0 ? Array.from(itemEls) : [parentEl];\n\n for (const el of targets) {\n const row: Record<string, string> = {};\n for (const child of Array.from(el.children)) {\n row[child.tagName] = child.textContent?.trim() ?? '';\n }\n result.items.push(row);\n }\n break;\n }\n\n // IDoc 패턴: <SEGMENT> 속성이 있는 최상위 자식들\n if (result.items.length === 0) {\n const root = doc.documentElement;\n const segments = Array.from(root.children).filter(el => el.hasAttribute('SEGMENT'));\n for (const seg of segments) {\n if (seg.tagName === 'EDI_DC40') continue; // 제어 레코드 제외\n const row: Record<string, string> = {};\n for (const child of Array.from(seg.children)) {\n row[child.tagName] = child.textContent?.trim() ?? '';\n }\n if (Object.keys(row).length > 0) result.items.push(row);\n }\n }\n\n return result;\n }\n\n // ── 4. SAP BAPI 페이로드 → XML 직렬화 ───────────────────────\n /**\n * BAPI 페이로드 객체를 SAP XML 형식으로 직렬화.\n * sapGenPayload()의 결과 또는 단일 document 객체를 받음.\n */\n static stringifySap(payload: {\n BAPI_FUNCTION?: string;\n DOCUMENTHEADER?: Record<string, any>;\n ACCOUNTGL?: Record<string, any>[];\n [key: string]: any;\n }): string {\n const lines: string[] = [\n '<?xml version=\"1.0\" encoding=\"UTF-8\"?>',\n '<BAPI_CALL>',\n ];\n\n if (payload.BAPI_FUNCTION) {\n lines.push(` <FUNCTION>${this._escText(payload.BAPI_FUNCTION)}</FUNCTION>`);\n }\n\n if (payload.DOCUMENTHEADER && typeof payload.DOCUMENTHEADER === 'object') {\n lines.push(' <DOCUMENTHEADER>');\n for (const [k, v] of Object.entries(payload.DOCUMENTHEADER)) {\n if (v != null && v !== '') {\n lines.push(` <${k}>${this._escText(String(v))}</${k}>`);\n }\n }\n lines.push(' </DOCUMENTHEADER>');\n }\n\n // 배열 타입 필드를 ACCOUNTGL로 처리\n const itemsKey = Object.keys(payload).find(\n k => Array.isArray(payload[k]) && !k.startsWith('_')\n );\n if (itemsKey) {\n lines.push(` <${itemsKey}>`);\n for (const item of (payload[itemsKey] as Record<string, any>[])) {\n lines.push(' <ITEM>');\n for (const [k, v] of Object.entries(item)) {\n if (v != null && v !== '' && !k.startsWith('_')) {\n lines.push(` <${k}>${this._escText(String(v))}</${k}>`);\n }\n }\n lines.push(' </ITEM>');\n }\n lines.push(` </${itemsKey}>`);\n }\n\n lines.push('</BAPI_CALL>');\n return lines.join('\\n');\n }\n\n // ── 5. 다건 documents 배열 → XML (sapGenPayload 결과 전체) ───\n /**\n * sapGenPayload()의 { totalDocuments, documents[] } 결과를\n * 다건 BAPI XML로 직렬화.\n */\n static stringifySapBatch(payload: { documents: any[] }): string {\n const lines: string[] = [\n '<?xml version=\"1.0\" encoding=\"UTF-8\"?>',\n `<BAPI_BATCH total=\"${payload.documents.length}\">`,\n ];\n payload.documents.forEach((doc, i) => {\n lines.push(` <BAPI_CALL seq=\"${i + 1}\">`);\n const inner = this.stringifySap(doc)\n .split('\\n')\n .filter(l => !l.startsWith('<?xml'))\n .map(l => ' ' + l)\n .join('\\n');\n lines.push(inner);\n lines.push(' </BAPI_CALL>');\n });\n lines.push('</BAPI_BATCH>');\n return lines.join('\\n');\n }\n\n // ── 내부 이스케이프 헬퍼 ─────────────────────────────────────\n private static _escText(s: string): string {\n return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\n }\n\n private static _escAttr(s: string): string {\n return this._escText(s).replace(/\"/g, '&quot;').replace(/'/g, '&apos;');\n }\n}\n"],"names":["GridShuttle","_left","_right","mount","opts","wrap","mk","label","title","fn","b","L","from","to","n","_","i","createGridShuttle","left","right","OrgChart","selector","data","idField","parentIdField","expandOnLoad","r","buildTree","theme","collect","nodes","id","nodeWidth","nodeHeight","levelGap","siblingGap","layout","nextX","place","node","y","vis","x","firstX","lastX","child","minX","maxX","root","maxY","svg","x1","y1","x2","y2","el","columns","totalW","totalH","drawLines","p","px","py","midY","c0","cn","ci","cx","renderNodes","info","card","content","col","val","div","s","out","btn","icon","e","XmlConverter","xml","options","fieldMap","trim","doc","errNode","_a","rowTag","rootEl","_b","rowEls","rows","row","attr","field","text","rootTag","mode","declaration","indent","nullAs","excludeFields","pad","lines","item","entries","k","attrs","v","tag","result","headerEl","returnEls","ret","itemParentTags","parentTag","parentEl","itemEls","targets","_c","segments","seg","_d","payload","itemsKey","inner","l"],"mappings":"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"}