open-grid 1.1.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/open-grid.js CHANGED
@@ -1,54 +1,54 @@
1
- import { b as E } from "./OpenGrid-5flQwc3W.js";
2
- import { O as L } from "./OpenGrid-5flQwc3W.js";
1
+ import { b as E } from "./OpenGrid-yg4mw6Ge.js";
2
+ import { D as $, I as S, O, S as D, i as k, r as M, s as B } from "./OpenGrid-yg4mw6Ge.js";
3
3
  class C {
4
- constructor(t, e, r, i = {}) {
4
+ constructor(t, e, o, i = {}) {
5
5
  this._left = t, this._right = e;
6
- const o = document.createElement("div");
7
- o.className = "og-shuttle", o.style.cssText = `display:flex;gap:6px;align-items:center;justify-content:center;flex-direction:${i.layout === "horizontal" ? "row" : "column"};`;
8
- const c = (m, g, u) => {
9
- const a = document.createElement("button");
10
- return a.type = "button", a.className = "og-shuttle-btn", a.textContent = m, a.title = g, a.style.cssText = "min-width:34px;height:30px;padding:0 8px;border:1px solid #bbb;border-radius:7px;background:#fff;cursor:pointer;font-size:14px;color:#444;line-height:1;box-shadow:0 1px 2px rgba(0,0,0,0.06);", a.addEventListener("mouseover", () => {
11
- a.style.background = "#f0f6ff", a.style.borderColor = "#1976d2";
12
- }), a.addEventListener("mouseout", () => {
13
- a.style.background = "#fff", a.style.borderColor = "#bbb";
14
- }), a.addEventListener("click", u), a;
6
+ const r = document.createElement("div");
7
+ r.className = "og-shuttle", r.style.cssText = `display:flex;gap:6px;align-items:center;justify-content:center;flex-direction:${i.layout === "horizontal" ? "row" : "column"};`;
8
+ const a = (m, f, u) => {
9
+ const c = document.createElement("button");
10
+ return c.type = "button", c.className = "og-shuttle-btn", c.textContent = m, c.title = f, c.style.cssText = "min-width:34px;height:30px;padding:0 8px;border:1px solid #bbb;border-radius:7px;background:#fff;cursor:pointer;font-size:14px;color:#444;line-height:1;box-shadow:0 1px 2px rgba(0,0,0,0.06);", c.addEventListener("mouseover", () => {
11
+ c.style.background = "#f0f6ff", c.style.borderColor = "#1976d2";
12
+ }), c.addEventListener("mouseout", () => {
13
+ c.style.background = "#fff", c.style.borderColor = "#bbb";
14
+ }), c.addEventListener("click", u), c;
15
15
  }, _ = i.labels ?? {};
16
- o.appendChild(c(
16
+ r.appendChild(a(
17
17
  _.toRight ?? "▶",
18
18
  "체크한 행을 오른쪽 그리드로 이동",
19
19
  () => {
20
20
  this._left.moveCheckedTo(this._right);
21
21
  }
22
- )), o.appendChild(c(
22
+ )), r.appendChild(a(
23
23
  _.toLeft ?? "◀",
24
24
  "체크한 행을 왼쪽 그리드로 이동",
25
25
  () => {
26
26
  this._right.moveCheckedTo(this._left);
27
27
  }
28
- )), i.includeAll && (o.appendChild(c(
28
+ )), i.includeAll && (r.appendChild(a(
29
29
  _.allRight ?? "⏩",
30
30
  "왼쪽 전체를 오른쪽으로 이동",
31
31
  () => {
32
32
  this._moveAll(this._left, this._right);
33
33
  }
34
- )), o.appendChild(c(
34
+ )), r.appendChild(a(
35
35
  _.allLeft ?? "⏪",
36
36
  "오른쪽 전체를 왼쪽으로 이동",
37
37
  () => {
38
38
  this._moveAll(this._right, this._left);
39
39
  }
40
- ))), r.appendChild(o), this._el = o;
40
+ ))), o.appendChild(r), this._el = r;
41
41
  }
42
42
  _moveAll(t, e) {
43
- const r = t.getData().length;
44
- r > 0 && t.moveRowsTo(e, Array.from({ length: r }, (i, o) => o));
43
+ const o = t.getData().length;
44
+ o > 0 && t.moveRowsTo(e, Array.from({ length: o }, (i, r) => r));
45
45
  }
46
46
  destroy() {
47
47
  this._el.remove();
48
48
  }
49
49
  }
50
- function v(b, t, e, r) {
51
- return new C(b, t, e, r);
50
+ function v(A, t, e, o) {
51
+ return new C(A, t, e, o);
52
52
  }
53
53
  class N {
54
54
  constructor(t, e) {
@@ -65,16 +65,20 @@ class N {
65
65
  }
66
66
  setData(t) {
67
67
  this._data = t;
68
- const { idField: e, parentIdField: r, expandOnLoad: i } = this._opts;
69
- i && this._expandedKeys.size === 0 && t.forEach((o) => this._expandedKeys.add(o[e])), this._roots = E(t, { idField: e, parentIdField: r }, this._expandedKeys), this._render();
68
+ const { idField: e, parentIdField: o, expandOnLoad: i } = this._opts;
69
+ i && this._expandedKeys.size === 0 && t.forEach((r) => this._expandedKeys.add(r[e])), this._roots = E(t, { idField: e, parentIdField: o }, this._expandedKeys), this._render();
70
70
  }
71
71
  setTheme(t) {
72
72
  this._container.setAttribute("data-og-theme", t);
73
73
  }
74
+ /** R12b: FORM(스킨) 축 — data-og-skin 을 자기 컨테이너에 설정(setTheme 과 동형, 색과 직교). */
75
+ setSkin(t) {
76
+ this._container.setAttribute("data-og-skin", t);
77
+ }
74
78
  expandAll() {
75
79
  const t = (e) => {
76
- for (const r of e)
77
- this._expandedKeys.add(r._treeId), r.children.length && t(r.children);
80
+ for (const o of e)
81
+ this._expandedKeys.add(o._treeId), o.children.length && t(o.children);
78
82
  };
79
83
  t(this._roots), this._rebuild();
80
84
  }
@@ -90,65 +94,65 @@ class N {
90
94
  }
91
95
  // ── 레이아웃 계산 (post-order: 리프부터 배치, 부모는 자식 중앙) ──
92
96
  _calcLayout() {
93
- const { nodeWidth: t, nodeHeight: e, levelGap: r, siblingGap: i } = this._opts, o = /* @__PURE__ */ new Map();
94
- let c = 0;
97
+ const { nodeWidth: t, nodeHeight: e, levelGap: o, siblingGap: i } = this._opts, r = /* @__PURE__ */ new Map();
98
+ let a = 0;
95
99
  const _ = (u) => {
96
- const a = u._depth * (e + r), p = u._expanded ? u.children : [];
100
+ const c = u._depth * (e + o), p = u._expanded ? u.children : [];
97
101
  if (!p.length) {
98
- const f = c;
99
- return c += t + i, o.set(u._treeId, { x: f, y: a }), { minX: f, maxX: f };
102
+ const g = a;
103
+ return a += t + i, r.set(u._treeId, { x: g, y: c }), { minX: g, maxX: g };
100
104
  }
101
105
  let n = 1 / 0, l = -1 / 0;
102
- for (const f of p) {
103
- const { minX: s, maxX: h } = _(f);
106
+ for (const g of p) {
107
+ const { minX: s, maxX: h } = _(g);
104
108
  s < n && (n = s), h > l && (l = h);
105
109
  }
106
110
  const d = n + (l - n + t) / 2 - t / 2;
107
- return o.set(u._treeId, { x: d, y: a }), { minX: n, maxX: l };
111
+ return r.set(u._treeId, { x: d, y: c }), { minX: n, maxX: l };
108
112
  };
109
113
  for (const u of this._roots) _(u);
110
- let m = 0, g = 0;
111
- for (const { x: u, y: a } of o.values())
112
- u + t > m && (m = u + t), a + e > g && (g = a + e);
113
- return { layout: o, totalW: m + i, totalH: g + r + 16 };
114
+ let m = 0, f = 0;
115
+ for (const { x: u, y: c } of r.values())
116
+ u + t > m && (m = u + t), c + e > f && (f = c + e);
117
+ return { layout: r, totalW: m + i, totalH: f + o + 16 };
114
118
  }
115
119
  // ── SVG 직선 헬퍼 ──
116
- _line(t, e, r, i, o) {
117
- const c = document.createElementNS("http://www.w3.org/2000/svg", "line");
118
- c.setAttribute("x1", String(e)), c.setAttribute("y1", String(r)), c.setAttribute("x2", String(i)), c.setAttribute("y2", String(o)), c.setAttribute("class", "og-orgchart-line"), t.appendChild(c);
120
+ _line(t, e, o, i, r) {
121
+ const a = document.createElementNS("http://www.w3.org/2000/svg", "line");
122
+ a.setAttribute("x1", String(e)), a.setAttribute("y1", String(o)), a.setAttribute("x2", String(i)), a.setAttribute("y2", String(r)), a.setAttribute("class", "og-orgchart-line"), t.appendChild(a);
119
123
  }
120
124
  // ── 렌더 ──
121
125
  _render() {
122
- const { nodeWidth: t, nodeHeight: e, levelGap: r, columns: i } = this._opts, { layout: o, totalW: c, totalH: _ } = this._calcLayout();
126
+ const { nodeWidth: t, nodeHeight: e, levelGap: o, columns: i } = this._opts, { layout: r, totalW: a, totalH: _ } = this._calcLayout();
123
127
  this._container.innerHTML = "";
124
128
  const m = document.createElement("div");
125
- m.className = "og-orgchart-wrap", m.style.cssText = `width:${c}px;height:${_}px;`;
126
- const g = document.createElementNS("http://www.w3.org/2000/svg", "svg");
127
- g.setAttribute("width", String(c)), g.setAttribute("height", String(_)), g.style.cssText = "position:absolute;top:0;left:0;pointer-events:none;overflow:visible;";
129
+ m.className = "og-orgchart-wrap", m.style.cssText = `width:${a}px;height:${_}px;`;
130
+ const f = document.createElementNS("http://www.w3.org/2000/svg", "svg");
131
+ f.setAttribute("width", String(a)), f.setAttribute("height", String(_)), f.style.cssText = "position:absolute;top:0;left:0;pointer-events:none;overflow:visible;";
128
132
  const u = (p) => {
129
133
  for (const n of p) {
130
134
  if (!n._expanded || !n.children.length) continue;
131
- const l = o.get(n._treeId), d = l.x + t / 2, f = l.y + e, s = f + r / 2, h = n.children;
132
- if (this._line(g, d, f, d, s), h.length > 1) {
133
- const x = o.get(h[0]._treeId), y = o.get(h[h.length - 1]._treeId);
134
- this._line(g, x.x + t / 2, s, y.x + t / 2, s);
135
+ const l = r.get(n._treeId), d = l.x + t / 2, g = l.y + e, s = g + o / 2, h = n.children;
136
+ if (this._line(f, d, g, d, s), h.length > 1) {
137
+ const x = r.get(h[0]._treeId), y = r.get(h[h.length - 1]._treeId);
138
+ this._line(f, x.x + t / 2, s, y.x + t / 2, s);
135
139
  }
136
140
  for (const x of h) {
137
- const y = o.get(x._treeId), A = y.x + t / 2;
138
- this._line(g, A, s, A, y.y);
141
+ const y = r.get(x._treeId), b = y.x + t / 2;
142
+ this._line(f, b, s, b, y.y);
139
143
  }
140
144
  u(h);
141
145
  }
142
146
  };
143
- u(this._roots), m.appendChild(g);
144
- const a = (p) => {
147
+ u(this._roots), m.appendChild(f);
148
+ const c = (p) => {
145
149
  for (const n of p) {
146
- const l = o.get(n._treeId);
150
+ const l = r.get(n._treeId);
147
151
  if (!l) continue;
148
152
  const d = document.createElement("div");
149
153
  d.className = "og-orgchart-node", n._hasChildren && d.classList.add("og-orgchart-node--branch"), n._expanded && d.classList.add("og-orgchart-node--expanded"), this._selectedId === n._treeId && d.classList.add("og-orgchart-node--selected"), d.style.cssText = `left:${l.x}px;top:${l.y}px;width:${t}px;height:${e}px;`;
150
- const f = document.createElement("div");
151
- f.className = "og-orgchart-node-content";
154
+ const g = document.createElement("div");
155
+ g.className = "og-orgchart-node-content";
152
156
  for (const s of i) {
153
157
  const h = n.data[s.field], x = document.createElement("div");
154
158
  if (x.className = "og-orgchart-col" + (s.className ? " " + s.className : ""), s.style) {
@@ -160,9 +164,9 @@ class N {
160
164
  typeof y == "string" ? x.innerHTML = y : x.appendChild(y);
161
165
  } else
162
166
  x.textContent = h ?? "";
163
- f.appendChild(x);
167
+ g.appendChild(x);
164
168
  }
165
- if (d.appendChild(f), n._hasChildren) {
169
+ if (d.appendChild(g), n._hasChildren) {
166
170
  const s = document.createElement("button");
167
171
  s.type = "button", s.className = "og-orgchart-toggle", s.setAttribute("aria-expanded", n._expanded ? "true" : "false"), s.setAttribute("aria-label", n._expanded ? "접기" : "펼치기");
168
172
  const h = document.createElement("i");
@@ -172,13 +176,13 @@ class N {
172
176
  }
173
177
  d.addEventListener("click", () => {
174
178
  this._selectedId = n._treeId, this._opts.onNodeClick(n._treeId, n.data), this._container.querySelectorAll(".og-orgchart-node--selected").forEach((s) => s.classList.remove("og-orgchart-node--selected")), d.classList.add("og-orgchart-node--selected");
175
- }), m.appendChild(d), n._expanded && n.children.length && a(n.children);
179
+ }), m.appendChild(d), n._expanded && n.children.length && c(n.children);
176
180
  }
177
181
  };
178
- a(this._roots), this._container.appendChild(m);
182
+ c(this._roots), this._container.appendChild(m);
179
183
  }
180
184
  }
181
- class w {
185
+ class I {
182
186
  // ── 1. XML → 데이터 배열 ────────────────────────────────────
183
187
  /**
184
188
  * XML 문자열을 파싱하여 그리드 데이터 배열로 변환.
@@ -188,28 +192,28 @@ class w {
188
192
  */
189
193
  static parse(t, e = {}) {
190
194
  var p, n;
191
- const { fieldMap: r = {}, trim: i = !0 } = e, c = new DOMParser().parseFromString(t.trim(), "text/xml"), _ = c.querySelector("parsererror");
195
+ const { fieldMap: o = {}, trim: i = !0 } = e, a = new DOMParser().parseFromString(t.trim(), "text/xml"), _ = a.querySelector("parsererror");
192
196
  if (_) throw new Error(`XML 파싱 오류: ${(p = _.textContent) == null ? void 0 : p.trim()}`);
193
- const m = c.documentElement;
194
- let g = e.rowTag;
195
- if (!g) {
196
- const l = e.rootTag ? c.querySelector(e.rootTag) : m;
197
- g = ((n = l == null ? void 0 : l.children[0]) == null ? void 0 : n.tagName) ?? "row";
197
+ const m = a.documentElement;
198
+ let f = e.rowTag;
199
+ if (!f) {
200
+ const l = e.rootTag ? a.querySelector(e.rootTag) : m;
201
+ f = ((n = l == null ? void 0 : l.children[0]) == null ? void 0 : n.tagName) ?? "row";
198
202
  }
199
- const u = c.getElementsByTagName(g), a = [];
203
+ const u = a.getElementsByTagName(f), c = [];
200
204
  for (let l = 0; l < u.length; l++) {
201
- const d = u[l], f = {};
205
+ const d = u[l], g = {};
202
206
  for (const s of Array.from(d.attributes)) {
203
- const h = r[s.name] ?? s.name;
204
- f[h] = i ? s.value.trim() : s.value;
207
+ const h = o[s.name] ?? s.name;
208
+ g[h] = i ? s.value.trim() : s.value;
205
209
  }
206
210
  for (const s of Array.from(d.children)) {
207
- const h = r[s.tagName] ?? s.tagName, x = s.textContent ?? "";
208
- f[h] = i ? x.trim() : x;
211
+ const h = o[s.tagName] ?? s.tagName, x = s.textContent ?? "";
212
+ g[h] = i ? x.trim() : x;
209
213
  }
210
- a.push(f);
214
+ c.push(g);
211
215
  }
212
- return a;
216
+ return c;
213
217
  }
214
218
  // ── 2. 데이터 배열 → XML ─────────────────────────────────────
215
219
  /**
@@ -217,34 +221,34 @@ class w {
217
221
  */
218
222
  static stringify(t, e = {}) {
219
223
  const {
220
- rootTag: r = "rows",
224
+ rootTag: o = "rows",
221
225
  rowTag: i = "row",
222
- mode: o = "element",
223
- fieldMap: c = {},
226
+ mode: r = "element",
227
+ fieldMap: a = {},
224
228
  declaration: _ = !0,
225
229
  indent: m = 2,
226
- nullAs: g = "",
230
+ nullAs: f = "",
227
231
  excludeFields: u = []
228
- } = e, a = " ".repeat(m), p = [];
229
- _ && p.push('<?xml version="1.0" encoding="UTF-8"?>'), p.push(`<${r}>`);
232
+ } = e, c = " ".repeat(m), p = [];
233
+ _ && p.push('<?xml version="1.0" encoding="UTF-8"?>'), p.push(`<${o}>`);
230
234
  for (const n of t) {
231
235
  const l = Object.entries(n).filter(([d]) => !u.includes(d));
232
- if (o === "attribute") {
233
- const d = l.map(([f, s]) => {
234
- const h = c[f] ?? f, x = s == null ? g : String(s);
236
+ if (r === "attribute") {
237
+ const d = l.map(([g, s]) => {
238
+ const h = a[g] ?? g, x = s == null ? f : String(s);
235
239
  return `${h}="${this._escAttr(x)}"`;
236
240
  }).join(" ");
237
- p.push(`${a}<${i}${d ? " " + d : ""} />`);
241
+ p.push(`${c}<${i}${d ? " " + d : ""} />`);
238
242
  } else {
239
- p.push(`${a}<${i}>`);
240
- for (const [d, f] of l) {
241
- const s = c[d] ?? d, h = f == null ? g : String(f);
242
- p.push(`${a}${a}<${s}>${this._escText(h)}</${s}>`);
243
+ p.push(`${c}<${i}>`);
244
+ for (const [d, g] of l) {
245
+ const s = a[d] ?? d, h = g == null ? f : String(g);
246
+ p.push(`${c}${c}<${s}>${this._escText(h)}</${s}>`);
243
247
  }
244
- p.push(`${a}</${i}>`);
248
+ p.push(`${c}</${i}>`);
245
249
  }
246
250
  }
247
- return p.push(`</${r}>`), p.join(`
251
+ return p.push(`</${o}>`), p.join(`
248
252
  `);
249
253
  }
250
254
  // ── 3. SAP BAPI XML 응답 파싱 ────────────────────────────────
@@ -257,38 +261,38 @@ class w {
257
261
  * <RETURN><TYPE>S</TYPE><MESSAGE>...</MESSAGE></RETURN>
258
262
  */
259
263
  static parseSap(t) {
260
- var m, g, u, a;
261
- const r = new DOMParser().parseFromString(t.trim(), "text/xml"), i = { header: {}, items: [], returns: [], raw: r }, o = r.getElementsByTagName("DOCUMENTHEADER")[0];
262
- if (o)
263
- for (const p of Array.from(o.children))
264
+ var m, f, u, c;
265
+ const o = new DOMParser().parseFromString(t.trim(), "text/xml"), i = { header: {}, items: [], returns: [], raw: o }, r = o.getElementsByTagName("DOCUMENTHEADER")[0];
266
+ if (r)
267
+ for (const p of Array.from(r.children))
264
268
  i.header[p.tagName] = ((m = p.textContent) == null ? void 0 : m.trim()) ?? "";
265
- const c = r.getElementsByTagName("RETURN");
266
- for (const p of Array.from(c)) {
269
+ const a = o.getElementsByTagName("RETURN");
270
+ for (const p of Array.from(a)) {
267
271
  const n = {};
268
272
  for (const l of Array.from(p.children))
269
- n[l.tagName] = ((g = l.textContent) == null ? void 0 : g.trim()) ?? "";
273
+ n[l.tagName] = ((f = l.textContent) == null ? void 0 : f.trim()) ?? "";
270
274
  i.returns.push(n);
271
275
  }
272
276
  const _ = ["ACCOUNTGL", "ACCOUNTRECEIVABLE", "ACCOUNTPAYABLE", "ITEMS"];
273
277
  for (const p of _) {
274
- const n = r.getElementsByTagName(p)[0];
278
+ const n = o.getElementsByTagName(p)[0];
275
279
  if (!n) continue;
276
280
  const l = n.getElementsByTagName("ITEM"), d = l.length > 0 ? Array.from(l) : [n];
277
- for (const f of d) {
281
+ for (const g of d) {
278
282
  const s = {};
279
- for (const h of Array.from(f.children))
283
+ for (const h of Array.from(g.children))
280
284
  s[h.tagName] = ((u = h.textContent) == null ? void 0 : u.trim()) ?? "";
281
285
  i.items.push(s);
282
286
  }
283
287
  break;
284
288
  }
285
289
  if (i.items.length === 0) {
286
- const p = r.documentElement, n = Array.from(p.children).filter((l) => l.hasAttribute("SEGMENT"));
290
+ const p = o.documentElement, n = Array.from(p.children).filter((l) => l.hasAttribute("SEGMENT"));
287
291
  for (const l of n) {
288
292
  if (l.tagName === "EDI_DC40") continue;
289
293
  const d = {};
290
- for (const f of Array.from(l.children))
291
- d[f.tagName] = ((a = f.textContent) == null ? void 0 : a.trim()) ?? "";
294
+ for (const g of Array.from(l.children))
295
+ d[g.tagName] = ((c = g.textContent) == null ? void 0 : c.trim()) ?? "";
292
296
  Object.keys(d).length > 0 && i.items.push(d);
293
297
  }
294
298
  }
@@ -306,22 +310,22 @@ class w {
306
310
  ];
307
311
  if (t.BAPI_FUNCTION && e.push(` <FUNCTION>${this._escText(t.BAPI_FUNCTION)}</FUNCTION>`), t.DOCUMENTHEADER && typeof t.DOCUMENTHEADER == "object") {
308
312
  e.push(" <DOCUMENTHEADER>");
309
- for (const [i, o] of Object.entries(t.DOCUMENTHEADER))
310
- o != null && o !== "" && e.push(` <${i}>${this._escText(String(o))}</${i}>`);
313
+ for (const [i, r] of Object.entries(t.DOCUMENTHEADER))
314
+ r != null && r !== "" && e.push(` <${i}>${this._escText(String(r))}</${i}>`);
311
315
  e.push(" </DOCUMENTHEADER>");
312
316
  }
313
- const r = Object.keys(t).find(
317
+ const o = Object.keys(t).find(
314
318
  (i) => Array.isArray(t[i]) && !i.startsWith("_")
315
319
  );
316
- if (r) {
317
- e.push(` <${r}>`);
318
- for (const i of t[r]) {
320
+ if (o) {
321
+ e.push(` <${o}>`);
322
+ for (const i of t[o]) {
319
323
  e.push(" <ITEM>");
320
- for (const [o, c] of Object.entries(i))
321
- c != null && c !== "" && !o.startsWith("_") && e.push(` <${o}>${this._escText(String(c))}</${o}>`);
324
+ for (const [r, a] of Object.entries(i))
325
+ a != null && a !== "" && !r.startsWith("_") && e.push(` <${r}>${this._escText(String(a))}</${r}>`);
322
326
  e.push(" </ITEM>");
323
327
  }
324
- e.push(` </${r}>`);
328
+ e.push(` </${o}>`);
325
329
  }
326
330
  return e.push("</BAPI_CALL>"), e.join(`
327
331
  `);
@@ -336,12 +340,12 @@ class w {
336
340
  '<?xml version="1.0" encoding="UTF-8"?>',
337
341
  `<BAPI_BATCH total="${t.documents.length}">`
338
342
  ];
339
- return t.documents.forEach((r, i) => {
343
+ return t.documents.forEach((o, i) => {
340
344
  e.push(` <BAPI_CALL seq="${i + 1}">`);
341
- const o = this.stringifySap(r).split(`
342
- `).filter((c) => !c.startsWith("<?xml")).map((c) => " " + c).join(`
345
+ const r = this.stringifySap(o).split(`
346
+ `).filter((a) => !a.startsWith("<?xml")).map((a) => " " + a).join(`
343
347
  `);
344
- e.push(o), e.push(" </BAPI_CALL>");
348
+ e.push(r), e.push(" </BAPI_CALL>");
345
349
  }), e.push("</BAPI_BATCH>"), e.join(`
346
350
  `);
347
351
  }
@@ -354,10 +358,16 @@ class w {
354
358
  }
355
359
  }
356
360
  export {
361
+ $ as DEFAULT_ICON_ROLES,
357
362
  C as GridShuttle,
358
- L as OpenGrid,
363
+ S as IconRegistry,
364
+ O as OpenGrid,
359
365
  N as OrgChart,
360
- w as XmlConverter,
361
- v as createGridShuttle
366
+ D as SkinRegistry,
367
+ I as XmlConverter,
368
+ v as createGridShuttle,
369
+ k as iconRegistry,
370
+ M as renderIcon,
371
+ B as skinRegistry
362
372
  };
363
373
  //# sourceMappingURL=open-grid.js.map
@@ -0,0 +1,100 @@
1
+ /**
2
+ * ThemeContext — DOM-free 값 객체. 활성 색 테마(및 미래의 스킨) 식별자를 운반한다.
3
+ * R12a 에서 resolver 메서드는 아직 이 컨텍스트로 분기하지 않는다(반환은 항상 `var()` 문자열이라
4
+ * 브라우저가 런타임에 테마별로 재계산 → 오늘의 zero-rerender 테마 전환을 보존, 현상맵 §1.3).
5
+ * R12b(스킨)에서 `skin` 을 읽어 FORM 토큰을 해결하는 자리를 여기 마련해 둔다.
6
+ */
7
+ export declare class ThemeContext {
8
+ readonly theme: string;
9
+ readonly skin: string;
10
+ constructor(theme?: string, skin?: string);
11
+ }
12
+ /**
13
+ * propagateAppearance — 분리(portal-ed) UI 로 외관 축을 함께 복사(item3 §4.3, HANMS Q8).
14
+ * 두 속성(`data-og-theme` COLOR · `data-og-skin` FORM)을 **한 번에** 복사해, 컴포넌트마다
15
+ * 두 번째 속성을 잊어 스킨만 안 먹는 조용한 사고(§6-9)를 구조적으로 막는다.
16
+ * `fromEl` 에서 가장 가까운 속성 보유 조상을 찾아 `toEl` 에 복사한다.
17
+ */
18
+ export declare function propagateAppearance(fromEl: Element | null, toEl: Element): void;
19
+ /** border()/focusRing() 형태 옵션(미래 스킨용). 미지정 시 오늘의 기본값 = byte-identical. */
20
+ export interface BorderOptions {
21
+ /** 보더 스타일 키워드(기본 'solid'). */
22
+ style?: string;
23
+ /** true 면 상태(added/edited/removed·selection·range) 보더 — HANMS G-ST2: 항상 solid 강제. */
24
+ state?: boolean;
25
+ }
26
+ export interface FocusRingOptions {
27
+ width?: number;
28
+ style?: string;
29
+ color?: string;
30
+ }
31
+ export type ElevationLevel = 'sm' | 'md' | 'lg';
32
+ /**
33
+ * AppearanceResolver — 렌더 레이어가 "형태 값"을 물어보는 단일 지점.
34
+ * R12a 는 **결정을 객체화**할 뿐 값은 오늘과 동일하다(회귀 0). 상태 없음(순수) — 반환은
35
+ * `var()` 기반 문자열 또는 px 패스스루라, 인스턴스 공유가 안전하다(멀티그리드 격리 무해).
36
+ */
37
+ export declare class AppearanceResolver {
38
+ private _ctx;
39
+ constructor(_ctx?: ThemeContext);
40
+ /** 활성 테마/스킨 컨텍스트(R12b 스킨 해결의 진입점). */
41
+ get context(): ThemeContext;
42
+ /** 스킨이 활성(비-default)인가. default 면 오늘의 리터럴을 그대로 반환(byte-identical). */
43
+ private _skinActive;
44
+ /**
45
+ * R12b: 스킨 컨텍스트 교체(테마는 유지). 파사드 setSkin 이 호출한 뒤 재렌더하면 인라인 form 사이트가
46
+ * 이 컨텍스트로 재해석된다. default → named 전환 시 border/divider 가 리터럴 → var() 로 승격.
47
+ */
48
+ setSkin(skin: string): void;
49
+ /** border-color 토큰 참조(폴백 포함) — 렌더 코드가 오늘 쓰는 문자열과 동일. */
50
+ private _borderColorVar;
51
+ /**
52
+ * 셀/헤더 가장자리 보더. 오늘의 리터럴 `1px solid var(--og-border-color,#e0e0e0)` 과
53
+ * **문자 단위 동일**. HANMS G-ST2: state 보더는 스타일을 solid 로 강제(현재 호출은 state 미지정 → no-op).
54
+ */
55
+ border(opts?: BorderOptions): string;
56
+ /**
57
+ * 행/섹션 구획선(가로 separator). 오늘은 border() 와 동일 문자열(=`1px solid var(--og-border-color,#e0e0e0)`).
58
+ * 별도 메서드로 둔 이유: R12b 스킨에서 divider-style 이 border-style 과 갈라질 수 있어(§1.2)
59
+ * 결정 지점을 미리 분리해 둔다. 현재 출력은 border() 와 byte-identical.
60
+ */
61
+ divider(): string;
62
+ /**
63
+ * G-ST1(코어 불변식, HANMS §2): 텍스처 존 제한. 텍스처는 컨테이너 배경·헤더 여백·빈 상태·온보딩
64
+ * 오버레이에만 렌더되고, **데이터/상태/범위/병합/포커스 셀 배경 뒤에는 절대 렌더 금지**(스킨이 끌 수 없음).
65
+ * 렌더 레이어가 셀 배경 텍스처를 바를 때 이 메서드로 zone 을 물어본다.
66
+ * - 금지 zone → 항상 `'none'`(스킨과 무관).
67
+ * - 허용 zone → `var(--og-texture-bg, none)`(스킨 미설정 시 none = byte-identical).
68
+ */
69
+ texture(zone: 'container' | 'header-pad' | 'empty' | 'onboarding' | 'data' | 'status' | 'range' | 'merge' | 'focus'): string;
70
+ /**
71
+ * 반경 값 → CSS 길이 문자열. R12a 는 패스스루(`${px}px`)로 오늘의 리터럴을 그대로 보존한다.
72
+ * 반경 리터럴이 흩어져 있던 결정 지점(이미지/프로그레스/스위치/뱃지/마스킹/상태뱃지)을 이 한 곳으로 모은다.
73
+ * R12b 에서 `--og-radius-*` 스케일 토큰으로 승격할 착지점.
74
+ */
75
+ radius(px: number): string;
76
+ /**
77
+ * 데이터/그룹 셀의 인라인 패딩. 오늘의 그룹 셀 리터럴 `2px 8px` 과 동일.
78
+ * R12b `--og-cell-padding-*` 승격 자리.
79
+ */
80
+ cellPadding(): string;
81
+ /**
82
+ * 엘리베이션(box-shadow) — R12b 스킨 축의 형태/잉크 분리 seam(§1.4)을 미리 표기한다.
83
+ * R12a 에서는 어떤 인라인 사이트도 이 메서드를 경유하지 않는다(현재 그림자 결정이 인라인에 없음).
84
+ * 값은 미래 토큰 + 오늘과 무해한 기본 geometry/alpha 로, 라우팅 0 이라 출력에 영향 없음.
85
+ */
86
+ elevation(level?: ElevationLevel): string;
87
+ /**
88
+ * 포커스 링. HANMS 하드 계약(불변식): 가시 포커스는 비협상 —
89
+ * `width < 2px` 또는 `style: 'none'` 은 최소 `2px solid` 로 **클램프**한다(스킨이 끌 수 없음).
90
+ * R12a 에서 라우팅되는 인라인 포커스 사이트는 없다(포커스 표시는 CSS 클래스 `.og-cell-focused`).
91
+ * 기본 반환은 현 프라이머리 색 기반의 AA-safe 링 — 미래 스킨/오버라이드가 이 초크포인트를 경유한다.
92
+ */
93
+ focusRing(opts?: FocusRingOptions): string;
94
+ }
95
+ /**
96
+ * 프로세스 공유 기본 resolver. CellRenderer(팩토리로 생성돼 per-instance 컨텍스트를 받지 않음)가
97
+ * 반경 결정을 이 초크포인트로 보낼 때 사용한다. R12a 반환은 상태 없는 순수값이라 공유가 안전하다.
98
+ * per-instance(테마 컨텍스트) 주입은 R12b 스킨에서 확장한다.
99
+ */
100
+ export declare const defaultAppearance: AppearanceResolver;
@@ -0,0 +1,70 @@
1
+ import { DataLayer } from './DataLayer.js';
2
+ import { ColumnLayout } from './ColumnLayout.js';
3
+ import { GridOptions, OpenGridInstance, Position, GridDropEvent } from './types.js';
4
+ /**
5
+ * R7(§3.1 C8, §6-R7): 그리드 간 이동·매핑·drop 표면(`moveRowsTo`/`moveCheckedTo`/크로스변환 해석/
6
+ * 3단계 드롭 이벤트 발화)을 `OpenGrid` God object 에서 **동작 불변**으로 옮긴 것. `OpenGrid` 는
7
+ * 얇은 위임 공개 메서드만 남긴다(공개 API 불변 — R0 `public_api_surface.txt` 동결).
8
+ *
9
+ * 스트랭글러 원칙(A2): `crossGridRegistry`(프로세스 스코프 싱글턴, `CrossGridRegistry.ts`)는 지금은
10
+ * **AS-IS 유지**한다 — 주입 `GridRegistry` 로의 승격(C8, R-6c)은 R8 컴포지션 루트로 이연한다.
11
+ *
12
+ * cross-grid 이동은 **두 그리드**(source=this, target)를 동시에 다룬다. 각 `OpenGrid` 는 자신의
13
+ * CrossGridController 를 소유하므로, target 측 연산(insert/rowCount/컬럼/3단계 발화)은
14
+ * `getPeerController(target)` 로 얻은 상대 컨트롤러의 동명 메서드로 수행한다 — `this`(source) 와
15
+ * peer(target) 로 갈라 원본의 `this._x` / `targetGrid._x` 접근을 1:1 재현한다(회귀 0).
16
+ * **3단계 drop emit 순서(before→후 이동→after→complete, 각 source→target)는 정확히 보존한다.**
17
+ */
18
+ export interface CrossGridControllerDeps<T extends Record<string, any> = any> {
19
+ /** GridDropEvent 의 sourceGrid/targetGrid 식별자 + 자기동일성 비교에 쓰는 소유 그리드. */
20
+ getSelf: () => OpenGridInstance<T>;
21
+ getData: () => DataLayer<T>;
22
+ getColLayout: () => ColumnLayout<T>;
23
+ getOptions: () => Required<GridOptions<T>>;
24
+ /** EventEmitter fan(this.emit) — 'gridDropBefore/After/Complete'/'gridDropMapping'. */
25
+ emit: (event: string, payload?: any) => void;
26
+ /** 공개 insertRow 위임(MutationService 경유) — target 삽입에 쓰인다. */
27
+ insertRow: (item: Partial<T>, position?: Position) => void;
28
+ /** 공개 deleteRow 위임(MutationService 경유) — source 제거에 쓰인다. */
29
+ deleteRow: (rowIndex: number | number[]) => void;
30
+ /** rowMgr.getChecked() — moveCheckedTo. */
31
+ getChecked: () => Array<{
32
+ rowIndex: number;
33
+ }>;
34
+ /** rowMgr.uncheckAll()(+재렌더) 공개 위임 — moveCheckedTo. */
35
+ uncheckAll: () => void;
36
+ /** 드래그 선택 집합 해석(_dragRowSet). OpenGrid 가 소유(RowDragDrop 배선과 공유). */
37
+ dragRowSet: (fromIndex: number) => number[];
38
+ /** 상대 그리드의 CrossGridController 획득(피어 연산 위임). 비 OpenGrid 대상은 undefined. */
39
+ getPeerController: (grid: OpenGridInstance<T>) => CrossGridController<T> | undefined;
40
+ }
41
+ export declare class CrossGridController<T extends Record<string, any> = any> {
42
+ private _deps;
43
+ constructor(deps: CrossGridControllerDeps<T>);
44
+ /** 이 그리드의 소유 인스턴스(GridDropEvent 식별자). */
45
+ getSelf(): OpenGridInstance<T>;
46
+ private _rowCount;
47
+ private _insertRow;
48
+ private _visibleLeafInfos;
49
+ /** 드래그 드롭 어댑터 → 공개 moveRowsTo 로 위임 */
50
+ handleCrossGridDrop(fromIndex: number, targetBodyEl: HTMLElement, targetIndex: number): void;
51
+ /**
52
+ * 이 그리드의 행들을 다른 그리드로 이동(move)한다. 드래그·화살표 셔틀 공통 경로.
53
+ * 3단계 이벤트(before→after→complete)와 crossGridMapping(필드 매핑)을 적용한다.
54
+ * @param target 대상 그리드
55
+ * @param sourceIndexes 이동할 (표시)행 인덱스들
56
+ * @param targetIndex 대상에서 삽입 위치 (생략 시 맨 끝에 추가)
57
+ * @returns 이동 성공 true, 취소/무효 false
58
+ */
59
+ moveRowsTo(target: OpenGridInstance<T>, sourceIndexes: number[], targetIndex?: number): Promise<boolean>;
60
+ /** 체크된 행을 다른 그리드로 이동 (화살표 셔틀용). 체크 없으면 무시. */
61
+ moveCheckedTo(target: OpenGridInstance<T>): Promise<boolean>;
62
+ /**
63
+ * 크로스그리드 이동의 행 변환 함수를 결정한다.
64
+ * 반환: null=변환 불필요(그대로) / 함수=변환 적용 / false=매핑 모달 취소(이동 중단)
65
+ */
66
+ private _resolveCrossTransform;
67
+ fireGridDropBefore(e: GridDropEvent<T>): boolean | void;
68
+ fireGridDropAfter(e: GridDropEvent<T>): void;
69
+ fireGridDropComplete(e: GridDropEvent<T>): void;
70
+ }