open-grid 0.3.2 → 0.4.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.
@@ -1 +1 @@
1
- {"version":3,"file":"open-grid.js","sources":["../src/core/OrgChart.ts","../src/core/XmlConverter.ts"],"sourcesContent":["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":["OrgChart","selector","opts","data","idField","parentIdField","expandOnLoad","r","buildTree","theme","collect","nodes","n","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","wrap","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","i","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"],"mappings":"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"}
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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"}
@@ -0,0 +1,21 @@
1
+ export interface FieldInfo {
2
+ field: string;
3
+ header: string;
4
+ }
5
+ export interface MappingResult {
6
+ /** 타깃필드 → 소스필드 (빈 문자열이면 미매핑) */
7
+ mapping: Record<string, string>;
8
+ /** crossGridMapping 에 그대로 쓸 수 있는 변환 함수 소스 */
9
+ script: string;
10
+ }
11
+ /** mapping → 변환 함수 스크립트 문자열 생성 */
12
+ export declare function buildMappingScript(mapping: Record<string, string>): string;
13
+ /** mapping → 실제 행 변환 함수 */
14
+ export declare function buildTransform(mapping: Record<string, string>): (src: any) => any;
15
+ /** 같은 필드 집합인지 (순서 무관) */
16
+ export declare function sameSchema(a: string[], b: string[]): boolean;
17
+ /**
18
+ * 매핑 모달을 띄우고 사용자가 확정한 매핑을 Promise 로 반환한다. (취소 시 null)
19
+ * 모달은 document.body 에 오버레이로 붙는다(디자인타임 헬퍼).
20
+ */
21
+ export declare function openCrossGridMapper(sourceFields: FieldInfo[], targetFields: FieldInfo[]): Promise<MappingResult | null>;
@@ -0,0 +1,13 @@
1
+ import { OpenGrid } from './OpenGrid.js';
2
+
3
+ export declare class CrossGridRegistry {
4
+ private _map;
5
+ register(bodyEl: HTMLElement, grid: OpenGrid<any>): void;
6
+ unregister(bodyEl: HTMLElement): void;
7
+ get(bodyEl: HTMLElement): OpenGrid<any> | undefined;
8
+ get size(): number;
9
+ /** 커서 좌표 아래의 다른(crossGrid 허용) 그리드 반환. 없으면 null */
10
+ resolveAt(clientX: number, clientY: number, exclude: OpenGrid<any>): OpenGrid<any> | null;
11
+ }
12
+ /** 전역 단일 레지스트리 */
13
+ export declare const crossGridRegistry: CrossGridRegistry;
@@ -0,0 +1,23 @@
1
+ /** 커서를 따라다니는 점선 고스트. transform 으로 X·Y 모두 이동(부드럽게). */
2
+ export declare class DragGhost {
3
+ private _el;
4
+ private _dx;
5
+ private _dy;
6
+ constructor(rect: DOMRect, grabX: number, grabY: number, count: number);
7
+ /** 커서 위치로 이동 (grab 오프셋 유지) */
8
+ move(clientX: number, clientY: number): void;
9
+ destroy(): void;
10
+ }
11
+ /**
12
+ * 드롭(삽입) 위치 마커. 행과 행 사이 경계에 "▶━━━◀" 형태로 또렷하게 표시해
13
+ * "여기에 삽입됩니다 / 지금 버튼을 떼면 됩니다" 를 직관적으로 알린다(워드 표 삽입 표시 느낌).
14
+ * 자기 그리드/타깃 그리드 모두에 재사용.
15
+ */
16
+ export declare class DropIndicator {
17
+ private _el;
18
+ constructor(color?: string);
19
+ /** parent(그리드 바디) 안의 top(행 경계) 위치에 표시 */
20
+ showIn(parent: HTMLElement, top: number): void;
21
+ hide(): void;
22
+ destroy(): void;
23
+ }
@@ -0,0 +1,25 @@
1
+ import { OpenGridInstance } from './types.js';
2
+
3
+ export interface GridShuttleOptions {
4
+ /** 버튼 배치 방향 (기본 'vertical') */
5
+ layout?: 'vertical' | 'horizontal';
6
+ /** 전체 이동(≫ ≪) 버튼도 표시 (기본 false) */
7
+ includeAll?: boolean;
8
+ /** 버튼 라벨 커스터마이즈 */
9
+ labels?: {
10
+ toRight?: string;
11
+ toLeft?: string;
12
+ allRight?: string;
13
+ allLeft?: string;
14
+ };
15
+ }
16
+ export declare class GridShuttle {
17
+ private _left;
18
+ private _right;
19
+ private _el;
20
+ constructor(_left: OpenGridInstance, _right: OpenGridInstance, mount: HTMLElement, opts?: GridShuttleOptions);
21
+ private _moveAll;
22
+ destroy(): void;
23
+ }
24
+ /** 두 그리드 사이에 셔틀(화살표 이동) 버튼을 만든다 */
25
+ export declare function createGridShuttle(left: OpenGridInstance, right: OpenGridInstance, mount: HTMLElement, opts?: GridShuttleOptions): GridShuttle;
@@ -16,7 +16,10 @@ export declare class OpenGrid<T extends Record<string, any> = any> extends Event
16
16
  private _editMgr;
17
17
  private _trigMgr;
18
18
  private _destroyed;
19
+ private _autoHeightWarned;
19
20
  private _colWidths;
21
+ /** 사용자가 헤더 드래그로 직접 조절한 컬럼 폭 (field 기준). _recalcWidths 가 덮어쓰지 않도록 보존 */
22
+ private _userWidths;
20
23
  private _filterPanel;
21
24
  private _filterSelect;
22
25
  private _pagination;
@@ -78,6 +81,31 @@ export declare class OpenGrid<T extends Record<string, any> = any> extends Event
78
81
  private _handleFilterIconClick;
79
82
  private _handleAllCheck;
80
83
  private _handleRowDrop;
84
+ /** 드래그/셔틀이 참조하는 바디 엘리먼트 (레지스트리 해석용) */
85
+ _crossBodyEl(): HTMLElement;
86
+ /** fromIndex 를 잡고 드래그할 때 함께 이동할 행 집합 (다중선택에 포함되면 선택 전체) */
87
+ private _dragRowSet;
88
+ /** 드래그 드롭 어댑터 → 공개 moveRowsTo 로 위임 */
89
+ private _handleCrossGridDrop;
90
+ /**
91
+ * 이 그리드의 행들을 다른 그리드로 이동(move)한다. 드래그·화살표 셔틀 공통 경로.
92
+ * 3단계 이벤트(before→after→complete)와 crossGridMapping(필드 매핑)을 적용한다.
93
+ * @param targetGrid 대상 그리드
94
+ * @param sourceIndexes 이동할 (표시)행 인덱스들
95
+ * @param targetIndex 대상에서 삽입 위치 (생략 시 맨 끝에 추가)
96
+ * @returns 이동 성공 true, 취소/무효 false
97
+ */
98
+ moveRowsTo(target: OpenGridInstance<T>, sourceIndexes: number[], targetIndex?: number): Promise<boolean>;
99
+ /** 체크된 행을 다른 그리드로 이동 (화살표 셔틀용). 체크 없으면 무시. */
100
+ moveCheckedTo(target: OpenGridInstance<T>): Promise<boolean>;
101
+ /**
102
+ * 크로스그리드 이동의 행 변환 함수를 결정한다.
103
+ * 반환: null=변환 불필요(그대로) / 함수=변환 적용 / false=매핑 모달 취소(이동 중단)
104
+ */
105
+ private _resolveCrossTransform;
106
+ private _fireGridDropBefore;
107
+ private _fireGridDropAfter;
108
+ private _fireGridDropComplete;
81
109
  /** 행을 드롭으로 이동할 때 실행된다 */
82
110
  /** ???꾩튂 ?대룞 */
83
111
  reorderRow(fromIndex: number, toIndex: number): void;
@@ -1,14 +1,34 @@
1
1
  export type RowDropCallback = (fromIndex: number, toIndex: number) => void;
2
+ /** 커서 좌표로 다른 그리드의 바디를 찾는 해석기 */
3
+ export interface CrossGridResolveResult {
4
+ bodyEl: HTMLElement;
5
+ rowHeight: number;
6
+ totalRows: number;
7
+ }
8
+ export interface CrossGridConfig {
9
+ /** 커서 위치(x,y)에 있는 다른(crossGrid 허용) 그리드 바디 정보 반환. 없으면 null */
10
+ resolveTarget: (clientX: number, clientY: number) => CrossGridResolveResult | null;
11
+ /** 다른 그리드로 드롭됐을 때 호출 (소스 fromIndex, 타깃 바디, 타깃 삽입 인덱스) */
12
+ onCrossDrop: (fromIndex: number, targetBodyEl: HTMLElement, targetIndex: number) => void;
13
+ }
2
14
  /**
3
- * 행 드래그앤드롭 관리자.
4
- * 행 DOM에 드래그 핸들을 심고, 드롭 위치를 표시한 뒤 콜백으로 알림.
15
+ * 행 드래그앤드롭 관리자 (순수 DnD).
16
+ * 행 DOM에 드래그 핸들을 심고, 고스트/인디케이터로 위치를 표시한 뒤 콜백으로 알림.
17
+ * 그리드 간 이동 판정(타깃 그리드 해석)은 주입된 CrossGridConfig 에 위임한다.
5
18
  */
6
19
  export declare class RowDragDrop {
7
- private _drag;
8
- private _onDrop;
9
20
  private _bodyEl;
10
21
  private _rowHeight;
11
- constructor(bodyEl: HTMLElement, rowHeight: number, onDrop: RowDropCallback);
22
+ private _onDrop;
23
+ private _cross;
24
+ /** fromIndex 기준 함께 드래그할 행 수(멀티행 배지용). 기본 1 */
25
+ private _getDragCount;
26
+ private _drag;
27
+ private readonly _selfIndicator;
28
+ private readonly _crossIndicator;
29
+ constructor(_bodyEl: HTMLElement, _rowHeight: number, _onDrop: RowDropCallback, _cross?: CrossGridConfig | null,
30
+ /** fromIndex 기준 함께 드래그할 행 수(멀티행 배지용). 기본 1 */
31
+ _getDragCount?: (fromIndex: number) => number);
12
32
  /** 행 엘리먼트에 드래그 핸들 삽입 */
13
33
  attachHandle(rowEl: HTMLElement, rowIndex: number, totalRows: number): HTMLElement;
14
34
  private _startDrag;
@@ -17,7 +17,18 @@ export interface CellRenderer {
17
17
  * formula가 없으면 null 반환 → 기존 ctx.value 사용.
18
18
  */
19
19
  export declare function resolveFormula(ctx: RenderContext): string | null;
20
- export declare function formatNumber(value: any, format?: string, precision?: number): string;
20
+ /**
21
+ * 숫자 포맷.
22
+ * format 문자열:
23
+ * '#,##0' 천단위 콤마, 정수
24
+ * '#,##0.00' 천단위 콤마, 소수 2자리
25
+ * '₩#,##0' 통화 접두 (₩1,234)
26
+ * '$#,##0.00' 통화 접두 ($1,234.56)
27
+ * '#,##0원' 통화 접미 (1,234원)
28
+ * '$#,##0;($#,##0)' 양수;음수 패턴 — 음수를 괄호로 (회계식)
29
+ * currency: ISO 통화코드('KRW'|'USD'|'EUR'…) 지정 시 Intl.NumberFormat 로케일 통화 포맷 우선.
30
+ */
31
+ export declare function formatNumber(value: any, format?: string, precision?: number, currency?: string): string;
21
32
  export declare function formatDate(value: any, format?: string): string;
22
33
  export declare class TextRenderer implements CellRenderer {
23
34
  render(ctx: RenderContext): HTMLElement;
@@ -68,6 +68,36 @@ export interface DragDropEvent<T = any> {
68
68
  targetIndex: number;
69
69
  targetGridId?: string;
70
70
  }
71
+ /**
72
+ * 그리드↔그리드 행 이동 이벤트.
73
+ * crossGrid:true 인 두 그리드 사이에서 행을 드래그·드롭할 때 3단계로 발생한다.
74
+ * - onGridDropBefore : 변경 직전(이동 전). false 반환 시 이동 취소.
75
+ * - onGridDropAfter : 양쪽 데이터 모델 이동 완료 후.
76
+ * - onGridDropComplete: 양쪽 재렌더까지 끝난 후.
77
+ */
78
+ export interface GridDropEvent<T = any> {
79
+ /** 행을 보낸(드래그 시작) 그리드 */
80
+ sourceGrid: OpenGridInstance<T>;
81
+ /** 행을 받은(드롭 대상) 그리드 */
82
+ targetGrid: OpenGridInstance<T>;
83
+ /** 이동된 행 데이터 (내부 id 제외 복사본) */
84
+ rows: T[];
85
+ /** 소스 그리드에서의 원래 행 인덱스들 */
86
+ sourceIndexes: number[];
87
+ /** 타깃 그리드에서 삽입된 시작 인덱스 */
88
+ targetIndex: number;
89
+ /** before 단계에서 true 로 바꾸면 이동 취소 (onGridDropBefore가 false 반환한 것과 동일) */
90
+ cancel?: boolean;
91
+ }
92
+ /** 그리드↔그리드 필드 매핑 확정 이벤트 (interactive 모드에서 매핑 모달 확인 시) */
93
+ export interface GridMappingEvent<T = any> {
94
+ sourceGrid: OpenGridInstance<T>;
95
+ targetGrid: OpenGridInstance<T>;
96
+ /** 타깃필드 → 소스필드 매핑 */
97
+ mapping: Record<string, string>;
98
+ /** crossGridMapping 에 baking 할 수 있는 변환 함수 소스 */
99
+ script: string;
100
+ }
71
101
  export interface SelectionEvent<T = any> {
72
102
  rows: T[];
73
103
  rowIndexes: number[];
@@ -105,7 +135,13 @@ export interface ColumnDef<T = any> {
105
135
  maxWidth?: number;
106
136
  flex?: number;
107
137
  type?: DataType;
138
+ /**
139
+ * 숫자/날짜 포맷 문자열. 숫자는 통화 기호 접두·접미와 음수 패턴 지원:
140
+ * '#,##0' · '#,##0.00' · '₩#,##0' · '$#,##0.00' · '#,##0원' · '$#,##0;($#,##0)'(음수 괄호)
141
+ */
108
142
  format?: string;
143
+ /** ISO 통화코드('KRW'|'USD'|'EUR'…). 지정 시 Intl.NumberFormat 로케일 통화 포맷 (format 보다 우선) */
144
+ currency?: string;
109
145
  valueMap?: Record<string, string>;
110
146
  renderer?: RendererType | RendererDef;
111
147
  editable?: boolean | ((row: T, rowIndex: number) => boolean);
@@ -255,6 +291,15 @@ export interface GridOptions<T = any> {
255
291
  stateColumn?: boolean;
256
292
  checkColumn?: boolean;
257
293
  draggable?: boolean;
294
+ /** 그리드↔그리드 행 드래그 이동 허용 (draggable:true 와 함께 사용, 양쪽 그리드 모두 true 여야 이동) */
295
+ crossGrid?: boolean;
296
+ /**
297
+ * 크로스그리드 이동 시 소스→타깃 행 변환 방식.
298
+ * - 'auto'(기본): 필드명 그대로 복사
299
+ * - 'interactive': 소스/타깃 스키마가 다르면 매핑 모달을 띄워 개발자가 매칭 + 변환 스크립트 출력
300
+ * - 함수: (srcRow) => targetRow 로 직접 변환 (모달 없이 baking)
301
+ */
302
+ crossGridMapping?: 'auto' | 'interactive' | ((srcRow: T) => Partial<T>);
258
303
  mergeCells?: boolean;
259
304
  groupBy?: string[];
260
305
  summary?: SummaryOptions;
@@ -290,6 +335,14 @@ export interface GridOptions<T = any> {
290
335
  fromIndex: number;
291
336
  toIndex: number;
292
337
  }) => void;
338
+ /** 변경전 — 이동 직전. false 반환 시 이동 취소 */
339
+ onGridDropBefore?: (e: GridDropEvent<T>) => boolean | void;
340
+ /** 변경후 — 양쪽 데이터 모델 이동 완료 */
341
+ onGridDropAfter?: (e: GridDropEvent<T>) => void;
342
+ /** 완료시 — 양쪽 재렌더까지 끝남 */
343
+ onGridDropComplete?: (e: GridDropEvent<T>) => void;
344
+ /** interactive 매핑 모달에서 매핑 확정 시 — 생성된 매핑/스크립트 수신 */
345
+ onGridDropMapping?: (e: GridMappingEvent<T>) => void;
293
346
  onColumnReorder?: (e: {
294
347
  fromIndex: number;
295
348
  toIndex: number;
@@ -386,6 +439,10 @@ export interface OpenGridInstance<T = any> {
386
439
  resetFilter(field?: string): void;
387
440
  getFilterState(): Record<string, FilterItem[]>;
388
441
  restoreFilter(state: Record<string, FilterItem[]>): void;
442
+ /** 지정 행들을 다른 그리드로 이동. 3단계 이벤트 + crossGridMapping 적용. */
443
+ moveRowsTo(target: OpenGridInstance<T>, sourceIndexes: number[], targetIndex?: number): Promise<boolean>;
444
+ /** 체크된 행을 다른 그리드로 이동 (화살표 셔틀용) */
445
+ moveCheckedTo(target: OpenGridInstance<T>): Promise<boolean>;
389
446
  freeze(columnCount: number): void;
390
447
  freezeRows(rowCount: number): void;
391
448
  groupBy(fields: string[]): void;
@@ -1,5 +1,7 @@
1
1
 
2
2
  export { OpenGrid } from './core/OpenGrid.js';
3
+ export { GridShuttle, createGridShuttle } from './core/GridShuttle.js';
4
+ export type { GridShuttleOptions } from './core/GridShuttle.js';
3
5
  export { OrgChart } from './core/OrgChart.js';
4
6
  export { XmlConverter } from './core/XmlConverter.js';
5
7
  export type { OrgChartOptions, OrgChartColumnDef } from './core/OrgChart.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-grid",
3
- "version": "0.3.2",
3
+ "version": "0.4.0",
4
4
  "description": "High-performance, framework-agnostic data grid with Vue 3 and React 18 support",
5
5
  "type": "module",
6
6
  "main": "dist/open-grid.cjs",
@@ -95,8 +95,5 @@
95
95
  ],
96
96
  "license": "MIT",
97
97
  "author": "OPEN_GRID Contributors",
98
- "repository": {
99
- "type": "git",
100
- "url": "https://github.com/open-grid/open-grid"
101
- }
98
+ "homepage": "https://foxnail.kr/open-grid/demo/v2/index.php"
102
99
  }