@nine-lab/nine-util 0.9.125 → 0.9.127

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/nine-util.js CHANGED
@@ -9,53 +9,7 @@ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read fr
9
9
  var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
10
10
  var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
11
11
  var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
12
- var _shift, _dialog, _init, _onMouseDown, _onTouchStart, _NineUtil_instances, prepare_fn, _name, _color, _enabled, _Trace_instances, autoConfig_fn, _timer, _queue, _delay, _TaskDebouncer_instances, flush_fn, _request, _mode, _detectMode, _startDrag, _init2, _prepareLayout;
13
- const listeners = /* @__PURE__ */ new Set();
14
- const _initialConfig = {
15
- ux: { nativeOverride: false, theme: "light" },
16
- board: { readOnly: false },
17
- cssPath: "",
18
- debug: false
19
- };
20
- if (typeof window !== "undefined" && !window.__NINE_GLOBAL_CONFIG__) {
21
- window.__NINE_GLOBAL_CONFIG__ = _initialConfig;
22
- }
23
- const _config = typeof window !== "undefined" ? window.__NINE_GLOBAL_CONFIG__ : _initialConfig;
24
- const subscribeConfig = (fn) => {
25
- listeners.add(fn);
26
- fn("all", _config);
27
- return () => listeners.delete(fn);
28
- };
29
- const config = new Proxy(_config, {
30
- set(target, prop, value) {
31
- target[prop] = value;
32
- listeners.forEach((fn) => fn(prop, target));
33
- return true;
34
- },
35
- get(target, prop) {
36
- return target[prop];
37
- }
38
- });
39
- const nine = {
40
- config,
41
- // Getter에서 window.nine까지 확인할 필요도 없습니다.
42
- // 이미 config 자체가 전역 저장소(__NINE_GLOBAL_CONFIG__)를 바라보고 있기 때문입니다.
43
- get cssPath() {
44
- return this.config.cssPath || "";
45
- },
46
- setup(options = {}) {
47
- Object.entries(options).forEach(([key, value]) => {
48
- if (typeof value === "object" && value !== null && !Array.isArray(value)) {
49
- this.config[key] = { ...this.config[key], ...value };
50
- } else {
51
- this.config[key] = value;
52
- }
53
- });
54
- if (typeof window !== "undefined") {
55
- window.nine = window.nine || this;
56
- }
57
- }
58
- };
12
+ var _shift, _dialog, _init, _onMouseDown, _onTouchStart, _NineUtil_instances, prepare_fn, _name, _color, _enabled, _Trace_instances, autoConfig_fn, _a, _timer, _queue, _delay, _TaskDebouncer_instances, flush_fn, _request, _mode, _detectMode, _startDrag, _init2, _prepareLayout;
59
13
  const dialogStyles = `
60
14
  dialog::backdrop {
61
15
  background: rgba(0, 0, 0, 0.3);
@@ -621,14 +575,14 @@ class BasePopup extends HTMLElement {
621
575
  this.attachShadow({ mode: "open" });
622
576
  }
623
577
  static async open(PopupClass, message, title, options, renderFn) {
624
- var _a, _b, _c;
578
+ var _a2, _b, _c;
625
579
  const tagName = PopupClass.tagName.toLowerCase();
626
580
  const config2 = {
627
581
  "true-text": "확인",
628
582
  "false-text": "취소",
629
583
  class: "classic",
630
584
  animation: "fade",
631
- ...((_c = (_b = (_a = window.nine) == null ? void 0 : _a.config) == null ? void 0 : _b.ux) == null ? void 0 : _c[tagName.replace("nine-", "").replace("-popup", "")]) || {},
585
+ ...((_c = (_b = (_a2 = window.nine) == null ? void 0 : _a2.config) == null ? void 0 : _b.ux) == null ? void 0 : _c[tagName.replace("nine-", "").replace("-popup", "")]) || {},
632
586
  ...options
633
587
  };
634
588
  document.querySelectorAll(tagName).forEach((el2) => el2.remove());
@@ -795,7 +749,53 @@ prepare_fn = function(type, message, title, defaultClass) {
795
749
  };
796
750
  // static 필드는 클래스 자체에 저장됨
797
751
  __publicField(NineUtil, "cssPath", "");
798
- class Trace {
752
+ const listeners = /* @__PURE__ */ new Set();
753
+ const _initialConfig = {
754
+ ux: { nativeOverride: false, theme: "light" },
755
+ board: { readOnly: false },
756
+ cssPath: "",
757
+ debug: false
758
+ };
759
+ if (typeof window !== "undefined" && !window.__NINE_GLOBAL_CONFIG__) {
760
+ window.__NINE_GLOBAL_CONFIG__ = _initialConfig;
761
+ }
762
+ const _config = typeof window !== "undefined" ? window.__NINE_GLOBAL_CONFIG__ : _initialConfig;
763
+ const subscribeConfig = (fn) => {
764
+ listeners.add(fn);
765
+ fn("all", _config);
766
+ return () => listeners.delete(fn);
767
+ };
768
+ const config = new Proxy(_config, {
769
+ set(target, prop, value) {
770
+ target[prop] = value;
771
+ listeners.forEach((fn) => fn(prop, target));
772
+ return true;
773
+ },
774
+ get(target, prop) {
775
+ return target[prop];
776
+ }
777
+ });
778
+ const nine = {
779
+ config,
780
+ // Getter에서 window.nine까지 확인할 필요도 없습니다.
781
+ // 이미 config 자체가 전역 저장소(__NINE_GLOBAL_CONFIG__)를 바라보고 있기 때문입니다.
782
+ get cssPath() {
783
+ return this.config.cssPath || "";
784
+ },
785
+ setup(options = {}) {
786
+ Object.entries(options).forEach(([key, value]) => {
787
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
788
+ this.config[key] = { ...this.config[key], ...value };
789
+ } else {
790
+ this.config[key] = value;
791
+ }
792
+ });
793
+ if (typeof window !== "undefined") {
794
+ window.nine = window.nine || this;
795
+ }
796
+ }
797
+ };
798
+ let Trace$1 = (_a = class {
799
799
  constructor(name = null, color = "green") {
800
800
  __privateAdd(this, _Trace_instances);
801
801
  __privateAdd(this, _name);
@@ -835,12 +835,7 @@ class Trace {
835
835
  disable() {
836
836
  __privateSet(this, _enabled, false);
837
837
  }
838
- }
839
- _name = new WeakMap();
840
- _color = new WeakMap();
841
- _enabled = new WeakMap();
842
- _Trace_instances = new WeakSet();
843
- autoConfig_fn = function() {
838
+ }, _name = new WeakMap(), _color = new WeakMap(), _enabled = new WeakMap(), _Trace_instances = new WeakSet(), autoConfig_fn = function() {
844
839
  if (typeof window === "undefined") return;
845
840
  const isLocal = window.location.hostname === "localhost" || window.location.hostname === "127.0.0.1" || window.location.hostname.startsWith("192.168.");
846
841
  if (isLocal) {
@@ -855,9 +850,9 @@ autoConfig_fn = function() {
855
850
  ""
856
851
  );
857
852
  }
858
- };
859
- const trace$1 = new Trace();
860
- if (typeof window !== "undefined") window.trace = trace$1;
853
+ }, _a);
854
+ const trace$2 = new Trace$1();
855
+ if (typeof window !== "undefined") window.trace = trace$2;
861
856
  class TaskDebouncer {
862
857
  constructor(delay = 50) {
863
858
  __privateAdd(this, _TaskDebouncer_instances);
@@ -899,6 +894,13 @@ flush_fn = function() {
899
894
  });
900
895
  __privateSet(this, _timer, null);
901
896
  };
897
+ class Trace extends trace$2.constructor {
898
+ constructor() {
899
+ super();
900
+ this.init("nine-util", "green");
901
+ }
902
+ }
903
+ const trace$1 = new Trace();
902
904
  class Loading {
903
905
  static show() {
904
906
  let overlay = document.getElementById("global-loading-overlay");
@@ -975,12 +977,12 @@ __privateAdd(_Fetch, _request, (method, url, data = {}, showLoading = true) => {
975
977
  });
976
978
  // 기존 post/get 메서드도 인자를 넘겨주도록 수정
977
979
  __publicField(_Fetch, "get", (url, data = {}, showLoading = true) => {
978
- var _a;
979
- return __privateGet(_a = _Fetch, _request).call(_a, "GET", url, data, showLoading);
980
+ var _a2;
981
+ return __privateGet(_a2 = _Fetch, _request).call(_a2, "GET", url, data, showLoading);
980
982
  });
981
983
  __publicField(_Fetch, "post", (url, data = {}, showLoading = true) => {
982
- var _a;
983
- return __privateGet(_a = _Fetch, _request).call(_a, "POST", url, data, showLoading);
984
+ var _a2;
985
+ return __privateGet(_a2 = _Fetch, _request).call(_a2, "POST", url, data, showLoading);
984
986
  });
985
987
  /**
986
988
  * 🚀 범용 청크 전송 (파라미터 이름까지 동적 설정)
@@ -1033,6 +1035,14 @@ __publicField(_Fetch, "postMultipart", async (url, rows = [], options = {}) => {
1033
1035
  });
1034
1036
  let Fetch = _Fetch;
1035
1037
  const api = Fetch;
1038
+ const safe = async (promise) => {
1039
+ try {
1040
+ const data = await promise;
1041
+ return [data, null];
1042
+ } catch (err) {
1043
+ return [null, err];
1044
+ }
1045
+ };
1036
1046
  class UxSplitter extends HTMLElement {
1037
1047
  constructor() {
1038
1048
  super();
@@ -1175,7 +1185,7 @@ class UxSplitter extends HTMLElement {
1175
1185
  const htmlTmpl = document.createElement("template");
1176
1186
  htmlTmpl.innerHTML = `
1177
1187
  <style>
1178
- @import "https://cdn.jsdelivr.net/npm/@nine-lab/nine-util@${"0.9.125"}/dist/css/nine-util.css";
1188
+ @import "https://cdn.jsdelivr.net/npm/@nine-lab/nine-util@${"0.9.127"}/dist/css/nine-util.css";
1179
1189
  ${this.cssPath ? `@import "${this.cssPath}";` : ""}
1180
1190
  </style>
1181
1191
  ${gripTmpl}
@@ -1226,8 +1236,9 @@ const utilInstance = new NineUtil();
1226
1236
  nine.alert = utilInstance.alert.bind(utilInstance);
1227
1237
  nine.confirm = utilInstance.confirm.bind(utilInstance);
1228
1238
  nine.prompt = utilInstance.prompt.bind(utilInstance);
1239
+ nine.safe = safe;
1229
1240
  nine.api = api;
1230
- nine.trace = trace$1;
1241
+ nine.trace = trace$2;
1231
1242
  nine.subscribeConfig = subscribeConfig;
1232
1243
  nine.config = config || {};
1233
1244
  if (typeof window !== "undefined") {
@@ -1237,7 +1248,7 @@ export {
1237
1248
  Fetch,
1238
1249
  NineUtil,
1239
1250
  TaskDebouncer,
1240
- Trace,
1251
+ Trace$1 as Trace,
1241
1252
  api,
1242
1253
  config,
1243
1254
  Loading as loading,
@@ -1247,6 +1258,6 @@ export {
1247
1258
  nineDialog,
1248
1259
  ninePromptPopup,
1249
1260
  subscribeConfig,
1250
- trace$1 as trace
1261
+ trace$2 as trace
1251
1262
  };
1252
1263
  //# sourceMappingURL=nine-util.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"nine-util.js","sources":["../src/core/Config.js","../src/ux/dialog/style.dialog.js","../src/ux/dialog/nineDialog.js","../src/ux/dialog/nineConfirm.js","../src/ux/dialog/ninePrompt.js","../src/ux/dialog/NineUtil.js","../src/core/Trace.js","../src/core/TaskDebouncer.js","../src/ux/Loading.js","../src/net/Fetch.js","../src/ux/UxSplitter.js","../src/index.js"],"sourcesContent":["// @nine-lab/nine-util/core/Config.js\r\n\r\nconst listeners = new Set();\r\n\r\n// 💡 [핵심] 전역 저장소를 단일화합니다.\r\n// window에 이미 있으면 그것을 쓰고, 없으면 초기값을 생성하여 등록합니다.\r\nconst _initialConfig = {\r\n\tux: { nativeOverride: false, theme: 'light' },\r\n\tboard: { readOnly: false },\r\n\tcssPath: \"\",\r\n\tdebug: false\r\n};\r\n\r\nif (typeof window !== 'undefined' && !window.__NINE_GLOBAL_CONFIG__) {\r\n\twindow.__NINE_GLOBAL_CONFIG__ = _initialConfig;\r\n}\r\n\r\n// 이제 모든 모듈의 _config는 동일한 window 객체 메모리를 가리킵니다.\r\nconst _config = typeof window !== 'undefined' ? window.__NINE_GLOBAL_CONFIG__ : _initialConfig;\r\n\r\nexport const subscribeConfig = (fn) => {\r\n\tlisteners.add(fn);\r\n\tfn('all', _config);\r\n\treturn () => listeners.delete(fn);\r\n};\r\n\r\n// Proxy 역시 전역 저장소인 _config를 조작합니다.\r\nexport const config = new Proxy(_config, {\r\n\tset(target, prop, value) {\r\n\t\ttarget[prop] = value;\r\n\t\tlisteners.forEach(fn => fn(prop, target));\r\n\t\treturn true;\r\n\t},\r\n\tget(target, prop) {\r\n\t\treturn target[prop];\r\n\t}\r\n});\r\n\r\nexport const nine = {\r\n\tconfig: config,\r\n\r\n\t// Getter에서 window.nine까지 확인할 필요도 없습니다.\r\n\t// 이미 config 자체가 전역 저장소(__NINE_GLOBAL_CONFIG__)를 바라보고 있기 때문입니다.\r\n\tget cssPath() {\r\n\t\treturn this.config.cssPath || \"\";\r\n\t},\r\n\r\n\tsetup(options = {}) {\r\n\t\tObject.entries(options).forEach(([key, value]) => {\r\n\t\t\t// 깊은 병합 지원\r\n\t\t\tif (typeof value === 'object' && value !== null && !Array.isArray(value)) {\r\n\t\t\t\tthis.config[key] = { ...this.config[key], ...value };\r\n\t\t\t} else {\r\n\t\t\t\tthis.config[key] = value;\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\t// 다른 모듈에서 window.nine으로 접근할 수 있도록 보장\r\n\t\tif (typeof window !== 'undefined') {\r\n\t\t\twindow.nine = window.nine || this;\r\n\t\t}\r\n\t}\r\n};","// nxDialog.styles.js\nexport const dialogStyles = `\n\tdialog::backdrop {\n\t\tbackground: rgba(0, 0, 0, 0.3);\n\t}\n\t\n\tdialog:modal {\n\t\tdisplay: flex;\n\t\tflex-direction: column;\n\t\tpadding: 0;\n\t\toverflow: hidden;\n\t\tborder: 1px solid darkgreen;\n\t\toutline: none;\n\t\tresize: both;\n\t\tbox-shadow: 0 0 4px 0 darkgreen;\n width: 500px;\n height: 150px;\n min-width: 330px;\n min-height: 60px;\n }\n \n \n \n \n\tdiv.head .rect1, div.head .rect2, div.head .rect3 {\n\t\tdisplay: none;\n\t\twidth: 50px;\n\t\theight: 100%;\n\t}\n\tdiv.head .rect1 {\n\t\tbackground-color: red;\n\t}\n\tdiv.head .rect2 {\n\t\tbackground-color: darkgreen;\n\t}\n\tdiv.head .rect3 {\n\t\tbackground-color: olive;\n\t}\n\t\n\tdiv.head {\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\t--height: 30px;\n\t\tbackground-color: darkgreen;\n\t\tpadding: 4px;\n\t\tcursor: move;\n\t}\n\tdiv.head:hover {\n\t\tfilter: brightness(110%);\n\t}\n\t\n\tdiv.head span {\n\t\tfont-size: 12px;\n\t\tposition: relative;\n\t}\n\t\n\tdiv.head span.title {\n\t\tcolor: #ddd;\n\t\tmargin-left: 4px;\n\t\tfont-weight: bold;\n\t}\n\t\n\tdiv.head span.sub-title {\n\t\tcolor: #ccc;\n\t\tmargin-left: 8px;\n\t\tfont-style: italic;\n\t}\n\t\n\tdiv.head form {\n\t\tmargin: 0;\n\t}\n\tdiv.head button {\n\t\tmargin-right: 4px;\n\t\tbackground-color: transparent;\n\t\tborder: none;\n\t\tcolor: #ccc;\n\t\tfont-size: x-small;\n\t}\n\tdiv.head button:hover {\n\t\tcursor: pointer;\n\t}\n\t\n\tdiv.contents {\n\t\tdisplay: flex;\n\t\twidth: 100%;\n\t\theight: 100%;\n\t\toverflow: hidden;\n\t}\n\tdiv.left {\n\t\tposition: relative;\n\t\twidth: 16px;\n\t\theight: 100%;\n\t\tbackground-color: #ddd;\n\t\tdisplay: none;\n\t}\n\t\n\tdiv.left span {\n\t\twriting-mode: vertical-rl;\n\t\t-moz-user-select: none;\n\t\t-webkit-user-select: none;\n\t\t-ms-user-select: none;\n\t\tuser-select: none;\n\t\tcolor: #ccc;\n\t\tfont-weight: 700;\n\t\twidth: 100%;\n\t\theight: 100%;\n\t\tmargin-left: 3px;\n\t\tmargin-top: 3px;\n\t}\n\tdiv.close2 {\n\t\tdisplay: none;\n\t\tposition: absolute;\n\t\tright: 0;\n\t\ttop: 3px;\n\t\tcursor: pointer;\n\t\tcolor: #666;\n\t}\n\tdiv.close2 svg:hover {\n\t\tcolor: #999;\n\t}\n\t\n\tdiv.body {\n\t\tdisplay: flex;\n\t\twidth: 100%;\n\t\theight: unset;\n\t\t--border: 3px solid #999;\n\t\t--border-top: none;\n\t\toverflow-x: hidden;\n\t\toverflow-y: auto;\n\t\tpadding: 10px;\n\t\tgap: 8px;\n\t\tflex-direction: column;\n\t}\n\t\n\t\n\t\n\t\n\tng-sphere.icon {\n\t\tmargin-left: 8px;\n\t}\n\t\n\t.buttons {\n\t\tdisplay: flex;\n\t\tposition: absolute;\n\t\tright: 4px;\n\t}\n\t\n\tng-sphere {\n\t\tposition: relative;\n\t\t--width: 16px;\n\t\t--height: 16px;\n\t\tcursor: pointer;\n\t\tmargin-right: 4px;\n\t\tdisplay: flex;\n\t}\n\tng-sphere:hover {\n\t\tfilter: brightness(90%);\n\t}\n\tng-sphere:active {\n\t\tfilter: brightness(80%);\n\t}\n\t\n\tng-sphere:hover::after {\n\t\tcontent: \"\";\n\t\tposition: absolute;\n\t\twidth: 100%;\n\t\theight: 100%;\n\t\tbackground-repeat: no-repeat;\n\t\tbackground-position: center;\n\t}\n\tng-sphere.apply:hover::after {\n\t\tbackground-size: 14px 14px;\n\t\tbackground-image: url('data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\"><polyline points=\"2.5,7 6,10 11,3\" style=\"fill:none;stroke:white;stroke-width:2px;\" /></svg>');\n\t}\n\t\n\tng-sphere.reset:hover::after {\n\t\tbackground-size: 12px 12px;\n\t\tbackground-image: url('data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\" style=\"fill:none;stroke:white;stroke-width:2px;\" focusable=\"false\" aria-hidden=\"true\"><path d=\"M10 5h5V0\"></path><path d=\"M15 8a6.957 6.957 0 0 1-7 7 6.957 6.957 0 0 1-7-7 6.957 6.957 0 0 1 7-7 6.87 6.87 0 0 1 6.3 4\"></path></svg>');\n\t}\n\t\n\tng-sphere.close:hover::after {\n\t\tbackground-size: 12px 12px;\n\t\tbackground-image: url('data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" style=\"fill:none;stroke:white;stroke-width:2px;\" focusable=\"false\" aria-hidden=\"true\" viewBox=\"0 0 16 16\"><path d=\"M2 2l12 12M14 2L2 14\"></path></svg>');\n\t}\n\t\n\t\n\tbutton {\n cursor: pointer;\n }\n \n .input-area {\n position: relative;\n height: 100%;\n --display: flex;\n textarea {\n width: 100%;\n height: 100%;\n min-height: 100px;\n padding: 8px;\n box-sizing: border-box;\n resize: none;\n border-radius: 2px;\n border-color: #ccc;\n }\n textarea:focus {\n border-color: green;\n outline: none; /* 브라우저 기본 파란색 테두리 제거 */\n }\n }\n \n .buttons-confirm {\n position: relative;\n display: flex;\n justify-content: flex-end;\n --bottom: 8px;\n --right: 8px;\n }\n \n \n .buttons-confirm button {\n height: 32px;\n margin-right: 8px;\n border: none;\n outline: none;\n width: 60px;\n -moz-user-select: none;\n -webkit-user-select: none;\n -ms-user-select: none;\n user-select: none;\n }\n .buttons-confirm button:hover {\n filter: brightness(90%);\n }\n .buttons-confirm button:active {\n color: #ccc;\n }\n \n button.ok {\n --display: none;\n background-color: darkgreen;\n color: white;\n }\n button.cancel {\n color: white;\n background-color: #6c757d;\n }\n \n \n \n div.msg {\n position: relative;\n height: 100%;\n font-size: 14px;\n color: #333;\n }\n \n .reset, .apply {\n display: none;\n }\n \n \n \n :host(.classic) dialog:modal {\n border: 1px solid #007bff;\n box-shadow: 0 0 4px 0 #007bff;\n }\n \n :host(.classic) div.head {\n background-color: #007bff;\n }\n :host(.classic) div.head:hover {\n filter: brightness(110%);\n }\n \n :host(.classic) div.head span {\n font-size: 12px;\n }\n \n :host(.classic) div.head span.title {\n color: #ddd;\n margin-left: 4px;\n font-weight: bold;\n }\n \n :host(.classic) div.head span.sub-title {\n color: #ccc;\n margin-left: 8px;\n font-style: italic;\n }\n :host(.classic) div.head button {\n margin-right: 4px;\n background-color: transparent;\n border: none;\n color: #ccc;\n font-size: x-small;\n }\n \n \n \n \n :host(.rgb) dialog:modal {\n border: none;\n box-shadow: unset;\n border-top: none;\n }\n \n :host(.rgb) div.left {\n display: block;\n background-color: #ddd;\n }\n :host(.rgb) div.left span {\n color: #ccc;\n }\n :host(.rgb) div.close2 {\n display: block;\n color: #666;\n }\n :host(.rgb) div.close2 svg:hover {\n color: #999;\n }\n :host(.rgb) div.head {\n height: 4px;\n background-color: #999;\n padding: 0;\n }\n :host(.rgb) div.contents {\n height: calc(100% - 4px);\n }\n \n :host(.rgb) div.head ng-sphere,\n :host(.rgb) div.head span,\n :host(.rgb) div.head .buttons {\n display: none;\n }\n \n :host(.rgb) div.head .rect1,\n :host(.rgb) div.head .rect2,\n :host(.rgb) div.head .rect3 {\n display: flex;\n }\n \n \n :host(.rgb) div.head:hover {\n filter: unset;\n }\n \n \n /* --- Animation Core --- */\n:host {\n --nx-duration: 0.4s;\n --nx-timing: cubic-bezier(0.34, 1.56, 0.64, 1);\n}\n\n/* 🎯 수정: 애니메이션 클래스가 붙은 경우에만 초기 opacity를 0으로 설정 */\n:host(.fade) dialog,\n:host(.zoom) dialog,\n:host(.moveUp) dialog,\n:host(.moveDown) dialog,\n:host(.moveLeft) dialog,\n:host(.moveRight) dialog,\n:host(.roadRunner) dialog {\n opacity: 0;\n}\n\n/* shake는 애니메이션 내부에서 opacity를 다루므로 제외하거나 별도 처리 */\n:host(.shake) dialog { \n opacity: 1; \n}\n\n/* 1. Fade (서서히 나타남) */\n:host(.fade) dialog { animation: nx-fade-in var(--nx-duration) forwards; }\n@keyframes nx-fade-in { from { opacity: 0; } to { opacity: 1; } }\n\n/* 2. Zoom (커지며 나타남) */\n:host(.zoom) dialog { animation: nx-zoom-in var(--nx-duration) var(--nx-timing) forwards; }\n@keyframes nx-zoom-in { from { opacity: 0; transform: scale(0.5); } to { opacity: 1; transform: scale(1); } }\n\n/* 3. Slide (상하좌우) */\n:host(.moveUp) dialog { animation: nx-move-up var(--nx-duration) var(--nx-timing) forwards; }\n:host(.moveDown) dialog { animation: nx-move-down var(--nx-duration) var(--nx-timing) forwards; }\n:host(.moveLeft) dialog { animation: nx-move-left var(--nx-duration) var(--nx-timing) forwards; }\n:host(.moveRight) dialog { animation: nx-move-right var(--nx-duration) var(--nx-timing) forwards; }\n\n@keyframes nx-move-up { from { opacity: 0; transform: translateY(100px); } to { opacity: 1; transform: translateY(0); } }\n@keyframes nx-move-down { from { opacity: 0; transform: translateY(-100px); } to { opacity: 1; transform: translateY(0); } }\n@keyframes nx-move-left { from { opacity: 0; transform: translateX(100px); } to { opacity: 1; transform: translateX(0); } }\n@keyframes nx-move-right { from { opacity: 0; transform: translateX(-100px); } to { opacity: 1; transform: translateY(0); } }\n\n/* 4. Shake (상하좌우 격렬한 진동 - 에러 인지용) */\n:host(.shake) dialog { \n animation: nx-heavy-shake 0.5s cubic-bezier(.36,.07,.19,.97) both;\n opacity: 1; \n}\n\n@keyframes nx-heavy-shake {\n 10%, 90% { transform: translate3d(-1px, -2px, 0); }\n 20%, 80% { transform: translate3d(2px, 4px, 0); }\n 30%, 50%, 70% { transform: translate3d(-6px, -6px, 0); }\n 40%, 60% { transform: translate3d(6px, 6px, 0); }\n}\n\n/* 5. Road Runner (등장: 왼쪽에서 탄력 있게 / 퇴장: 움츠렸다가 광속 탈출) */\n:host(.roadRunner) dialog { \n animation: roadRunnerIn 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards; \n}\n\n@keyframes roadRunnerIn {\n 0% { transform: translateX(-1500px) skewX(30deg); opacity: 1; }\n 70% { transform: translateX(30px) skewX(-10deg); opacity: 1; }\n 100% { transform: translateX(0) skewX(0deg); opacity: 1; }\n}\n\n/* --- Out Animations (닫힐 때) --- */\ndialog.out { pointer-events: none; }\n\n/* Road Runner 퇴장: 슥 움츠렸다가(Anticipation) 쌩~! */\n:host(.roadRunner) dialog.out { \n animation: roadRunnerOut 0.5s cubic-bezier(0.6, -0.28, 0.735, 0.045) forwards; \n}\n\n@keyframes roadRunnerOut {\n 0% { \n transform: translateX(0) scale(1) skewX(0deg); \n opacity: 1; \n }\n 30% { \n /* 예비 동작: 뒤로 살짝 갔다가 움츠러들기 */\n transform: translateX(50px) scaleX(1.2) scaleY(0.8) skewX(-20deg); \n opacity: 1; \n }\n 100% { \n /* 발사: 길게 늘어나며 광속 탈출 */\n transform: translateX(2000px) scaleX(4) scaleY(0.3) skewX(50deg); \n opacity: 0; \n filter: blur(10px); /* 👈 잔상 느낌 추가 */\n }\n}\n\n/* 일반 퇴장 (기본) */\ndialog.out { animation: nx-fade-out 0.3s forwards; }\n@keyframes nx-fade-out { from { opacity: 1; transform: scale(1); } to { opacity: 0; transform: scale(0.9); } }\n`;","import { dialogStyles } from './style.dialog.js';\n\nexport class nineDialog extends HTMLElement\n{\n\t#shift;\n\t#dialog;\n\n\n\tconstructor () {\n\t\tsuper();\n\t}\n\n\tconnectedCallback() {\n\n\t\tconst v = this.innerHTML;\n\t\tconst titleText = this.getAttribute(\"title\") || \"Details\";\n\n\t\ttrace.log(\"111111111\")\n\n\t\tthis.innerHTML = `\n\t\t\t<style>${dialogStyles}</style>\n\t\t\n\t\t\t<dialog>\n\t\t\t\t<div class=\"head\">\n\t\t\t\t\t<div class=\"rect1\"></div>\n\t\t\t\t\t<div class=\"rect2\"></div>\n\t\t\t\t\t<div class=\"rect3\"></div>\n\t\t\t\t\t<ng-sphere class=\"icon\" end-fill=\"#666\" size=\"8\"></ng-sphere>\n\t\t\t\t\t<span class=\"title\">${titleText}</span>\n\t\t\t\t\t<span class=\"sub-title\"></span>\n\t\t\t\t\t<div class=\"buttons\">\n\t\t\t\t\t\t<ng-sphere class=\"apply\" start-fill=\"#cc6\" end-fill=\"#660\" size=\"16\" title=\"apply\"></ng-sphere>\n\t\t\t\t\t\t<ng-sphere class=\"reset\" start-fill=\"#99f\" end-fill=\"#00f\" size=\"16\" title=\"reset\"></ng-sphere>\n\t\t\t\t\t\t<ng-sphere class=\"close\" start-fill=\"#f99\" end-fill=\"#f00\" size=\"16\" title=\"close\"></ng-sphere>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"contents\">\n\t\t\t\t\t<div class=\"left\">\n\t\t\t\t\t\t<span>가나다라마바사아자차카타파하가나다라마바사아자차카타파하가나다라마바사아자차카타파하가나다라마바사아자차카타파하가나다라마바사아자차카타파하가나다라마바사아자차카타파하가나다라마바사아자차카타파하가나다라마바사아자차카타파하</span>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"body\">\n\t\t\t\t\t\t${v}\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"close2\">\n\t\t\t\t\t\t<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" viewBox=\"0 0 16 16\">\n\t\t\t\t\t\t\t<path d=\"M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708\"/>\n\t\t\t\t\t\t</svg>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</dialog>\n\t\t`;\n\n\t\t//this.#owner = this.getRootNode().host.closest(\"nine-grid\");\n\n\t\t//$(\".title\", this).html(\"Details\");\n\n\t\tthis.#dialog = this.querySelector('dialog');\n\t\tthis.#init();\n\t};\n\n\tshowModal = () => {\n\t\tthis.#dialog.showModal();\n\t};\n\n\tclose = () => {\n\t\t// 이벤트 리스너 제거 (표준 방식은 핸들러 참조가 필요하지만,\n\t\t// 여기서는 요소가 사라지므로 메모리 관리를 위해 정리)\n\t\tthis.#dialog.close();\n\t\tthis.remove();\n\t};\n\n\t#init = () => {\n\t\tconst head = this.querySelector('.head');\n\n\t\t// 1. 모든 닫기 성격의 버튼 (.close, .close2, .cancel) 공통 처리\n\t\tthis.querySelectorAll('.close, .close2, .cancel').forEach(btn => {\n\t\t\tbtn.onclick = () => this.closeWithAnimation(null); // 취소/닫기는 null 리턴\n\t\t});\n\n\t\t// 2. 확인 버튼 (.ok) 처리\n\t\t// 확인 버튼은 텍스트 입력값 등 데이터가 필요하므로\n\t\t// 실제 데이터 추출은 각 팝업 클래스(prompt 등)에서 하되,\n\t\t// 닫기 애니메이션 실행은 여기서 담당하도록 가이드합니다.\n\t\tthis.querySelectorAll('.ok').forEach(btn => {\n\t\t\t// .ok 버튼의 로직은 각 팝업의 setupEvents에서 덮어쓰거나\n\t\t\t// 델리게이트 이벤트를 통해 처리합니다.\n\t\t});\n\n\t\t// 드래그 로직 생략...\n\t};\n\n\t// --- 드래그 로직 (Vanilla JS) ---\n\t#onMouseDown = e => {\n\t\tif (e.target.closest(\"buttons\")) return;\n\t\tif (e.button !== 0 || e.altKey || e.ctrlKey || e.shiftKey) return;\n\n\t\tconst rect = this.#dialog.getBoundingClientRect();\n\t\tthis.#shift = {\n\t\t\tx: e.clientX - rect.left,\n\t\t\ty: e.clientY - rect.top\n\t\t};\n\n\t\tconst onMouseMove = (ev) => {\n\t\t\tthis.#dialog.style.position = 'fixed';\n\t\t\tthis.#dialog.style.margin = '0';\n\t\t\tthis.#dialog.style.left = `${ev.clientX - this.#shift.x}px`;\n\t\t\tthis.#dialog.style.top = `${ev.clientY - this.#shift.y}px`;\n\t\t};\n\n\t\tconst onMouseUp = () => {\n\t\t\tdocument.removeEventListener('mousemove', onMouseMove);\n\t\t\tdocument.removeEventListener('mouseup', onMouseUp);\n\t\t};\n\n\t\tdocument.addEventListener('mousemove', onMouseMove);\n\t\tdocument.addEventListener('mouseup', onMouseUp);\n\t};\n\n\t#onTouchStart = e => {\n\t\tif (e.target.closest(\"buttons\")) return;\n\n\t\tconst rect = this.#dialog.getBoundingClientRect();\n\t\tconst touch = e.changedTouches[0];\n\t\tthis.#shift = {\n\t\t\tx: touch.pageX - rect.left,\n\t\t\ty: touch.pageY - rect.top\n\t\t};\n\n\t\tconst onTouchMove = (ev) => {\n\t\t\tconst t = ev.changedTouches[0];\n\t\t\tthis.#dialog.style.position = 'fixed';\n\t\t\tthis.#dialog.style.margin = '0';\n\t\t\tthis.#dialog.style.left = `${t.pageX - this.#shift.x}px`;\n\t\t\tthis.#dialog.style.top = `${t.pageY - this.#shift.y}px`;\n\t\t};\n\n\t\tconst onTouchEnd = () => {\n\t\t\tdocument.removeEventListener('touchmove', onTouchMove);\n\t\t\tdocument.removeEventListener('touchend', onTouchEnd);\n\t\t};\n\n\t\tdocument.addEventListener('touchmove', onTouchMove);\n\t\tdocument.addEventListener('touchend', onTouchEnd);\n\t};\n\n\tcloseWithAnimation(returnValue) {\n\t\tthis.#dialog.classList.add(\"out\"); // 퇴장 애니메이션 시작\n\n\t\t// 애니메이션(0.3s)이 끝난 후 제거 및 이벤트 발생\n\t\tsetTimeout(() => {\n\t\t\tthis.#dialog.close();\n\t\t\t// 부모(BasePopup)에게 작업 완료와 결과값을 알림\n\t\t\tthis.dispatchEvent(new CustomEvent('closed', { detail: returnValue }));\n\t\t\tthis.remove();\n\t\t}, 300);\n\t}\n}\n\n// BasePopup.js\nexport class BasePopup extends HTMLElement {\n\n\tconstructor() {\n\t\tsuper();\n\t\tthis.attachShadow({ mode: 'open' });\n\t}\n\n\tstatic async open(PopupClass, message, title, options, renderFn) {\n\t\t// 1. 설정 병합\n\t\tconst tagName = PopupClass.tagName.toLowerCase();\n\t\tconst config = {\n\t\t\t\"true-text\": \"확인\",\n\t\t\t\"false-text\": \"취소\",\n\t\t\tclass: \"classic\",\n\t\t\tanimation: \"fade\",\n\t\t\t...(window.nine?.config?.ux?.[tagName.replace('nine-', '').replace('-popup', '')] || {}),\n\t\t\t...options\n\t\t};\n\n\t\t// 2. 중복 제거 및 엘리먼트 생성\n\t\tdocument.querySelectorAll(tagName).forEach(el => el.remove());\n\t\tconst el = document.createElement(tagName);\n\t\tif (config.class) el.classList.add(config.class);\n\t\tif (config.animation) el.classList.add(config.animation);\n\t\tdocument.body.appendChild(el);\n\n\t\t// 3. 렌더링 (각 팝업의 UI 그리기)\n\t\trenderFn(el, message, config);\n\n\t\tconst dialogComp = el.shadowRoot.querySelector(\"nine-dialog\");\n\t\tif (title) dialogComp.setAttribute(\"title\", title);\n\n\t\treturn new Promise((resolve) => {\n\t\t\t// [중요] nine-dialog의 애니메이션이 끝난 후 던지는 이벤트를 수신\n\t\t\tdialogComp.addEventListener('closed', (e) => resolve(e.detail));\n\n\t\t\t// 각 팝업 클래스에서 버튼 클릭 시 dialogComp.closeWithAnimation(값)을\n\t\t\t// 호출하도록 이벤트를 바인딩해줌\n\t\t\tel.setupEvents(resolve, dialogComp);\n\n\t\t\tdialogComp.showModal();\n\t\t});\n\t}\n}\n\nif (!customElements.get('nine-dialog')) {\n\tcustomElements.define(\"nine-dialog\", nineDialog);\n}\n","import { nine } from \"../../core/Config.js\"; // 설정 참조용\nimport { BasePopup } from \"./nineDialog.js\";\n\nexport class nineConfirmPopup extends BasePopup {\n\tstatic tagName = 'nine-confirm-popup';\n\n\tconstructor() {\n\t\tsuper();\n\t}\n\n\trender(message, config) {\n\t\tthis.shadowRoot.innerHTML = `\n <nine-dialog>\n <div class=\"msg\">${message.replace(/\\n/g, \"<br/>\")}</div>\n <div class=\"buttons-confirm\">\n <button class=\"cancel\">${config[\"false-text\"]}</button>\n <button class=\"ok\">${config[\"true-text\"]}</button>\n </div>\n </nine-dialog>`;\n\t}\n\n\tsetupEvents(resolve, dialogComp) {\n\t\tthis.shadowRoot.querySelector(\".ok\").onclick = () => dialogComp.closeWithAnimation(true);\n\t\t// 취소는 nine-dialog 내부 기본 로직(closeWithAnimation(null))이 처리함\n\t}\n\n\tstatic confirm = (m, t, o) => BasePopup.open(nineConfirmPopup, m, t, o, (el, msg, conf) => el.render(msg, conf));\n}\n\n// --- 3. ALERT (단순 알림) ---\nexport class nineAlertPopup extends BasePopup {\n\tstatic tagName = 'nine-alert-popup';\n\n\tconstructor() {\n\t\tsuper();\n\t}\n\n\trender(message, config) {\n\t\tthis.shadowRoot.innerHTML = `\n <nine-dialog>\n <div class=\"msg\">${message.replace(/\\n/g, \"<br/>\")}</div>\n <div class=\"buttons-confirm\">\n <button class=\"cancel\">확인</button>\n </div>\n </nine-dialog>`;\n\t}\n\n\tsetupEvents(resolve, dialogComp) {\n\t\t// 얼럿은 취소 버튼 하나만 두거나, 확인 버튼이 cancel 역할을 수행하게 함\n\t}\n\n\tstatic alert = (m, t, o) => BasePopup.open(nineAlertPopup, m, t, o, (el, msg, conf) => el.render(msg, conf));\n}\n\n// Custom Element 등록\nif (!customElements.get('nine-confirm-popup')) customElements.define('nine-confirm-popup', nineConfirmPopup);\nif (!customElements.get('nine-alert-popup')) customElements.define(\"nine-alert-popup\", nineAlertPopup);","import { nine } from \"../../core/Config.js\";\nimport { BasePopup } from \"./nineDialog.js\";\n\n/**\n *\n */\nexport class ninePromptPopup extends BasePopup {\n\tstatic tagName = 'nine-prompt-popup';\n\n\tconstructor() {\n\t\tsuper();\n\t}\n\n\trender(message, config) {\n\n\t\ttrace.log(this);\n\t\ttrace.log(this.shadowRoot);\n\n\t\tthis.shadowRoot.innerHTML = `\n\t\t\t<style>\n\t\t\t\tdialog {\n\t\t\t\t\theight: 300px !important;\n\t\t\t\t}\n\t\t\t\t.msg {\n\t\t\t\t\theight: unset !important;\n\t\t\t\t}\n\t\t\t</style>\n\t\t\t\n <nine-dialog>\n <div class=\"msg\">${message.replace(/\\n/g, \"<br/>\")}</div>\n <div class=\"input-area\">\n <textarea placeholder=\"내용을 입력하세요...\"></textarea>\n </div>\n <div class=\"buttons-confirm\">\n <button class=\"cancel\">${config[\"false-text\"]}</button>\n <button class=\"ok\">${config[\"true-text\"]}</button>\n </div>\n </nine-dialog>`;\n\t}\n\n\tsetupEvents(resolve, dialogComp) {\n\t\tconst textarea = this.shadowRoot.querySelector(\"textarea\");\n\t\tconst okBtn = this.shadowRoot.querySelector(\".ok\");\n\n\t\t// 확인 버튼 클릭 시 textarea 값을 가지고 애니메이션 닫기\n\t\tokBtn.onclick = () => dialogComp.closeWithAnimation(textarea.value);\n\n\t\t// 렌더링 후 포커스\n\t\trequestAnimationFrame(() => textarea.focus());\n\t}\n\n\tstatic prompt = (m, t, o) => BasePopup.open(ninePromptPopup, m, t, o, (el, msg, conf) => el.render(msg, conf));\n}\n\nif (!customElements.get('nine-prompt-popup')) {\n\tcustomElements.define('nine-prompt-popup', ninePromptPopup);\n}","// src/core/NineUtil.js\r\nimport { nineAlertPopup, nineConfirmPopup } from './nineConfirm.js';\r\nimport { ninePromptPopup } from \"./ninePrompt.js\";\r\n\r\nexport class NineUtil {\r\n\t// static 필드는 클래스 자체에 저장됨\r\n\tstatic cssPath = \"\";\r\n\r\n\t/**\r\n\t * 팝업 준비 로직 (Private 메서드)\r\n\t */\r\n\t#prepare(type, message, title, defaultClass) {\r\n\r\n\t\tconst options = { class: defaultClass, animation: 'fade' };\r\n\t\t//const popup = type === 'alert' ? nineAlertPopup : (type === 'confirm' ? nineConfirmPopup : ninePromptPopup);\r\n\t\tlet isExecuted = false;\r\n\r\n\t\tconst popupMap = {\r\n\t\t\talert: nineAlertPopup,\r\n\t\t\tconfirm: nineConfirmPopup,\r\n\t\t\tprompt: ninePromptPopup\r\n\t\t};\r\n\r\n\t\tconst popup = popupMap[type];\r\n\r\n\t\tconst runner = {\r\n\t\t\trgb: () => { options.class = 'rgb'; return runner; },\r\n\t\t\tclassic: () => { options.class = 'classic'; return runner; },\r\n\t\t\tshake: () => { options.animation = 'shake'; return runner; },\r\n\t\t\trun: () => { options.animation = 'roadRunner'; return runner; },\r\n\t\t\tzoom: () => { options.animation = 'zoom'; return runner; },\r\n\r\n\t\t\tthen: (resolve, reject) => {\r\n\t\t\t\tisExecuted = true;\r\n\t\t\t\treturn popup[type](message, title, options).then(resolve, reject);\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\t// Microtask: 동기 체이닝이 모두 끝난 후 실행\r\n\t\tPromise.resolve().then(() => {\r\n\t\t\tif (!isExecuted) {\r\n\t\t\t\tisExecuted = true;\r\n\t\t\t\tpopup[type](message, title, options);\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\treturn runner;\r\n\t}\r\n\r\n\talert(message, title = \"Alert\") {\r\n\t\treturn this.#prepare('alert', message, title, 'classic');\r\n\t}\r\n\r\n\tconfirm(message, title = \"Confirm\") {\r\n\t\treturn this.#prepare('confirm', message, title, 'classic');\r\n\t}\r\n\r\n\tprompt(message, title = \"Prompt\") {\r\n\t\treturn this.#prepare('prompt', message, title, 'classic');\r\n\t}\r\n}","export class Trace {\r\n\t#name;\r\n\t#color;\r\n\t#enabled = true;\r\n\r\n\tconstructor(name = null, color = \"green\") {\r\n\t\tthis.#name = name;\r\n\t\tthis.#color = color;\r\n\t\tthis.#autoConfig();\r\n\t\t/**\r\n\t\t// 1. 쪼개진 인스턴스들을 하나로 합치는 '본드' 역할 (이게 핵심!)\r\n\t\tif (typeof window !== 'undefined' && window.__NINE_TRACE__) {\r\n\t\t\treturn window.__NINE_TRACE__;\r\n\t\t}\r\n\t\tthis.#autoConfig();\r\n\t\tif (typeof window !== 'undefined') window.__NINE_TRACE__ = this;\r\n\t\t\t*/\r\n\t}\r\n\r\n\t#autoConfig() {\r\n\t\tif (typeof window === 'undefined') return;\r\n\t\tconst isLocal = window.location.hostname === 'localhost' ||\r\n\t\t\twindow.location.hostname === '127.0.0.1' ||\r\n\t\t\twindow.location.hostname.startsWith('192.168.');\r\n\r\n\t\tif (isLocal) {\r\n\t\t\tthis.enable();\r\n\t\t} else {\r\n\t\t\tthis.disable();\r\n\t\t\tconsole.log(\r\n\t\t\t\t`%c[${this.#name || 'Trace'}]%c 운영 모드: 로그 비활성화. %ctrace.enable()%c 로 활성화 가능`,\r\n\t\t\t\t\"color: #4CAF50; font-weight: bold;\", \"\",\r\n\t\t\t\t\"background: #333; color: yellow; padding: 2px 5px;\", \"\"\r\n\t\t\t);\r\n\t\t}\r\n\t}\r\n\r\n\t// 🟢 빼먹었던 init 메서드 다시 추가!\r\n\tinitBAK(name, color = \"green\") {\r\n\t\tthis.#name = name;\r\n\t\tthis.#color = color;\r\n\t}\r\n\r\n\tinit(name, color = \"green\") {\r\n\t\t//const style = `color: ${color}; font-weight: bold;`;\r\n\t\tthis.#name = name;\r\n\t\tthis.#color = color;\r\n\r\n\t\treturn this;\r\n\t\t/**\r\n\t\tconsole.log(name, color);\r\n\t\treturn {\r\n\t\t\tlog: console.log.bind(console, `%c[${name}]`, style),\r\n\t\t\twarn: console.warn.bind(console, `%c[${name}]`, \"color: cyan; font-weight: bold;\"),\r\n\t\t\terror: console.error.bind(console, `%c[${name}]`, \"color: red; font-weight: bold;\")\r\n\t\t}; */\r\n\t}\r\n\r\n\t//get log() { return console.log.bind(console); }\r\n\r\n\t// 🔴 핵심: 소스 위치를 호출부로 찍어주는 Getter 로직\r\n\tget log() {\r\n\t\t//if (!this.#enabled) return () => {};\r\n\t\tconst style = `color: ${this.#color}; font-weight: bold;`;\r\n\t\t// 이름이 있으면 프리픽스를 붙이고, 없으면 그냥 로그를 바인딩합니다.\r\n\t\treturn (this.#name)\r\n\t\t\t? console.log.bind(console, `%c[${this.#name}]`, style)\r\n\t\t\t: console.log.bind(console);\r\n\t}\r\n\r\n\tget warn() {\r\n\t\tif (!this.#enabled) return () => {};\r\n\t\treturn (this.#name)\r\n\t\t\t? console.warn.bind(console, `%c[${this.#name}]`, \"color: cyan; font-weight: bold;\")\r\n\t\t\t: console.warn.bind(console);\r\n\t}\r\n\r\n\tget error() {\r\n\t\t// 에러는 enabled 상태와 상관없이 찍고 싶으시면 if 체크를 주석 처리하세요.\r\n\t\t// if (!this.#enabled) return () => {};\r\n\t\treturn (this.#name)\r\n\t\t\t? console.error.bind(console, `%c[${this.#name}]`, \"color: red; font-weight: bold;\")\r\n\t\t\t: console.error.bind(console);\r\n\t}\r\n\r\n\tenable() { this.#enabled = true; }\r\n\tdisable() { this.#enabled = false; }\r\n}\r\n\r\nexport const trace = new Trace();\r\nif (typeof window !== 'undefined') window.trace = trace;","export class TaskDebouncer {\r\n\t#timer = null;\r\n\t#queue = [];\r\n\t#delay;\r\n\r\n\tconstructor(delay = 50) {\r\n\t\tthis.#delay = delay;\r\n\t}\r\n\r\n\t/**\r\n\t * @param {Function} func - 실행할 함수\r\n\t * @param {...any} args - 함수에 전달할 임의의 파라미터들\r\n\t */\r\n\texec(func, ...args) {\r\n\t\t// 1. 어떤 함수와 어떤 인자들이 들어왔는지 큐에 저장\r\n\t\tthis.#queue.push({ func, args });\r\n\r\n\t\t// 2. 디바운스 타이머 설정\r\n\t\tif (this.#timer) clearTimeout(this.#timer);\r\n\r\n\t\tthis.#timer = setTimeout(() => this.#flush(), this.#delay);\r\n\t}\r\n\r\n\texecWithKey(key, func, ...args) {\r\n\t\t// 1. 같은 키(예: 'resize')가 들어오면 이전 큐에서 해당 키 삭제 (중복 제거)\r\n\t\tthis.#queue = this.#queue.filter(task => task.key !== key);\r\n\r\n\t\t// 2. 새로운 태스크 추가\r\n\t\tthis.#queue.push({ key, func, args });\r\n\r\n\t\tif (this.#timer) clearTimeout(this.#timer);\r\n\t\tthis.#timer = setTimeout(() => this.#flush(), this.#delay);\r\n\t}\r\n\r\n\t#flush() {\r\n\t\tif (this.#queue.length === 0) return;\r\n\r\n\t\t// 3. 현재까지 쌓인 큐를 쏙 빼옴\r\n\t\tconst tasks = this.#queue.splice(0, this.#queue.length);\r\n\t\tconst seen = new Set();\r\n\r\n\t\ttasks.forEach(task => {\r\n\t\t\t// 4. 핵심: 함수 이름과 인자들을 문자열로 합쳐서 유니크 키 생성\r\n\t\t\t// JSON.stringify를 통해 [1, {a:1}] 같은 파라미터도 문자열로 비교 가능\r\n\t\t\tconst identifier = `${task.func.name}_${JSON.stringify(task.args)}`;\r\n\r\n\t\t\tif (!seen.has(identifier)) {\r\n\t\t\t\t// 5. 중복이 아닐 때만 원래 인자들(...args) 그대로 실행\r\n\t\t\t\ttask.func(...task.args);\r\n\t\t\t\tseen.add(identifier);\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tthis.#timer = null;\r\n\t}\r\n}","export class Loading {\n\tstatic show() {\n\t\tlet overlay = document.getElementById(\"global-loading-overlay\");\n\t\tif (!overlay) {\n\t\t\toverlay = document.createElement(\"div\");\n\t\t\toverlay.id = \"global-loading-overlay\";\n\t\t\toverlay.style.cssText = `\n position: fixed; inset: 0; z-index: 9999;\n background: rgba(0, 0, 0, 0.4); display: flex; \n justify-content: center; align-items: center;\n backdrop-filter: blur(2px);\n `;\n\t\t\toverlay.innerHTML = `<div class=\"loading-spinner\"></div>`;\n\t\t\tdocument.body.appendChild(overlay);\n\n\t\t\tif (!document.getElementById(\"nine-util-style\")) {\n\t\t\t\tconst style = document.createElement(\"style\");\n\t\t\t\tstyle.id = \"nine-util-style\";\n\t\t\t\tstyle.innerHTML = `\n .loading-spinner {\n width: 48px; height: 48px;\n border: 5px solid rgba(255, 255, 255, 0.3);\n border-top-color: white; border-radius: 50%;\n animation: nine-spin 1s linear infinite;\n }\n @keyframes nine-spin { to { transform: rotate(360deg); } }\n `;\n\t\t\t\tdocument.head.appendChild(style);\n\t\t\t}\n\t\t}\n\t\toverlay.style.display = \"flex\";\n\t}\n\n\tstatic hide() {\n\t\tconst overlay = document.getElementById(\"global-loading-overlay\");\n\t\tif (overlay) overlay.style.display = \"none\";\n\t}\n}","import { Loading } from \"../ux/Loading.js\";\nimport { trace } from \"../core/Trace.js\";\n\nexport class Fetch {\n\tstatic BASE_URL = window.__API_BASE_URL__ || \"\";\n\n\tstatic #request = (method, url, data = {}, showLoading = true) => {\n\t\tconst finalUrl = url.startsWith('http') ? url : `${this.BASE_URL}${url}`;\n\n\t\tif (showLoading) {\n\t\t\tLoading.show();\n\t\t}\n\n\t\t// 1. 기본 헤더 설정\n\t\tconst headers = {};\n\n\t\t// 🔴 핵심: 데이터가 FormData가 아닐 때만 JSON 헤더를 추가합니다.\n\t\tif (!(data instanceof FormData)) {\n\t\t\theaders[\"Content-Type\"] = \"application/json\";\n\t\t}\n\n\t\tconst options = {\n\t\t\tmethod,\n\t\t\theaders\n\t\t};\n\n\t\tlet targetUrl = finalUrl;\n\t\tif (method === \"GET\") {\n\t\t\ttargetUrl += `?${new URLSearchParams(data)}`;\n\t\t} else {\n\t\t\t// 🔴 핵심: FormData는 그대로 body에 넣고, 일반 객체는 JSON.stringify 처리합니다.\n\t\t\toptions.body = data instanceof FormData ? data : JSON.stringify(data);\n\t\t}\n\n\t\treturn fetch(targetUrl, options)\n\t\t\t.then(async res => {\n\t\t\t\tif (!res.ok) {\n\t\t\t\t\tconst text = await res.text();\n\t\t\t\t\tthrow new Error(`API 오류 (${res.status}): ${text}`);\n\t\t\t\t}\n\t\t\t\treturn res.json();\n\t\t\t})\n\t\t\t.catch(err => {\n\t\t\t\ttrace.error(`[IdeFetch.${method.toLowerCase()}] ${finalUrl} 실패:`, err);\n\t\t\t\tthrow err;\n\t\t\t})\n\t\t\t.finally(() => {\n\t\t\t\tif (showLoading) {\n\t\t\t\t\tLoading.hide();\n\t\t\t\t}\n\t\t\t});\n\t};\n\n\t// 기존 post/get 메서드도 인자를 넘겨주도록 수정\n\tstatic get = (url, data = {}, showLoading = true) => this.#request(\"GET\", url, data, showLoading);\n\tstatic post = (url, data = {}, showLoading = true) => this.#request(\"POST\", url, data, showLoading);\n\n\t/**\n\t * 🚀 범용 청크 전송 (파라미터 이름까지 동적 설정)\n\t * @param {string} url - API 주소\n\t * @param {Array} rows - 데이터 배열\n\t * @param {object} options - 상세 옵션\n\t * - fileKey: 객체 내 파일 속성명 (기본: 'fileContents')\n\t * - filePartName: 서버에서 받을 파일 파트명 (기본: 'files')\n\t * - jsonPartName: 서버에서 받을 JSON 파트명 (기본: 'dataList')\n\t * - chunkSize: 분할 단위 (기본: 10)\n\t */\n\tstatic postMultipart = async (url, rows = [], options = {}) => {\n\t\tconst {\n\t\t\tfileKey = 'fileContents',\n\t\t\tfilePartName = 'files',\n\t\t\tjsonPartName = 'dataList',\n\t\t\tchunkSize = 10\n\t\t} = options;\n\n\t\t// 1. 시작 전 로딩바 띄우기\n\t\tLoading.show();\n\n\t\tlet totalCount = 0;\n\t\tlet lastResponse = null;\n\n\t\t// 🔴 2. 전체 루프를 Promise 체인처럼 관리 (내부는 await 유지)\n\t\treturn (async () => {\n\t\t\tfor (let i = 0; i < rows.length; i += chunkSize) {\n\t\t\t\tconst formData = new FormData();\n\t\t\t\tconst chunk = rows.slice(i, i + chunkSize);\n\t\t\t\tconst rowDataList = [];\n\n\t\t\t\tchunk.forEach((row) => {\n\t\t\t\t\tconst { [fileKey]: fileObj, _fileObj, ...rest } = row;\n\t\t\t\t\trowDataList.push(rest);\n\t\t\t\t\tif (fileObj instanceof File) {\n\t\t\t\t\t\tformData.append(filePartName, fileObj);\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tconst jsonBlob = new Blob([JSON.stringify(rowDataList)], { type: 'application/json' });\n\t\t\t\tformData.append(jsonPartName, jsonBlob);\n\n\t\t\t\t// showLoading = false로 내부 호출\n\t\t\t\tlastResponse = await this.post(url, formData, false);\n\n\t\t\t\tif (lastResponse && (lastResponse.success || lastResponse.status === 'OK')) {\n\t\t\t\t\ttotalCount += chunk.length;\n\t\t\t\t} else {\n\t\t\t\t\tthrow new Error(`청크 전송 실패: ${i}번째 섹션`);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn { ...lastResponse, success: true, totalCount };\n\t\t})()\n\t\t\t.catch(err => {\n\t\t\t\ttrace.error(\"[postChunk] Error:\", err);\n\t\t\t\tthrow err;\n\t\t\t})\n\t\t\t.finally(() => {\n\t\t\t\t// 🔴 3. 성공하든 실패하든 여기서 깔끔하게 닫기!\n\t\t\t\tLoading.hide();\n\t\t\t});\n\t};\n}\n\nexport const api = Fetch;","import { NineUtil } from \"./dialog/NineUtil.js\";\r\nimport { trace } from \"../core/Trace.js\";\r\n\r\nclass UxSplitter extends HTMLElement {\r\n\r\n\t#mode;\r\n\r\n\tconstructor() {\r\n\t\tsuper();\r\n\t\tthis.attachShadow({ mode: \"open\" });\r\n\t}\r\n\r\n\tconnectedCallback() {\r\n\r\n\t\tthis.#init();\r\n\t}\r\n\r\n\t#detectMode = (el) => {\r\n\t\tconst prev = el.previousElementSibling;\r\n\t\tconst next = el.nextElementSibling;\r\n\t\tif (!prev || !next) {\r\n\t\t\tthis.#mode = this.classList.contains('h') ? \"h\" : \"v\";\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst prevRect = prev.getBoundingClientRect();\r\n\t\tconst nextRect = next.getBoundingClientRect();\r\n\r\n\t\tif (this.classList.contains('h')) {\r\n\t\t\tthis.#mode = \"h\";\r\n\t\t} else if (this.classList.contains('v')) {\r\n\t\t\tthis.#mode = \"v\";\r\n\t\t} else {\r\n\t\t\tthis.#mode = (Math.abs(prevRect.top - nextRect.top) < 5) ? \"h\" : \"v\";\r\n\t\t}\r\n\t};\r\n\r\n\t#startDrag = (e) => {\r\n\t\te.preventDefault();\r\n\t\te.stopPropagation();\r\n\r\n\t\tconst splitterRect = this.getBoundingClientRect();\r\n\t\tconst isHorizontal = this.#mode === \"h\";\r\n\r\n\t\t// 마우스 포인터와 스플리터 시작점 사이의 거리\r\n\t\tconst clickOffset = isHorizontal\r\n\t\t\t? e.clientX - splitterRect.left\r\n\t\t\t: e.clientY - splitterRect.top;\r\n\r\n\t\tconst dragBar = document.createElement(\"div\");\r\n\t\tdragBar.className = `nx-splitter-drag-bar-${this.#mode}`;\r\n\r\n\t\tObject.assign(dragBar.style, {\r\n\t\t\tposition: \"absolute\",\r\n\t\t\tzIndex: \"999\",\r\n\t\t\tbackground: \"#666\",\r\n\t\t\topacity: \"0.6\",\r\n\t\t\tpointerEvents: \"none\"\r\n\t\t});\r\n\r\n\t\tconst root = this.getRootNode({ composed: true });\r\n\t\tconst parent = root instanceof ShadowRoot ? root.host : this.parentElement;\r\n\t\tconst prev = this.previousElementSibling;\r\n\t\tconst next = this.nextElementSibling;\r\n\r\n\t\tif (!parent || !prev || !next) {\r\n\t\t\ttrace.warn(\"Spliter's parent or siblings not found.\");\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t(parent.shadowRoot || parent).appendChild(dragBar);\r\n\t\tconst dragBarOffsetParentRect = dragBar.offsetParent.getBoundingClientRect();\r\n\r\n\t\tconst prevRect = prev.getBoundingClientRect();\r\n\t\tconst nextRect = next.getBoundingClientRect();\r\n\r\n\t\t// 드래그 바의 초기 위치와 크기 설정\r\n\t\tconst initialSplitterPosInParent = (isHorizontal\r\n\t\t\t? splitterRect.left - dragBarOffsetParentRect.left\r\n\t\t\t: splitterRect.top - dragBarOffsetParentRect.top) + clickOffset;\r\n\r\n\t\tif (isHorizontal) {\r\n\t\t\tdragBar.style.top = \"0\";\r\n\t\t\tdragBar.style.left = `${initialSplitterPosInParent}px`;\r\n\t\t\tdragBar.style.width = \"2px\";\r\n\t\t\tdragBar.style.height = \"100%\";\r\n\t\t} else {\r\n\t\t\tdragBar.style.left = \"0\";\r\n\t\t\tdragBar.style.top = `${initialSplitterPosInParent}px`;\r\n\t\t\tdragBar.style.height = \"2px\";\r\n\t\t\tdragBar.style.width = \"100%\";\r\n\t\t}\r\n\r\n\t\tdragBar.style.mixBlendMode = \"difference\";\r\n\t\tdragBar.style.zIndex = \"99999\";\r\n\r\n\t\tconst minLimit = isHorizontal\r\n\t\t\t? prevRect.left - dragBarOffsetParentRect.left\r\n\t\t\t: prevRect.top - dragBarOffsetParentRect.top;\r\n\t\tconst maxLimit = isHorizontal\r\n\t\t\t? nextRect.right - dragBarOffsetParentRect.left - splitterRect.width\r\n\t\t\t: nextRect.bottom - dragBarOffsetParentRect.top - splitterRect.height;\r\n\r\n\t\tconst onMove = moveEvent => {\r\n\t\t\tconst clientPos = isHorizontal ? moveEvent.clientX : moveEvent.clientY;\r\n\t\t\tconst currentPosInParent = isHorizontal\r\n\t\t\t\t? clientPos - dragBarOffsetParentRect.left\r\n\t\t\t\t: clientPos - dragBarOffsetParentRect.top;\r\n\r\n\t\t\tconst clampedPos = Math.max(minLimit, Math.min(currentPosInParent, maxLimit));\r\n\r\n\t\t\tif (isHorizontal) {\r\n\t\t\t\tdragBar.style.left = `${clampedPos}px`;\r\n\t\t\t} else {\r\n\t\t\t\tdragBar.style.top = `${clampedPos}px`;\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\tconst onUp = () => {\r\n\t\t\twindow.removeEventListener(\"mousemove\", onMove);\r\n\t\t\twindow.removeEventListener(\"mouseup\", onUp);\r\n\t\t\tdragBar.remove();\r\n\r\n\t\t\tconst allChildren = Array.from(parent.children);\r\n\t\t\tconst allPanels = allChildren.filter(el => el.tagName.toLowerCase() !== 'nx-splitter');\r\n\r\n\t\t\t// ⭐⭐ gap 크기 계산 ⭐⭐\r\n\t\t\tconst style = window.getComputedStyle(parent);\r\n\t\t\tconst gapValue = isHorizontal ? style.getPropertyValue('column-gap') : style.getPropertyValue('row-gap');\r\n\t\t\tconst gapSize = parseFloat(gapValue) || 0;\r\n\t\t\tconst gapCount = allChildren.length > 1 ? allChildren.length - 1 : 0;\r\n\t\t\tconst totalGapSize = gapCount * gapSize;\r\n\r\n\t\t\tconst finalDragBarPos = isHorizontal ? parseFloat(dragBar.style.left) : parseFloat(dragBar.style.top);\r\n\t\t\tconst dragOffset = finalDragBarPos - initialSplitterPosInParent;\r\n\r\n\t\t\tconst prevSize = isHorizontal ? prev.getBoundingClientRect().width : prev.getBoundingClientRect().height;\r\n\t\t\tconst nextSize = isHorizontal ? next.getBoundingClientRect().width : next.getBoundingClientRect().height;\r\n\r\n\t\t\tlet newPrevSize = prevSize + dragOffset;\r\n\t\t\tlet newNextSize = nextSize - dragOffset;\r\n\r\n\t\t\t// 패널 크기가 음수가 되지 않도록 제한하고, 다른 패널에 차이를 보정\r\n\t\t\tif (newPrevSize < 0) {\r\n\t\t\t\tnewNextSize += newPrevSize;\r\n\t\t\t\tnewPrevSize = 0;\r\n\t\t\t}\r\n\t\t\tif (newNextSize < 0) {\r\n\t\t\t\tnewPrevSize += newNextSize;\r\n\t\t\t\tnewNextSize = 0;\r\n\t\t\t}\r\n\r\n\t\t\tconst initialSizes = allPanels.map(panel => isHorizontal ? panel.getBoundingClientRect().width : panel.getBoundingClientRect().height);\r\n\r\n\t\t\tconst totalSplitterSize = allChildren.reduce((sum, child) => {\r\n\t\t\t\tif (child.tagName.toLowerCase() === 'nx-splitter') {\r\n\t\t\t\t\treturn sum + (isHorizontal ? child.getBoundingClientRect().width : child.getBoundingClientRect().height);\r\n\t\t\t\t}\r\n\t\t\t\treturn sum;\r\n\t\t\t}, 0);\r\n\r\n\t\t\tconst totalContainerSize = (isHorizontal ? parent.getBoundingClientRect().width : parent.getBoundingClientRect().height);\r\n\t\t\tconst totalFlexSpace = totalContainerSize - totalSplitterSize - totalGapSize;\r\n\r\n\t\t\tlet flexSum = 0;\r\n\t\t\tallPanels.forEach((panel, index) => {\r\n\t\t\t\tlet newSize;\r\n\t\t\t\tif (panel === prev) {\r\n\t\t\t\t\tnewSize = newPrevSize;\r\n\t\t\t\t} else if (panel === next) {\r\n\t\t\t\t\tnewSize = newNextSize;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tnewSize = initialSizes[index];\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst newFlexBasis = newSize / totalFlexSpace;\r\n\t\t\t\t//panel.style.flex = `${newFlexBasis} ${newFlexBasis} 0`;\r\n\r\n\t\t\t\ttrace.log(panel);\r\n\r\n\t\t\t\tif (panel.classList.contains('sidebar')) {\r\n\t\t\t\t\t// 드래그가 끝난 시점의 newSize(px)를 그대로 고정값으로 할당\r\n\t\t\t\t\t// 이렇게 하면 비율(%)이 아니라 딱 그 픽셀만큼만 자리를 차지하게 됩니다.\r\n\t\t\t\t\tpanel.style.flex = `0 0 ${newSize}px`;\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// 나머지 메인 보드 같은 유연한 패널은 비율(%)로 처리\r\n\t\t\t\t\t//const newFlexBasis = newSize / totalFlexSpace;\r\n\t\t\t\t\tpanel.style.flex = `${newFlexBasis} ${newFlexBasis} 0`;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tflexSum += newFlexBasis;\r\n\t\t\t});\r\n\r\n\t\t\ttrace.log(`dragOffset: ${dragOffset}`);\r\n\t\t\ttrace.log(`Calculated FlexSum: ${flexSum}`);\r\n\t\t};\r\n\r\n\t\twindow.addEventListener(\"mousemove\", onMove);\r\n\t\twindow.addEventListener(\"mouseup\", onUp);\r\n\t};\r\n\r\n\tget cssPath() {\r\n\t\treturn this.getAttribute(\"css-path\") || NineUtil.cssPath;\r\n\t}\r\n\r\n\t#init = () => {\r\n\t\tthis.#detectMode(this);\r\n\t\tthis.classList.add(this.#mode);\r\n\r\n\t\tconst contents = this.innerHTML.trim();\r\n\t\t//const gripClass = `grip-${this.#mode}`;\r\n\t\tconst gripTmpl = (contents === \"\") ? `<div class=\"grip\"></div>` : `<div class=\"grip\"></div><div class=\"inner-container\">${contents}</div><div class=\"grip\"></div>`;\r\n\r\n\t\tthis.innerHTML = \"\";\r\n\t\tconst htmlTmpl = document.createElement(\"template\");\r\n\t\thtmlTmpl.innerHTML = `\r\n\t\t\t<style>\r\n\t\t\t\t@import \"https://cdn.jsdelivr.net/npm/@nine-lab/nine-util@${__APP_VERSION__}/dist/css/nine-util.css\";\r\n\t\t\t\t${this.cssPath ? `@import \"${this.cssPath}\";` : \"\"}\r\n\t\t\t</style>\r\n\t\t\t${gripTmpl}\r\n `;\r\n\r\n\t\tthis.shadowRoot.appendChild(htmlTmpl.content.cloneNode(true));\r\n\r\n\t\tthis.shadowRoot.querySelectorAll(\".grip\").forEach(el => {\r\n\t\t\tel.addEventListener(\"mousedown\", e => this.#startDrag(e));\r\n\t\t});\r\n\r\n\t\tthis.#prepareLayout();\r\n\r\n\t\twindow.addEventListener(\"resize\", () => this.#prepareLayout());\r\n\t};\r\n\r\n\t#prepareLayout = () => {\r\n\t\tconst isHorizontal = this.#mode === \"h\";\r\n\t\tconst parent = this.parentElement;\r\n\t\tconst allPanels = Array.from(parent.children).filter(el => el.tagName.toLowerCase() !== 'nx-splitter');\r\n\t\tif (allPanels.length < 2) return;\r\n\r\n\t\tconst parentRect = parent.getBoundingClientRect();\r\n\t\tconst totalContentSize = allPanels.reduce((sum, el) => {\r\n\t\t\tconst size = isHorizontal ? el.getBoundingClientRect().width : el.getBoundingClientRect().height;\r\n\t\t\treturn sum + size;\r\n\t\t}, 0);\r\n\t\tconst totalParentSize = isHorizontal ? parentRect.width : parentRect.height;\r\n\r\n\t\tallPanels.forEach(panel => {\r\n\t\t\tconst size = isHorizontal ? panel.getBoundingClientRect().width : panel.getBoundingClientRect().height;\r\n\t\t\tconst newSize = totalParentSize * (size / totalContentSize);\r\n\t\t\tconst flexGrow = newSize / totalParentSize;\r\n\t\t\tpanel.style.flex = `${flexGrow} ${flexGrow} 0`;\r\n\t\t});\r\n\t};\r\n}\r\n\r\nif (!customElements.get('nine-splitter')) {\r\n\tcustomElements.define(\"nine-splitter\", UxSplitter);\r\n}","// 1. 기존 core 모듈\r\nimport { NineUtil } from './ux/dialog/NineUtil.js';\r\nimport { nine, subscribeConfig, config } from './core/Config.js';\r\nimport { Trace, trace } from './core/Trace.js';\r\nimport { TaskDebouncer } from './core/TaskDebouncer.js';\r\n\r\n// 2. 신규 net 및 ux 모듈 추가\r\nimport { api, Fetch } from './net/Fetch.js';\r\nimport { Loading } from './ux/Loading.js';\r\n\r\nimport { nineDialog } from './ux/dialog/nineDialog.js';\r\nimport { nineConfirmPopup, nineAlertPopup } from './ux/dialog/nineConfirm.js';\r\nimport { ninePromptPopup } from './ux/dialog/ninePrompt.js';\r\n\r\n// ux\r\nimport './ux/UxSplitter.js';\r\n\r\nconst utilInstance = new NineUtil();\r\nnine.alert = utilInstance.alert.bind(utilInstance);\r\nnine.confirm = utilInstance.confirm.bind(utilInstance);\r\nnine.prompt = utilInstance.prompt.bind(utilInstance);\r\n\r\n// 기존 nine 객체(Config)와 Util 기능을 합성\r\n//Object.assign(nine, utilInstance);\r\n\r\nnine.api = api;\r\nnine.trace = trace;\r\nnine.subscribeConfig = subscribeConfig;\r\nnine.config = config || {};\r\n\r\nexport {\r\n\tnine,\r\n\tsubscribeConfig,\r\n\tconfig,\r\n\tNineUtil,\r\n\tTrace,\r\n\ttrace,\r\n\tTaskDebouncer,\r\n\tapi, // 🚀 추가: 이제 서비스에서 api.get() 가능\r\n\tFetch, // 🚀 추가: 클래스 자체도 혹시 모르니 노출\r\n\tLoading as loading, // 🚀 추가: loading.show() 로 쓰기 편하게 alias\r\n\tnineDialog,\r\n\tnineAlertPopup, nineConfirmPopup, ninePromptPopup\r\n};\r\n\r\nif (typeof window !== 'undefined') {\r\n\twindow.nine = nine;\r\n}\r\n"],"names":["_init","config","el","trace"],"mappings":";;;;;;;;;;;AAAA,0PAAAA,QAAA;AAEA,MAAM,YAAY,oBAAI;AAItB,MAAM,iBAAiB;AAAA,EACtB,IAAI,EAAE,gBAAgB,OAAO,OAAO,QAAO;AAAA,EAC3C,OAAO,EAAE,UAAU,MAAK;AAAA,EACxB,SAAS;AAAA,EACT,OAAO;AACR;AAEA,IAAI,OAAO,WAAW,eAAe,CAAC,OAAO,wBAAwB;AACpE,SAAO,yBAAyB;AACjC;AAGA,MAAM,UAAU,OAAO,WAAW,cAAc,OAAO,yBAAyB;AAEpE,MAAC,kBAAkB,CAAC,OAAO;AACtC,YAAU,IAAI,EAAE;AAChB,KAAG,OAAO,OAAO;AACjB,SAAO,MAAM,UAAU,OAAO,EAAE;AACjC;AAGY,MAAC,SAAS,IAAI,MAAM,SAAS;AAAA,EACxC,IAAI,QAAQ,MAAM,OAAO;AACxB,WAAO,IAAI,IAAI;AACf,cAAU,QAAQ,QAAM,GAAG,MAAM,MAAM,CAAC;AACxC,WAAO;AAAA,EACR;AAAA,EACA,IAAI,QAAQ,MAAM;AACjB,WAAO,OAAO,IAAI;AAAA,EACnB;AACD,CAAC;AAEW,MAAC,OAAO;AAAA,EACnB;AAAA;AAAA;AAAA,EAIA,IAAI,UAAU;AACb,WAAO,KAAK,OAAO,WAAW;AAAA,EAC/B;AAAA,EAEA,MAAM,UAAU,IAAI;AACnB,WAAO,QAAQ,OAAO,EAAE,QAAQ,CAAC,CAAC,KAAK,KAAK,MAAM;AAEjD,UAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK,GAAG;AACzE,aAAK,OAAO,GAAG,IAAI,EAAE,GAAG,KAAK,OAAO,GAAG,GAAG,GAAG;MAC9C,OAAO;AACN,aAAK,OAAO,GAAG,IAAI;AAAA,MACpB;AAAA,IACD,CAAC;AAGD,QAAI,OAAO,WAAW,aAAa;AAClC,aAAO,OAAO,OAAO,QAAQ;AAAA,IAC9B;AAAA,EACD;AACD;AC7DO,MAAM,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAA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"}
1
+ {"version":3,"file":"nine-util.js","sources":["../src/ux/dialog/style.dialog.js","../src/ux/dialog/nineDialog.js","../src/ux/dialog/nineConfirm.js","../src/ux/dialog/ninePrompt.js","../src/ux/dialog/NineUtil.js","../src/core/Config.js","../src/core/Trace.js","../src/core/TaskDebouncer.js","../src/external/NoPeer.js","../src/ux/Loading.js","../src/net/Fetch.js","../src/utils/promise.js","../src/ux/UxSplitter.js","../src/index.js"],"sourcesContent":["// nxDialog.styles.js\nexport const dialogStyles = `\n\tdialog::backdrop {\n\t\tbackground: rgba(0, 0, 0, 0.3);\n\t}\n\t\n\tdialog:modal {\n\t\tdisplay: flex;\n\t\tflex-direction: column;\n\t\tpadding: 0;\n\t\toverflow: hidden;\n\t\tborder: 1px solid darkgreen;\n\t\toutline: none;\n\t\tresize: both;\n\t\tbox-shadow: 0 0 4px 0 darkgreen;\n width: 500px;\n height: 150px;\n min-width: 330px;\n min-height: 60px;\n }\n \n \n \n \n\tdiv.head .rect1, div.head .rect2, div.head .rect3 {\n\t\tdisplay: none;\n\t\twidth: 50px;\n\t\theight: 100%;\n\t}\n\tdiv.head .rect1 {\n\t\tbackground-color: red;\n\t}\n\tdiv.head .rect2 {\n\t\tbackground-color: darkgreen;\n\t}\n\tdiv.head .rect3 {\n\t\tbackground-color: olive;\n\t}\n\t\n\tdiv.head {\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\t--height: 30px;\n\t\tbackground-color: darkgreen;\n\t\tpadding: 4px;\n\t\tcursor: move;\n\t}\n\tdiv.head:hover {\n\t\tfilter: brightness(110%);\n\t}\n\t\n\tdiv.head span {\n\t\tfont-size: 12px;\n\t\tposition: relative;\n\t}\n\t\n\tdiv.head span.title {\n\t\tcolor: #ddd;\n\t\tmargin-left: 4px;\n\t\tfont-weight: bold;\n\t}\n\t\n\tdiv.head span.sub-title {\n\t\tcolor: #ccc;\n\t\tmargin-left: 8px;\n\t\tfont-style: italic;\n\t}\n\t\n\tdiv.head form {\n\t\tmargin: 0;\n\t}\n\tdiv.head button {\n\t\tmargin-right: 4px;\n\t\tbackground-color: transparent;\n\t\tborder: none;\n\t\tcolor: #ccc;\n\t\tfont-size: x-small;\n\t}\n\tdiv.head button:hover {\n\t\tcursor: pointer;\n\t}\n\t\n\tdiv.contents {\n\t\tdisplay: flex;\n\t\twidth: 100%;\n\t\theight: 100%;\n\t\toverflow: hidden;\n\t}\n\tdiv.left {\n\t\tposition: relative;\n\t\twidth: 16px;\n\t\theight: 100%;\n\t\tbackground-color: #ddd;\n\t\tdisplay: none;\n\t}\n\t\n\tdiv.left span {\n\t\twriting-mode: vertical-rl;\n\t\t-moz-user-select: none;\n\t\t-webkit-user-select: none;\n\t\t-ms-user-select: none;\n\t\tuser-select: none;\n\t\tcolor: #ccc;\n\t\tfont-weight: 700;\n\t\twidth: 100%;\n\t\theight: 100%;\n\t\tmargin-left: 3px;\n\t\tmargin-top: 3px;\n\t}\n\tdiv.close2 {\n\t\tdisplay: none;\n\t\tposition: absolute;\n\t\tright: 0;\n\t\ttop: 3px;\n\t\tcursor: pointer;\n\t\tcolor: #666;\n\t}\n\tdiv.close2 svg:hover {\n\t\tcolor: #999;\n\t}\n\t\n\tdiv.body {\n\t\tdisplay: flex;\n\t\twidth: 100%;\n\t\theight: unset;\n\t\t--border: 3px solid #999;\n\t\t--border-top: none;\n\t\toverflow-x: hidden;\n\t\toverflow-y: auto;\n\t\tpadding: 10px;\n\t\tgap: 8px;\n\t\tflex-direction: column;\n\t}\n\t\n\t\n\t\n\t\n\tng-sphere.icon {\n\t\tmargin-left: 8px;\n\t}\n\t\n\t.buttons {\n\t\tdisplay: flex;\n\t\tposition: absolute;\n\t\tright: 4px;\n\t}\n\t\n\tng-sphere {\n\t\tposition: relative;\n\t\t--width: 16px;\n\t\t--height: 16px;\n\t\tcursor: pointer;\n\t\tmargin-right: 4px;\n\t\tdisplay: flex;\n\t}\n\tng-sphere:hover {\n\t\tfilter: brightness(90%);\n\t}\n\tng-sphere:active {\n\t\tfilter: brightness(80%);\n\t}\n\t\n\tng-sphere:hover::after {\n\t\tcontent: \"\";\n\t\tposition: absolute;\n\t\twidth: 100%;\n\t\theight: 100%;\n\t\tbackground-repeat: no-repeat;\n\t\tbackground-position: center;\n\t}\n\tng-sphere.apply:hover::after {\n\t\tbackground-size: 14px 14px;\n\t\tbackground-image: url('data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\"><polyline points=\"2.5,7 6,10 11,3\" style=\"fill:none;stroke:white;stroke-width:2px;\" /></svg>');\n\t}\n\t\n\tng-sphere.reset:hover::after {\n\t\tbackground-size: 12px 12px;\n\t\tbackground-image: url('data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\" style=\"fill:none;stroke:white;stroke-width:2px;\" focusable=\"false\" aria-hidden=\"true\"><path d=\"M10 5h5V0\"></path><path d=\"M15 8a6.957 6.957 0 0 1-7 7 6.957 6.957 0 0 1-7-7 6.957 6.957 0 0 1 7-7 6.87 6.87 0 0 1 6.3 4\"></path></svg>');\n\t}\n\t\n\tng-sphere.close:hover::after {\n\t\tbackground-size: 12px 12px;\n\t\tbackground-image: url('data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" style=\"fill:none;stroke:white;stroke-width:2px;\" focusable=\"false\" aria-hidden=\"true\" viewBox=\"0 0 16 16\"><path d=\"M2 2l12 12M14 2L2 14\"></path></svg>');\n\t}\n\t\n\t\n\tbutton {\n cursor: pointer;\n }\n \n .input-area {\n position: relative;\n height: 100%;\n --display: flex;\n textarea {\n width: 100%;\n height: 100%;\n min-height: 100px;\n padding: 8px;\n box-sizing: border-box;\n resize: none;\n border-radius: 2px;\n border-color: #ccc;\n }\n textarea:focus {\n border-color: green;\n outline: none; /* 브라우저 기본 파란색 테두리 제거 */\n }\n }\n \n .buttons-confirm {\n position: relative;\n display: flex;\n justify-content: flex-end;\n --bottom: 8px;\n --right: 8px;\n }\n \n \n .buttons-confirm button {\n height: 32px;\n margin-right: 8px;\n border: none;\n outline: none;\n width: 60px;\n -moz-user-select: none;\n -webkit-user-select: none;\n -ms-user-select: none;\n user-select: none;\n }\n .buttons-confirm button:hover {\n filter: brightness(90%);\n }\n .buttons-confirm button:active {\n color: #ccc;\n }\n \n button.ok {\n --display: none;\n background-color: darkgreen;\n color: white;\n }\n button.cancel {\n color: white;\n background-color: #6c757d;\n }\n \n \n \n div.msg {\n position: relative;\n height: 100%;\n font-size: 14px;\n color: #333;\n }\n \n .reset, .apply {\n display: none;\n }\n \n \n \n :host(.classic) dialog:modal {\n border: 1px solid #007bff;\n box-shadow: 0 0 4px 0 #007bff;\n }\n \n :host(.classic) div.head {\n background-color: #007bff;\n }\n :host(.classic) div.head:hover {\n filter: brightness(110%);\n }\n \n :host(.classic) div.head span {\n font-size: 12px;\n }\n \n :host(.classic) div.head span.title {\n color: #ddd;\n margin-left: 4px;\n font-weight: bold;\n }\n \n :host(.classic) div.head span.sub-title {\n color: #ccc;\n margin-left: 8px;\n font-style: italic;\n }\n :host(.classic) div.head button {\n margin-right: 4px;\n background-color: transparent;\n border: none;\n color: #ccc;\n font-size: x-small;\n }\n \n \n \n \n :host(.rgb) dialog:modal {\n border: none;\n box-shadow: unset;\n border-top: none;\n }\n \n :host(.rgb) div.left {\n display: block;\n background-color: #ddd;\n }\n :host(.rgb) div.left span {\n color: #ccc;\n }\n :host(.rgb) div.close2 {\n display: block;\n color: #666;\n }\n :host(.rgb) div.close2 svg:hover {\n color: #999;\n }\n :host(.rgb) div.head {\n height: 4px;\n background-color: #999;\n padding: 0;\n }\n :host(.rgb) div.contents {\n height: calc(100% - 4px);\n }\n \n :host(.rgb) div.head ng-sphere,\n :host(.rgb) div.head span,\n :host(.rgb) div.head .buttons {\n display: none;\n }\n \n :host(.rgb) div.head .rect1,\n :host(.rgb) div.head .rect2,\n :host(.rgb) div.head .rect3 {\n display: flex;\n }\n \n \n :host(.rgb) div.head:hover {\n filter: unset;\n }\n \n \n /* --- Animation Core --- */\n:host {\n --nx-duration: 0.4s;\n --nx-timing: cubic-bezier(0.34, 1.56, 0.64, 1);\n}\n\n/* 🎯 수정: 애니메이션 클래스가 붙은 경우에만 초기 opacity를 0으로 설정 */\n:host(.fade) dialog,\n:host(.zoom) dialog,\n:host(.moveUp) dialog,\n:host(.moveDown) dialog,\n:host(.moveLeft) dialog,\n:host(.moveRight) dialog,\n:host(.roadRunner) dialog {\n opacity: 0;\n}\n\n/* shake는 애니메이션 내부에서 opacity를 다루므로 제외하거나 별도 처리 */\n:host(.shake) dialog { \n opacity: 1; \n}\n\n/* 1. Fade (서서히 나타남) */\n:host(.fade) dialog { animation: nx-fade-in var(--nx-duration) forwards; }\n@keyframes nx-fade-in { from { opacity: 0; } to { opacity: 1; } }\n\n/* 2. Zoom (커지며 나타남) */\n:host(.zoom) dialog { animation: nx-zoom-in var(--nx-duration) var(--nx-timing) forwards; }\n@keyframes nx-zoom-in { from { opacity: 0; transform: scale(0.5); } to { opacity: 1; transform: scale(1); } }\n\n/* 3. Slide (상하좌우) */\n:host(.moveUp) dialog { animation: nx-move-up var(--nx-duration) var(--nx-timing) forwards; }\n:host(.moveDown) dialog { animation: nx-move-down var(--nx-duration) var(--nx-timing) forwards; }\n:host(.moveLeft) dialog { animation: nx-move-left var(--nx-duration) var(--nx-timing) forwards; }\n:host(.moveRight) dialog { animation: nx-move-right var(--nx-duration) var(--nx-timing) forwards; }\n\n@keyframes nx-move-up { from { opacity: 0; transform: translateY(100px); } to { opacity: 1; transform: translateY(0); } }\n@keyframes nx-move-down { from { opacity: 0; transform: translateY(-100px); } to { opacity: 1; transform: translateY(0); } }\n@keyframes nx-move-left { from { opacity: 0; transform: translateX(100px); } to { opacity: 1; transform: translateX(0); } }\n@keyframes nx-move-right { from { opacity: 0; transform: translateX(-100px); } to { opacity: 1; transform: translateY(0); } }\n\n/* 4. Shake (상하좌우 격렬한 진동 - 에러 인지용) */\n:host(.shake) dialog { \n animation: nx-heavy-shake 0.5s cubic-bezier(.36,.07,.19,.97) both;\n opacity: 1; \n}\n\n@keyframes nx-heavy-shake {\n 10%, 90% { transform: translate3d(-1px, -2px, 0); }\n 20%, 80% { transform: translate3d(2px, 4px, 0); }\n 30%, 50%, 70% { transform: translate3d(-6px, -6px, 0); }\n 40%, 60% { transform: translate3d(6px, 6px, 0); }\n}\n\n/* 5. Road Runner (등장: 왼쪽에서 탄력 있게 / 퇴장: 움츠렸다가 광속 탈출) */\n:host(.roadRunner) dialog { \n animation: roadRunnerIn 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards; \n}\n\n@keyframes roadRunnerIn {\n 0% { transform: translateX(-1500px) skewX(30deg); opacity: 1; }\n 70% { transform: translateX(30px) skewX(-10deg); opacity: 1; }\n 100% { transform: translateX(0) skewX(0deg); opacity: 1; }\n}\n\n/* --- Out Animations (닫힐 때) --- */\ndialog.out { pointer-events: none; }\n\n/* Road Runner 퇴장: 슥 움츠렸다가(Anticipation) 쌩~! */\n:host(.roadRunner) dialog.out { \n animation: roadRunnerOut 0.5s cubic-bezier(0.6, -0.28, 0.735, 0.045) forwards; \n}\n\n@keyframes roadRunnerOut {\n 0% { \n transform: translateX(0) scale(1) skewX(0deg); \n opacity: 1; \n }\n 30% { \n /* 예비 동작: 뒤로 살짝 갔다가 움츠러들기 */\n transform: translateX(50px) scaleX(1.2) scaleY(0.8) skewX(-20deg); \n opacity: 1; \n }\n 100% { \n /* 발사: 길게 늘어나며 광속 탈출 */\n transform: translateX(2000px) scaleX(4) scaleY(0.3) skewX(50deg); \n opacity: 0; \n filter: blur(10px); /* 👈 잔상 느낌 추가 */\n }\n}\n\n/* 일반 퇴장 (기본) */\ndialog.out { animation: nx-fade-out 0.3s forwards; }\n@keyframes nx-fade-out { from { opacity: 1; transform: scale(1); } to { opacity: 0; transform: scale(0.9); } }\n`;","import { dialogStyles } from './style.dialog.js';\n\nexport class nineDialog extends HTMLElement\n{\n\t#shift;\n\t#dialog;\n\n\n\tconstructor () {\n\t\tsuper();\n\t}\n\n\tconnectedCallback() {\n\n\t\tconst v = this.innerHTML;\n\t\tconst titleText = this.getAttribute(\"title\") || \"Details\";\n\n\t\ttrace.log(\"111111111\")\n\n\t\tthis.innerHTML = `\n\t\t\t<style>${dialogStyles}</style>\n\t\t\n\t\t\t<dialog>\n\t\t\t\t<div class=\"head\">\n\t\t\t\t\t<div class=\"rect1\"></div>\n\t\t\t\t\t<div class=\"rect2\"></div>\n\t\t\t\t\t<div class=\"rect3\"></div>\n\t\t\t\t\t<ng-sphere class=\"icon\" end-fill=\"#666\" size=\"8\"></ng-sphere>\n\t\t\t\t\t<span class=\"title\">${titleText}</span>\n\t\t\t\t\t<span class=\"sub-title\"></span>\n\t\t\t\t\t<div class=\"buttons\">\n\t\t\t\t\t\t<ng-sphere class=\"apply\" start-fill=\"#cc6\" end-fill=\"#660\" size=\"16\" title=\"apply\"></ng-sphere>\n\t\t\t\t\t\t<ng-sphere class=\"reset\" start-fill=\"#99f\" end-fill=\"#00f\" size=\"16\" title=\"reset\"></ng-sphere>\n\t\t\t\t\t\t<ng-sphere class=\"close\" start-fill=\"#f99\" end-fill=\"#f00\" size=\"16\" title=\"close\"></ng-sphere>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"contents\">\n\t\t\t\t\t<div class=\"left\">\n\t\t\t\t\t\t<span>가나다라마바사아자차카타파하가나다라마바사아자차카타파하가나다라마바사아자차카타파하가나다라마바사아자차카타파하가나다라마바사아자차카타파하가나다라마바사아자차카타파하가나다라마바사아자차카타파하가나다라마바사아자차카타파하</span>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"body\">\n\t\t\t\t\t\t${v}\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"close2\">\n\t\t\t\t\t\t<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" viewBox=\"0 0 16 16\">\n\t\t\t\t\t\t\t<path d=\"M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708\"/>\n\t\t\t\t\t\t</svg>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</dialog>\n\t\t`;\n\n\t\t//this.#owner = this.getRootNode().host.closest(\"nine-grid\");\n\n\t\t//$(\".title\", this).html(\"Details\");\n\n\t\tthis.#dialog = this.querySelector('dialog');\n\t\tthis.#init();\n\t};\n\n\tshowModal = () => {\n\t\tthis.#dialog.showModal();\n\t};\n\n\tclose = () => {\n\t\t// 이벤트 리스너 제거 (표준 방식은 핸들러 참조가 필요하지만,\n\t\t// 여기서는 요소가 사라지므로 메모리 관리를 위해 정리)\n\t\tthis.#dialog.close();\n\t\tthis.remove();\n\t};\n\n\t#init = () => {\n\t\tconst head = this.querySelector('.head');\n\n\t\t// 1. 모든 닫기 성격의 버튼 (.close, .close2, .cancel) 공통 처리\n\t\tthis.querySelectorAll('.close, .close2, .cancel').forEach(btn => {\n\t\t\tbtn.onclick = () => this.closeWithAnimation(null); // 취소/닫기는 null 리턴\n\t\t});\n\n\t\t// 2. 확인 버튼 (.ok) 처리\n\t\t// 확인 버튼은 텍스트 입력값 등 데이터가 필요하므로\n\t\t// 실제 데이터 추출은 각 팝업 클래스(prompt 등)에서 하되,\n\t\t// 닫기 애니메이션 실행은 여기서 담당하도록 가이드합니다.\n\t\tthis.querySelectorAll('.ok').forEach(btn => {\n\t\t\t// .ok 버튼의 로직은 각 팝업의 setupEvents에서 덮어쓰거나\n\t\t\t// 델리게이트 이벤트를 통해 처리합니다.\n\t\t});\n\n\t\t// 드래그 로직 생략...\n\t};\n\n\t// --- 드래그 로직 (Vanilla JS) ---\n\t#onMouseDown = e => {\n\t\tif (e.target.closest(\"buttons\")) return;\n\t\tif (e.button !== 0 || e.altKey || e.ctrlKey || e.shiftKey) return;\n\n\t\tconst rect = this.#dialog.getBoundingClientRect();\n\t\tthis.#shift = {\n\t\t\tx: e.clientX - rect.left,\n\t\t\ty: e.clientY - rect.top\n\t\t};\n\n\t\tconst onMouseMove = (ev) => {\n\t\t\tthis.#dialog.style.position = 'fixed';\n\t\t\tthis.#dialog.style.margin = '0';\n\t\t\tthis.#dialog.style.left = `${ev.clientX - this.#shift.x}px`;\n\t\t\tthis.#dialog.style.top = `${ev.clientY - this.#shift.y}px`;\n\t\t};\n\n\t\tconst onMouseUp = () => {\n\t\t\tdocument.removeEventListener('mousemove', onMouseMove);\n\t\t\tdocument.removeEventListener('mouseup', onMouseUp);\n\t\t};\n\n\t\tdocument.addEventListener('mousemove', onMouseMove);\n\t\tdocument.addEventListener('mouseup', onMouseUp);\n\t};\n\n\t#onTouchStart = e => {\n\t\tif (e.target.closest(\"buttons\")) return;\n\n\t\tconst rect = this.#dialog.getBoundingClientRect();\n\t\tconst touch = e.changedTouches[0];\n\t\tthis.#shift = {\n\t\t\tx: touch.pageX - rect.left,\n\t\t\ty: touch.pageY - rect.top\n\t\t};\n\n\t\tconst onTouchMove = (ev) => {\n\t\t\tconst t = ev.changedTouches[0];\n\t\t\tthis.#dialog.style.position = 'fixed';\n\t\t\tthis.#dialog.style.margin = '0';\n\t\t\tthis.#dialog.style.left = `${t.pageX - this.#shift.x}px`;\n\t\t\tthis.#dialog.style.top = `${t.pageY - this.#shift.y}px`;\n\t\t};\n\n\t\tconst onTouchEnd = () => {\n\t\t\tdocument.removeEventListener('touchmove', onTouchMove);\n\t\t\tdocument.removeEventListener('touchend', onTouchEnd);\n\t\t};\n\n\t\tdocument.addEventListener('touchmove', onTouchMove);\n\t\tdocument.addEventListener('touchend', onTouchEnd);\n\t};\n\n\tcloseWithAnimation(returnValue) {\n\t\tthis.#dialog.classList.add(\"out\"); // 퇴장 애니메이션 시작\n\n\t\t// 애니메이션(0.3s)이 끝난 후 제거 및 이벤트 발생\n\t\tsetTimeout(() => {\n\t\t\tthis.#dialog.close();\n\t\t\t// 부모(BasePopup)에게 작업 완료와 결과값을 알림\n\t\t\tthis.dispatchEvent(new CustomEvent('closed', { detail: returnValue }));\n\t\t\tthis.remove();\n\t\t}, 300);\n\t}\n}\n\n// BasePopup.js\nexport class BasePopup extends HTMLElement {\n\n\tconstructor() {\n\t\tsuper();\n\t\tthis.attachShadow({ mode: 'open' });\n\t}\n\n\tstatic async open(PopupClass, message, title, options, renderFn) {\n\t\t// 1. 설정 병합\n\t\tconst tagName = PopupClass.tagName.toLowerCase();\n\t\tconst config = {\n\t\t\t\"true-text\": \"확인\",\n\t\t\t\"false-text\": \"취소\",\n\t\t\tclass: \"classic\",\n\t\t\tanimation: \"fade\",\n\t\t\t...(window.nine?.config?.ux?.[tagName.replace('nine-', '').replace('-popup', '')] || {}),\n\t\t\t...options\n\t\t};\n\n\t\t// 2. 중복 제거 및 엘리먼트 생성\n\t\tdocument.querySelectorAll(tagName).forEach(el => el.remove());\n\t\tconst el = document.createElement(tagName);\n\t\tif (config.class) el.classList.add(config.class);\n\t\tif (config.animation) el.classList.add(config.animation);\n\t\tdocument.body.appendChild(el);\n\n\t\t// 3. 렌더링 (각 팝업의 UI 그리기)\n\t\trenderFn(el, message, config);\n\n\t\tconst dialogComp = el.shadowRoot.querySelector(\"nine-dialog\");\n\t\tif (title) dialogComp.setAttribute(\"title\", title);\n\n\t\treturn new Promise((resolve) => {\n\t\t\t// [중요] nine-dialog의 애니메이션이 끝난 후 던지는 이벤트를 수신\n\t\t\tdialogComp.addEventListener('closed', (e) => resolve(e.detail));\n\n\t\t\t// 각 팝업 클래스에서 버튼 클릭 시 dialogComp.closeWithAnimation(값)을\n\t\t\t// 호출하도록 이벤트를 바인딩해줌\n\t\t\tel.setupEvents(resolve, dialogComp);\n\n\t\t\tdialogComp.showModal();\n\t\t});\n\t}\n}\n\nif (!customElements.get('nine-dialog')) {\n\tcustomElements.define(\"nine-dialog\", nineDialog);\n}\n","import { BasePopup } from \"./nineDialog.js\";\n\nexport class nineConfirmPopup extends BasePopup {\n\tstatic tagName = 'nine-confirm-popup';\n\n\tconstructor() {\n\t\tsuper();\n\t}\n\n\trender(message, config) {\n\t\tthis.shadowRoot.innerHTML = `\n <nine-dialog>\n <div class=\"msg\">${message.replace(/\\n/g, \"<br/>\")}</div>\n <div class=\"buttons-confirm\">\n <button class=\"cancel\">${config[\"false-text\"]}</button>\n <button class=\"ok\">${config[\"true-text\"]}</button>\n </div>\n </nine-dialog>`;\n\t}\n\n\tsetupEvents(resolve, dialogComp) {\n\t\tthis.shadowRoot.querySelector(\".ok\").onclick = () => dialogComp.closeWithAnimation(true);\n\t\t// 취소는 nine-dialog 내부 기본 로직(closeWithAnimation(null))이 처리함\n\t}\n\n\tstatic confirm = (m, t, o) => BasePopup.open(nineConfirmPopup, m, t, o, (el, msg, conf) => el.render(msg, conf));\n}\n\n// --- 3. ALERT (단순 알림) ---\nexport class nineAlertPopup extends BasePopup {\n\tstatic tagName = 'nine-alert-popup';\n\n\tconstructor() {\n\t\tsuper();\n\t}\n\n\trender(message, config) {\n\t\tthis.shadowRoot.innerHTML = `\n <nine-dialog>\n <div class=\"msg\">${message.replace(/\\n/g, \"<br/>\")}</div>\n <div class=\"buttons-confirm\">\n <button class=\"cancel\">확인</button>\n </div>\n </nine-dialog>`;\n\t}\n\n\tsetupEvents(resolve, dialogComp) {\n\t\t// 얼럿은 취소 버튼 하나만 두거나, 확인 버튼이 cancel 역할을 수행하게 함\n\t}\n\n\tstatic alert = (m, t, o) => BasePopup.open(nineAlertPopup, m, t, o, (el, msg, conf) => el.render(msg, conf));\n}\n\n// Custom Element 등록\nif (!customElements.get('nine-confirm-popup')) customElements.define('nine-confirm-popup', nineConfirmPopup);\nif (!customElements.get('nine-alert-popup')) customElements.define(\"nine-alert-popup\", nineAlertPopup);","import { BasePopup } from \"./nineDialog.js\";\n\n/**\n *\n */\nexport class ninePromptPopup extends BasePopup {\n\tstatic tagName = 'nine-prompt-popup';\n\n\tconstructor() {\n\t\tsuper();\n\t}\n\n\trender(message, config) {\n\n\t\ttrace.log(this);\n\t\ttrace.log(this.shadowRoot);\n\n\t\tthis.shadowRoot.innerHTML = `\n\t\t\t<style>\n\t\t\t\tdialog {\n\t\t\t\t\theight: 300px !important;\n\t\t\t\t}\n\t\t\t\t.msg {\n\t\t\t\t\theight: unset !important;\n\t\t\t\t}\n\t\t\t</style>\n\t\t\t\n <nine-dialog>\n <div class=\"msg\">${message.replace(/\\n/g, \"<br/>\")}</div>\n <div class=\"input-area\">\n <textarea placeholder=\"내용을 입력하세요...\"></textarea>\n </div>\n <div class=\"buttons-confirm\">\n <button class=\"cancel\">${config[\"false-text\"]}</button>\n <button class=\"ok\">${config[\"true-text\"]}</button>\n </div>\n </nine-dialog>`;\n\t}\n\n\tsetupEvents(resolve, dialogComp) {\n\t\tconst textarea = this.shadowRoot.querySelector(\"textarea\");\n\t\tconst okBtn = this.shadowRoot.querySelector(\".ok\");\n\n\t\t// 확인 버튼 클릭 시 textarea 값을 가지고 애니메이션 닫기\n\t\tokBtn.onclick = () => dialogComp.closeWithAnimation(textarea.value);\n\n\t\t// 렌더링 후 포커스\n\t\trequestAnimationFrame(() => textarea.focus());\n\t}\n\n\tstatic prompt = (m, t, o) => BasePopup.open(ninePromptPopup, m, t, o, (el, msg, conf) => el.render(msg, conf));\n}\n\nif (!customElements.get('nine-prompt-popup')) {\n\tcustomElements.define('nine-prompt-popup', ninePromptPopup);\n}","// src/core/NineUtil.js\r\nimport { nineAlertPopup, nineConfirmPopup } from './nineConfirm.js';\r\nimport { ninePromptPopup } from \"./ninePrompt.js\";\r\n\r\nexport class NineUtil {\r\n\t// static 필드는 클래스 자체에 저장됨\r\n\tstatic cssPath = \"\";\r\n\r\n\t/**\r\n\t * 팝업 준비 로직 (Private 메서드)\r\n\t */\r\n\t#prepare(type, message, title, defaultClass) {\r\n\r\n\t\tconst options = { class: defaultClass, animation: 'fade' };\r\n\t\t//const popup = type === 'alert' ? nineAlertPopup : (type === 'confirm' ? nineConfirmPopup : ninePromptPopup);\r\n\t\tlet isExecuted = false;\r\n\r\n\t\tconst popupMap = {\r\n\t\t\talert: nineAlertPopup,\r\n\t\t\tconfirm: nineConfirmPopup,\r\n\t\t\tprompt: ninePromptPopup\r\n\t\t};\r\n\r\n\t\tconst popup = popupMap[type];\r\n\r\n\t\tconst runner = {\r\n\t\t\trgb: () => { options.class = 'rgb'; return runner; },\r\n\t\t\tclassic: () => { options.class = 'classic'; return runner; },\r\n\t\t\tshake: () => { options.animation = 'shake'; return runner; },\r\n\t\t\trun: () => { options.animation = 'roadRunner'; return runner; },\r\n\t\t\tzoom: () => { options.animation = 'zoom'; return runner; },\r\n\r\n\t\t\tthen: (resolve, reject) => {\r\n\t\t\t\tisExecuted = true;\r\n\t\t\t\treturn popup[type](message, title, options).then(resolve, reject);\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\t// Microtask: 동기 체이닝이 모두 끝난 후 실행\r\n\t\tPromise.resolve().then(() => {\r\n\t\t\tif (!isExecuted) {\r\n\t\t\t\tisExecuted = true;\r\n\t\t\t\tpopup[type](message, title, options);\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\treturn runner;\r\n\t}\r\n\r\n\talert(message, title = \"Alert\") {\r\n\t\treturn this.#prepare('alert', message, title, 'classic');\r\n\t}\r\n\r\n\tconfirm(message, title = \"Confirm\") {\r\n\t\treturn this.#prepare('confirm', message, title, 'classic');\r\n\t}\r\n\r\n\tprompt(message, title = \"Prompt\") {\r\n\t\treturn this.#prepare('prompt', message, title, 'classic');\r\n\t}\r\n}","const listeners = new Set();\r\n\r\n// 💡 [핵심] 전역 저장소를 단일화합니다.\r\n// window에 이미 있으면 그것을 쓰고, 없으면 초기값을 생성하여 등록합니다.\r\nconst _initialConfig = {\r\n\tux: { nativeOverride: false, theme: 'light' },\r\n\tboard: { readOnly: false },\r\n\tcssPath: \"\",\r\n\tdebug: false\r\n};\r\n\r\nif (typeof window !== 'undefined' && !window.__NINE_GLOBAL_CONFIG__) {\r\n\twindow.__NINE_GLOBAL_CONFIG__ = _initialConfig;\r\n}\r\n\r\n// 이제 모든 모듈의 _config는 동일한 window 객체 메모리를 가리킵니다.\r\nconst _config = typeof window !== 'undefined' ? window.__NINE_GLOBAL_CONFIG__ : _initialConfig;\r\n\r\nexport const subscribeConfig = (fn) => {\r\n\tlisteners.add(fn);\r\n\tfn('all', _config);\r\n\treturn () => listeners.delete(fn);\r\n};\r\n\r\n// Proxy 역시 전역 저장소인 _config를 조작합니다.\r\nexport const config = new Proxy(_config, {\r\n\tset(target, prop, value) {\r\n\t\ttarget[prop] = value;\r\n\t\tlisteners.forEach(fn => fn(prop, target));\r\n\t\treturn true;\r\n\t},\r\n\tget(target, prop) {\r\n\t\treturn target[prop];\r\n\t}\r\n});\r\n\r\nexport const nine = {\r\n\tconfig: config,\r\n\r\n\t// Getter에서 window.nine까지 확인할 필요도 없습니다.\r\n\t// 이미 config 자체가 전역 저장소(__NINE_GLOBAL_CONFIG__)를 바라보고 있기 때문입니다.\r\n\tget cssPath() {\r\n\t\treturn this.config.cssPath || \"\";\r\n\t},\r\n\r\n\tsetup(options = {}) {\r\n\t\tObject.entries(options).forEach(([key, value]) => {\r\n\t\t\t// 깊은 병합 지원\r\n\t\t\tif (typeof value === 'object' && value !== null && !Array.isArray(value)) {\r\n\t\t\t\tthis.config[key] = { ...this.config[key], ...value };\r\n\t\t\t} else {\r\n\t\t\t\tthis.config[key] = value;\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\t// 다른 모듈에서 window.nine으로 접근할 수 있도록 보장\r\n\t\tif (typeof window !== 'undefined') {\r\n\t\t\twindow.nine = window.nine || this;\r\n\t\t}\r\n\t}\r\n};","export class Trace {\r\n\t#name;\r\n\t#color;\r\n\t#enabled = true;\r\n\r\n\tconstructor(name = null, color = \"green\") {\r\n\t\tthis.#name = name;\r\n\t\tthis.#color = color;\r\n\t\tthis.#autoConfig();\r\n\t\t/**\r\n\t\t// 1. 쪼개진 인스턴스들을 하나로 합치는 '본드' 역할 (이게 핵심!)\r\n\t\tif (typeof window !== 'undefined' && window.__NINE_TRACE__) {\r\n\t\t\treturn window.__NINE_TRACE__;\r\n\t\t}\r\n\t\tthis.#autoConfig();\r\n\t\tif (typeof window !== 'undefined') window.__NINE_TRACE__ = this;\r\n\t\t\t*/\r\n\t}\r\n\r\n\t#autoConfig() {\r\n\t\tif (typeof window === 'undefined') return;\r\n\t\tconst isLocal = window.location.hostname === 'localhost' ||\r\n\t\t\twindow.location.hostname === '127.0.0.1' ||\r\n\t\t\twindow.location.hostname.startsWith('192.168.');\r\n\r\n\t\tif (isLocal) {\r\n\t\t\tthis.enable();\r\n\t\t} else {\r\n\t\t\tthis.disable();\r\n\t\t\tconsole.log(\r\n\t\t\t\t`%c[${this.#name || 'Trace'}]%c 운영 모드: 로그 비활성화. %ctrace.enable()%c 로 활성화 가능`,\r\n\t\t\t\t\"color: #4CAF50; font-weight: bold;\", \"\",\r\n\t\t\t\t\"background: #333; color: yellow; padding: 2px 5px;\", \"\"\r\n\t\t\t);\r\n\t\t}\r\n\t}\r\n\r\n\t// 🟢 빼먹었던 init 메서드 다시 추가!\r\n\tinitBAK(name, color = \"green\") {\r\n\t\tthis.#name = name;\r\n\t\tthis.#color = color;\r\n\t}\r\n\r\n\tinit(name, color = \"green\") {\r\n\t\t//const style = `color: ${color}; font-weight: bold;`;\r\n\t\tthis.#name = name;\r\n\t\tthis.#color = color;\r\n\r\n\t\treturn this;\r\n\t\t/**\r\n\t\tconsole.log(name, color);\r\n\t\treturn {\r\n\t\t\tlog: console.log.bind(console, `%c[${name}]`, style),\r\n\t\t\twarn: console.warn.bind(console, `%c[${name}]`, \"color: cyan; font-weight: bold;\"),\r\n\t\t\terror: console.error.bind(console, `%c[${name}]`, \"color: red; font-weight: bold;\")\r\n\t\t}; */\r\n\t}\r\n\r\n\t//get log() { return console.log.bind(console); }\r\n\r\n\t// 🔴 핵심: 소스 위치를 호출부로 찍어주는 Getter 로직\r\n\tget log() {\r\n\t\t//if (!this.#enabled) return () => {};\r\n\t\tconst style = `color: ${this.#color}; font-weight: bold;`;\r\n\t\t// 이름이 있으면 프리픽스를 붙이고, 없으면 그냥 로그를 바인딩합니다.\r\n\t\treturn (this.#name)\r\n\t\t\t? console.log.bind(console, `%c[${this.#name}]`, style)\r\n\t\t\t: console.log.bind(console);\r\n\t}\r\n\r\n\tget warn() {\r\n\t\tif (!this.#enabled) return () => {};\r\n\t\treturn (this.#name)\r\n\t\t\t? console.warn.bind(console, `%c[${this.#name}]`, \"color: cyan; font-weight: bold;\")\r\n\t\t\t: console.warn.bind(console);\r\n\t}\r\n\r\n\tget error() {\r\n\t\t// 에러는 enabled 상태와 상관없이 찍고 싶으시면 if 체크를 주석 처리하세요.\r\n\t\t// if (!this.#enabled) return () => {};\r\n\t\treturn (this.#name)\r\n\t\t\t? console.error.bind(console, `%c[${this.#name}]`, \"color: red; font-weight: bold;\")\r\n\t\t\t: console.error.bind(console);\r\n\t}\r\n\r\n\tenable() { this.#enabled = true; }\r\n\tdisable() { this.#enabled = false; }\r\n}\r\n\r\nexport const trace = new Trace();\r\nif (typeof window !== 'undefined') window.trace = trace;","export class TaskDebouncer {\r\n\t#timer = null;\r\n\t#queue = [];\r\n\t#delay;\r\n\r\n\tconstructor(delay = 50) {\r\n\t\tthis.#delay = delay;\r\n\t}\r\n\r\n\t/**\r\n\t * @param {Function} func - 실행할 함수\r\n\t * @param {...any} args - 함수에 전달할 임의의 파라미터들\r\n\t */\r\n\texec(func, ...args) {\r\n\t\t// 1. 어떤 함수와 어떤 인자들이 들어왔는지 큐에 저장\r\n\t\tthis.#queue.push({ func, args });\r\n\r\n\t\t// 2. 디바운스 타이머 설정\r\n\t\tif (this.#timer) clearTimeout(this.#timer);\r\n\r\n\t\tthis.#timer = setTimeout(() => this.#flush(), this.#delay);\r\n\t}\r\n\r\n\texecWithKey(key, func, ...args) {\r\n\t\t// 1. 같은 키(예: 'resize')가 들어오면 이전 큐에서 해당 키 삭제 (중복 제거)\r\n\t\tthis.#queue = this.#queue.filter(task => task.key !== key);\r\n\r\n\t\t// 2. 새로운 태스크 추가\r\n\t\tthis.#queue.push({ key, func, args });\r\n\r\n\t\tif (this.#timer) clearTimeout(this.#timer);\r\n\t\tthis.#timer = setTimeout(() => this.#flush(), this.#delay);\r\n\t}\r\n\r\n\t#flush() {\r\n\t\tif (this.#queue.length === 0) return;\r\n\r\n\t\t// 3. 현재까지 쌓인 큐를 쏙 빼옴\r\n\t\tconst tasks = this.#queue.splice(0, this.#queue.length);\r\n\t\tconst seen = new Set();\r\n\r\n\t\ttasks.forEach(task => {\r\n\t\t\t// 4. 핵심: 함수 이름과 인자들을 문자열로 합쳐서 유니크 키 생성\r\n\t\t\t// JSON.stringify를 통해 [1, {a:1}] 같은 파라미터도 문자열로 비교 가능\r\n\t\t\tconst identifier = `${task.func.name}_${JSON.stringify(task.args)}`;\r\n\r\n\t\t\tif (!seen.has(identifier)) {\r\n\t\t\t\t// 5. 중복이 아닐 때만 원래 인자들(...args) 그대로 실행\r\n\t\t\t\ttask.func(...task.args);\r\n\t\t\t\tseen.add(identifier);\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tthis.#timer = null;\r\n\t}\r\n}","import { trace as traceOrigin } from '../core/Trace.js';\n\nexport class Trace extends traceOrigin.constructor {\n constructor() {\n super();\n this.init(\"nine-util\", \"green\");\n }\n}\n\nexport const trace = new Trace();","export class Loading {\n\tstatic show() {\n\t\tlet overlay = document.getElementById(\"global-loading-overlay\");\n\t\tif (!overlay) {\n\t\t\toverlay = document.createElement(\"div\");\n\t\t\toverlay.id = \"global-loading-overlay\";\n\t\t\toverlay.style.cssText = `\n position: fixed; inset: 0; z-index: 9999;\n background: rgba(0, 0, 0, 0.4); display: flex; \n justify-content: center; align-items: center;\n backdrop-filter: blur(2px);\n `;\n\t\t\toverlay.innerHTML = `<div class=\"loading-spinner\"></div>`;\n\t\t\tdocument.body.appendChild(overlay);\n\n\t\t\tif (!document.getElementById(\"nine-util-style\")) {\n\t\t\t\tconst style = document.createElement(\"style\");\n\t\t\t\tstyle.id = \"nine-util-style\";\n\t\t\t\tstyle.innerHTML = `\n .loading-spinner {\n width: 48px; height: 48px;\n border: 5px solid rgba(255, 255, 255, 0.3);\n border-top-color: white; border-radius: 50%;\n animation: nine-spin 1s linear infinite;\n }\n @keyframes nine-spin { to { transform: rotate(360deg); } }\n `;\n\t\t\t\tdocument.head.appendChild(style);\n\t\t\t}\n\t\t}\n\t\toverlay.style.display = \"flex\";\n\t}\n\n\tstatic hide() {\n\t\tconst overlay = document.getElementById(\"global-loading-overlay\");\n\t\tif (overlay) overlay.style.display = \"none\";\n\t}\n}","import { trace } from \"@nopeer\";\nimport { Loading } from \"../ux/Loading.js\";\n\nexport class Fetch {\n\tstatic BASE_URL = window.__API_BASE_URL__ || \"\";\n\n\tstatic #request = (method, url, data = {}, showLoading = true) => {\n\t\tconst finalUrl = url.startsWith('http') ? url : `${this.BASE_URL}${url}`;\n\n\t\tif (showLoading) {\n\t\t\tLoading.show();\n\t\t}\n\n\t\t// 1. 기본 헤더 설정\n\t\tconst headers = {};\n\n\t\t// 🔴 핵심: 데이터가 FormData가 아닐 때만 JSON 헤더를 추가합니다.\n\t\tif (!(data instanceof FormData)) {\n\t\t\theaders[\"Content-Type\"] = \"application/json\";\n\t\t}\n\n\t\tconst options = {\n\t\t\tmethod,\n\t\t\theaders\n\t\t};\n\n\t\tlet targetUrl = finalUrl;\n\t\tif (method === \"GET\") {\n\t\t\ttargetUrl += `?${new URLSearchParams(data)}`;\n\t\t} else {\n\t\t\t// 🔴 핵심: FormData는 그대로 body에 넣고, 일반 객체는 JSON.stringify 처리합니다.\n\t\t\toptions.body = data instanceof FormData ? data : JSON.stringify(data);\n\t\t}\n\n\t\treturn fetch(targetUrl, options)\n\t\t\t.then(async res => {\n\t\t\t\tif (!res.ok) {\n\t\t\t\t\tconst text = await res.text();\n\t\t\t\t\tthrow new Error(`API 오류 (${res.status}): ${text}`);\n\t\t\t\t}\n\t\t\t\treturn res.json();\n\t\t\t})\n\t\t\t.catch(err => {\n\t\t\t\ttrace.error(`[IdeFetch.${method.toLowerCase()}] ${finalUrl} 실패:`, err);\n\t\t\t\tthrow err;\n\t\t\t})\n\t\t\t.finally(() => {\n\t\t\t\tif (showLoading) {\n\t\t\t\t\tLoading.hide();\n\t\t\t\t}\n\t\t\t});\n\t};\n\n\t// 기존 post/get 메서드도 인자를 넘겨주도록 수정\n\tstatic get = (url, data = {}, showLoading = true) => this.#request(\"GET\", url, data, showLoading);\n\tstatic post = (url, data = {}, showLoading = true) => this.#request(\"POST\", url, data, showLoading);\n\n\t/**\n\t * 🚀 범용 청크 전송 (파라미터 이름까지 동적 설정)\n\t * @param {string} url - API 주소\n\t * @param {Array} rows - 데이터 배열\n\t * @param {object} options - 상세 옵션\n\t * - fileKey: 객체 내 파일 속성명 (기본: 'fileContents')\n\t * - filePartName: 서버에서 받을 파일 파트명 (기본: 'files')\n\t * - jsonPartName: 서버에서 받을 JSON 파트명 (기본: 'dataList')\n\t * - chunkSize: 분할 단위 (기본: 10)\n\t */\n\tstatic postMultipart = async (url, rows = [], options = {}) => {\n\t\tconst {\n\t\t\tfileKey = 'fileContents',\n\t\t\tfilePartName = 'files',\n\t\t\tjsonPartName = 'dataList',\n\t\t\tchunkSize = 10\n\t\t} = options;\n\n\t\t// 1. 시작 전 로딩바 띄우기\n\t\tLoading.show();\n\n\t\tlet totalCount = 0;\n\t\tlet lastResponse = null;\n\n\t\t// 🔴 2. 전체 루프를 Promise 체인처럼 관리 (내부는 await 유지)\n\t\treturn (async () => {\n\t\t\tfor (let i = 0; i < rows.length; i += chunkSize) {\n\t\t\t\tconst formData = new FormData();\n\t\t\t\tconst chunk = rows.slice(i, i + chunkSize);\n\t\t\t\tconst rowDataList = [];\n\n\t\t\t\tchunk.forEach((row) => {\n\t\t\t\t\tconst { [fileKey]: fileObj, _fileObj, ...rest } = row;\n\t\t\t\t\trowDataList.push(rest);\n\t\t\t\t\tif (fileObj instanceof File) {\n\t\t\t\t\t\tformData.append(filePartName, fileObj);\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tconst jsonBlob = new Blob([JSON.stringify(rowDataList)], { type: 'application/json' });\n\t\t\t\tformData.append(jsonPartName, jsonBlob);\n\n\t\t\t\t// showLoading = false로 내부 호출\n\t\t\t\tlastResponse = await this.post(url, formData, false);\n\n\t\t\t\tif (lastResponse && (lastResponse.success || lastResponse.status === 'OK')) {\n\t\t\t\t\ttotalCount += chunk.length;\n\t\t\t\t} else {\n\t\t\t\t\tthrow new Error(`청크 전송 실패: ${i}번째 섹션`);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn { ...lastResponse, success: true, totalCount };\n\t\t})()\n\t\t\t.catch(err => {\n\t\t\t\ttrace.error(\"[postChunk] Error:\", err);\n\t\t\t\tthrow err;\n\t\t\t})\n\t\t\t.finally(() => {\n\t\t\t\t// 🔴 3. 성공하든 실패하든 여기서 깔끔하게 닫기!\n\t\t\t\tLoading.hide();\n\t\t\t});\n\t};\n}\n\nexport const api = Fetch;","/**\r\n * 비동기 함수를 try-catch 없이 안전하게 실행하게 도와주는 유틸리티\r\n * @param {Promise} promise\r\n * @returns {Promise<[any, Error|null]>}\r\n */\r\nexport const safe = async (promise) => {\r\n\ttry {\r\n\t\tconst data = await promise;\r\n\t\treturn [data, null];\r\n\t} catch (err) {\r\n\t\treturn [null, err];\r\n\t}\r\n};","import { trace } from \"@nopeer\";\r\nimport { NineUtil } from \"./dialog/NineUtil.js\";\r\n\r\nclass UxSplitter extends HTMLElement {\r\n\r\n\t#mode;\r\n\r\n\tconstructor() {\r\n\t\tsuper();\r\n\t\tthis.attachShadow({ mode: \"open\" });\r\n\t}\r\n\r\n\tconnectedCallback() {\r\n\r\n\t\tthis.#init();\r\n\t}\r\n\r\n\t#detectMode = (el) => {\r\n\t\tconst prev = el.previousElementSibling;\r\n\t\tconst next = el.nextElementSibling;\r\n\t\tif (!prev || !next) {\r\n\t\t\tthis.#mode = this.classList.contains('h') ? \"h\" : \"v\";\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst prevRect = prev.getBoundingClientRect();\r\n\t\tconst nextRect = next.getBoundingClientRect();\r\n\r\n\t\tif (this.classList.contains('h')) {\r\n\t\t\tthis.#mode = \"h\";\r\n\t\t} else if (this.classList.contains('v')) {\r\n\t\t\tthis.#mode = \"v\";\r\n\t\t} else {\r\n\t\t\tthis.#mode = (Math.abs(prevRect.top - nextRect.top) < 5) ? \"h\" : \"v\";\r\n\t\t}\r\n\t};\r\n\r\n\t#startDrag = (e) => {\r\n\t\te.preventDefault();\r\n\t\te.stopPropagation();\r\n\r\n\t\tconst splitterRect = this.getBoundingClientRect();\r\n\t\tconst isHorizontal = this.#mode === \"h\";\r\n\r\n\t\t// 마우스 포인터와 스플리터 시작점 사이의 거리\r\n\t\tconst clickOffset = isHorizontal\r\n\t\t\t? e.clientX - splitterRect.left\r\n\t\t\t: e.clientY - splitterRect.top;\r\n\r\n\t\tconst dragBar = document.createElement(\"div\");\r\n\t\tdragBar.className = `nx-splitter-drag-bar-${this.#mode}`;\r\n\r\n\t\tObject.assign(dragBar.style, {\r\n\t\t\tposition: \"absolute\",\r\n\t\t\tzIndex: \"999\",\r\n\t\t\tbackground: \"#666\",\r\n\t\t\topacity: \"0.6\",\r\n\t\t\tpointerEvents: \"none\"\r\n\t\t});\r\n\r\n\t\tconst root = this.getRootNode({ composed: true });\r\n\t\tconst parent = root instanceof ShadowRoot ? root.host : this.parentElement;\r\n\t\tconst prev = this.previousElementSibling;\r\n\t\tconst next = this.nextElementSibling;\r\n\r\n\t\tif (!parent || !prev || !next) {\r\n\t\t\ttrace.warn(\"Spliter's parent or siblings not found.\");\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t(parent.shadowRoot || parent).appendChild(dragBar);\r\n\t\tconst dragBarOffsetParentRect = dragBar.offsetParent.getBoundingClientRect();\r\n\r\n\t\tconst prevRect = prev.getBoundingClientRect();\r\n\t\tconst nextRect = next.getBoundingClientRect();\r\n\r\n\t\t// 드래그 바의 초기 위치와 크기 설정\r\n\t\tconst initialSplitterPosInParent = (isHorizontal\r\n\t\t\t? splitterRect.left - dragBarOffsetParentRect.left\r\n\t\t\t: splitterRect.top - dragBarOffsetParentRect.top) + clickOffset;\r\n\r\n\t\tif (isHorizontal) {\r\n\t\t\tdragBar.style.top = \"0\";\r\n\t\t\tdragBar.style.left = `${initialSplitterPosInParent}px`;\r\n\t\t\tdragBar.style.width = \"2px\";\r\n\t\t\tdragBar.style.height = \"100%\";\r\n\t\t} else {\r\n\t\t\tdragBar.style.left = \"0\";\r\n\t\t\tdragBar.style.top = `${initialSplitterPosInParent}px`;\r\n\t\t\tdragBar.style.height = \"2px\";\r\n\t\t\tdragBar.style.width = \"100%\";\r\n\t\t}\r\n\r\n\t\tdragBar.style.mixBlendMode = \"difference\";\r\n\t\tdragBar.style.zIndex = \"99999\";\r\n\r\n\t\tconst minLimit = isHorizontal\r\n\t\t\t? prevRect.left - dragBarOffsetParentRect.left\r\n\t\t\t: prevRect.top - dragBarOffsetParentRect.top;\r\n\t\tconst maxLimit = isHorizontal\r\n\t\t\t? nextRect.right - dragBarOffsetParentRect.left - splitterRect.width\r\n\t\t\t: nextRect.bottom - dragBarOffsetParentRect.top - splitterRect.height;\r\n\r\n\t\tconst onMove = moveEvent => {\r\n\t\t\tconst clientPos = isHorizontal ? moveEvent.clientX : moveEvent.clientY;\r\n\t\t\tconst currentPosInParent = isHorizontal\r\n\t\t\t\t? clientPos - dragBarOffsetParentRect.left\r\n\t\t\t\t: clientPos - dragBarOffsetParentRect.top;\r\n\r\n\t\t\tconst clampedPos = Math.max(minLimit, Math.min(currentPosInParent, maxLimit));\r\n\r\n\t\t\tif (isHorizontal) {\r\n\t\t\t\tdragBar.style.left = `${clampedPos}px`;\r\n\t\t\t} else {\r\n\t\t\t\tdragBar.style.top = `${clampedPos}px`;\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\tconst onUp = () => {\r\n\t\t\twindow.removeEventListener(\"mousemove\", onMove);\r\n\t\t\twindow.removeEventListener(\"mouseup\", onUp);\r\n\t\t\tdragBar.remove();\r\n\r\n\t\t\tconst allChildren = Array.from(parent.children);\r\n\t\t\tconst allPanels = allChildren.filter(el => el.tagName.toLowerCase() !== 'nx-splitter');\r\n\r\n\t\t\t// ⭐⭐ gap 크기 계산 ⭐⭐\r\n\t\t\tconst style = window.getComputedStyle(parent);\r\n\t\t\tconst gapValue = isHorizontal ? style.getPropertyValue('column-gap') : style.getPropertyValue('row-gap');\r\n\t\t\tconst gapSize = parseFloat(gapValue) || 0;\r\n\t\t\tconst gapCount = allChildren.length > 1 ? allChildren.length - 1 : 0;\r\n\t\t\tconst totalGapSize = gapCount * gapSize;\r\n\r\n\t\t\tconst finalDragBarPos = isHorizontal ? parseFloat(dragBar.style.left) : parseFloat(dragBar.style.top);\r\n\t\t\tconst dragOffset = finalDragBarPos - initialSplitterPosInParent;\r\n\r\n\t\t\tconst prevSize = isHorizontal ? prev.getBoundingClientRect().width : prev.getBoundingClientRect().height;\r\n\t\t\tconst nextSize = isHorizontal ? next.getBoundingClientRect().width : next.getBoundingClientRect().height;\r\n\r\n\t\t\tlet newPrevSize = prevSize + dragOffset;\r\n\t\t\tlet newNextSize = nextSize - dragOffset;\r\n\r\n\t\t\t// 패널 크기가 음수가 되지 않도록 제한하고, 다른 패널에 차이를 보정\r\n\t\t\tif (newPrevSize < 0) {\r\n\t\t\t\tnewNextSize += newPrevSize;\r\n\t\t\t\tnewPrevSize = 0;\r\n\t\t\t}\r\n\t\t\tif (newNextSize < 0) {\r\n\t\t\t\tnewPrevSize += newNextSize;\r\n\t\t\t\tnewNextSize = 0;\r\n\t\t\t}\r\n\r\n\t\t\tconst initialSizes = allPanels.map(panel => isHorizontal ? panel.getBoundingClientRect().width : panel.getBoundingClientRect().height);\r\n\r\n\t\t\tconst totalSplitterSize = allChildren.reduce((sum, child) => {\r\n\t\t\t\tif (child.tagName.toLowerCase() === 'nx-splitter') {\r\n\t\t\t\t\treturn sum + (isHorizontal ? child.getBoundingClientRect().width : child.getBoundingClientRect().height);\r\n\t\t\t\t}\r\n\t\t\t\treturn sum;\r\n\t\t\t}, 0);\r\n\r\n\t\t\tconst totalContainerSize = (isHorizontal ? parent.getBoundingClientRect().width : parent.getBoundingClientRect().height);\r\n\t\t\tconst totalFlexSpace = totalContainerSize - totalSplitterSize - totalGapSize;\r\n\r\n\t\t\tlet flexSum = 0;\r\n\t\t\tallPanels.forEach((panel, index) => {\r\n\t\t\t\tlet newSize;\r\n\t\t\t\tif (panel === prev) {\r\n\t\t\t\t\tnewSize = newPrevSize;\r\n\t\t\t\t} else if (panel === next) {\r\n\t\t\t\t\tnewSize = newNextSize;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tnewSize = initialSizes[index];\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst newFlexBasis = newSize / totalFlexSpace;\r\n\t\t\t\t//panel.style.flex = `${newFlexBasis} ${newFlexBasis} 0`;\r\n\r\n\t\t\t\ttrace.log(panel);\r\n\r\n\t\t\t\tif (panel.classList.contains('sidebar')) {\r\n\t\t\t\t\t// 드래그가 끝난 시점의 newSize(px)를 그대로 고정값으로 할당\r\n\t\t\t\t\t// 이렇게 하면 비율(%)이 아니라 딱 그 픽셀만큼만 자리를 차지하게 됩니다.\r\n\t\t\t\t\tpanel.style.flex = `0 0 ${newSize}px`;\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// 나머지 메인 보드 같은 유연한 패널은 비율(%)로 처리\r\n\t\t\t\t\t//const newFlexBasis = newSize / totalFlexSpace;\r\n\t\t\t\t\tpanel.style.flex = `${newFlexBasis} ${newFlexBasis} 0`;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tflexSum += newFlexBasis;\r\n\t\t\t});\r\n\r\n\t\t\ttrace.log(`dragOffset: ${dragOffset}`);\r\n\t\t\ttrace.log(`Calculated FlexSum: ${flexSum}`);\r\n\t\t};\r\n\r\n\t\twindow.addEventListener(\"mousemove\", onMove);\r\n\t\twindow.addEventListener(\"mouseup\", onUp);\r\n\t};\r\n\r\n\tget cssPath() {\r\n\t\treturn this.getAttribute(\"css-path\") || NineUtil.cssPath;\r\n\t}\r\n\r\n\t#init = () => {\r\n\t\tthis.#detectMode(this);\r\n\t\tthis.classList.add(this.#mode);\r\n\r\n\t\tconst contents = this.innerHTML.trim();\r\n\t\t//const gripClass = `grip-${this.#mode}`;\r\n\t\tconst gripTmpl = (contents === \"\") ? `<div class=\"grip\"></div>` : `<div class=\"grip\"></div><div class=\"inner-container\">${contents}</div><div class=\"grip\"></div>`;\r\n\r\n\t\tthis.innerHTML = \"\";\r\n\t\tconst htmlTmpl = document.createElement(\"template\");\r\n\t\thtmlTmpl.innerHTML = `\r\n\t\t\t<style>\r\n\t\t\t\t@import \"https://cdn.jsdelivr.net/npm/@nine-lab/nine-util@${__APP_VERSION__}/dist/css/nine-util.css\";\r\n\t\t\t\t${this.cssPath ? `@import \"${this.cssPath}\";` : \"\"}\r\n\t\t\t</style>\r\n\t\t\t${gripTmpl}\r\n `;\r\n\r\n\t\tthis.shadowRoot.appendChild(htmlTmpl.content.cloneNode(true));\r\n\r\n\t\tthis.shadowRoot.querySelectorAll(\".grip\").forEach(el => {\r\n\t\t\tel.addEventListener(\"mousedown\", e => this.#startDrag(e));\r\n\t\t});\r\n\r\n\t\tthis.#prepareLayout();\r\n\r\n\t\twindow.addEventListener(\"resize\", () => this.#prepareLayout());\r\n\t};\r\n\r\n\t#prepareLayout = () => {\r\n\t\tconst isHorizontal = this.#mode === \"h\";\r\n\t\tconst parent = this.parentElement;\r\n\t\tconst allPanels = Array.from(parent.children).filter(el => el.tagName.toLowerCase() !== 'nx-splitter');\r\n\t\tif (allPanels.length < 2) return;\r\n\r\n\t\tconst parentRect = parent.getBoundingClientRect();\r\n\t\tconst totalContentSize = allPanels.reduce((sum, el) => {\r\n\t\t\tconst size = isHorizontal ? el.getBoundingClientRect().width : el.getBoundingClientRect().height;\r\n\t\t\treturn sum + size;\r\n\t\t}, 0);\r\n\t\tconst totalParentSize = isHorizontal ? parentRect.width : parentRect.height;\r\n\r\n\t\tallPanels.forEach(panel => {\r\n\t\t\tconst size = isHorizontal ? panel.getBoundingClientRect().width : panel.getBoundingClientRect().height;\r\n\t\t\tconst newSize = totalParentSize * (size / totalContentSize);\r\n\t\t\tconst flexGrow = newSize / totalParentSize;\r\n\t\t\tpanel.style.flex = `${flexGrow} ${flexGrow} 0`;\r\n\t\t});\r\n\t};\r\n}\r\n\r\nif (!customElements.get('nine-splitter')) {\r\n\tcustomElements.define(\"nine-splitter\", UxSplitter);\r\n}","// 1. 기존 core 모듈\r\nimport { NineUtil } from './ux/dialog/NineUtil.js';\r\nimport { nine, subscribeConfig, config } from './core/Config.js';\r\nimport { Trace, trace } from './core/Trace.js';\r\nimport { TaskDebouncer } from './core/TaskDebouncer.js';\r\n\r\n// 2. 신규 net 및 ux 모듈 추가\r\nimport { api, Fetch } from './net/Fetch.js';\r\nimport { Loading } from './ux/Loading.js';\r\n\r\nimport { nineDialog } from './ux/dialog/nineDialog.js';\r\nimport { nineConfirmPopup, nineAlertPopup } from './ux/dialog/nineConfirm.js';\r\nimport { ninePromptPopup } from './ux/dialog/ninePrompt.js';\r\n\r\nimport { safe } from \"./utils/promise.js\"; // 경로에 맞춰 임포트\r\n// ux\r\nimport './ux/UxSplitter.js';\r\n\r\nconst utilInstance = new NineUtil();\r\nnine.alert = utilInstance.alert.bind(utilInstance);\r\nnine.confirm = utilInstance.confirm.bind(utilInstance);\r\nnine.prompt = utilInstance.prompt.bind(utilInstance);\r\n\r\nnine.safe = safe;\r\n\r\n// 기존 nine 객체(Config)와 Util 기능을 합성\r\n//Object.assign(nine, utilInstance);\r\n\r\nnine.api = api;\r\nnine.trace = trace;\r\nnine.subscribeConfig = subscribeConfig;\r\nnine.config = config || {};\r\n\r\nexport {\r\n\tnine,\r\n\tsubscribeConfig,\r\n\tconfig,\r\n\tNineUtil,\r\n\tTrace,\r\n\ttrace,\r\n\tTaskDebouncer,\r\n\tapi, // 🚀 추가: 이제 서비스에서 api.get() 가능\r\n\tFetch, // 🚀 추가: 클래스 자체도 혹시 모르니 노출\r\n\tLoading as loading, // 🚀 추가: loading.show() 로 쓰기 편하게 alias\r\n\tnineDialog,\r\n\tnineAlertPopup, nineConfirmPopup, ninePromptPopup\r\n};\r\n\r\nif (typeof window !== 'undefined') {\r\n\twindow.nine = nine;\r\n}\r\n"],"names":["_init","_a","config","el","trace","Trace","traceOrigin"],"mappings":";;;;;;;;;;;AAAA,8PAAAA,QAAA;AACO,MAAM,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA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"}
@@ -1,2 +1,2 @@
1
- !function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n((t="undefined"!=typeof globalThis?globalThis:t||self)["nine-util"]={})}(this,function(t){"use strict";var n,e,o,i,s,a,r,l,c,d,h,p,g,u,m,f,v,w,b,x,y,k,E,L=Object.defineProperty,C=t=>{throw TypeError(t)},R=(t,n,e)=>((t,n,e)=>n in t?L(t,n,{enumerable:!0,configurable:!0,writable:!0,value:e}):t[n]=e)(t,"symbol"!=typeof n?n+"":n,e),M=(t,n,e)=>n.has(t)||C("Cannot "+e),$=(t,n,e)=>(M(t,n,"read from private field"),e?e.call(t):n.get(t)),S=(t,n,e)=>n.has(t)?C("Cannot add the same private member more than once"):n instanceof WeakSet?n.add(t):n.set(t,e),B=(t,n,e,o)=>(M(t,n,"write to private field"),o?o.call(t,e):n.set(t,e),e),z=(t,n,e)=>(M(t,n,"access private method"),e);const T=new Set,A={ux:{nativeOverride:!1,theme:"light"},board:{readOnly:!1},cssPath:"",debug:!1};"undefined"==typeof window||window.__NINE_GLOBAL_CONFIG__||(window.__NINE_GLOBAL_CONFIG__=A);const P="undefined"!=typeof window?window.__NINE_GLOBAL_CONFIG__:A,W=t=>(T.add(t),t("all",P),()=>T.delete(t)),_=new Proxy(P,{set:(t,n,e)=>(t[n]=e,T.forEach(e=>e(n,t)),!0),get:(t,n)=>t[n]}),N={config:_,get cssPath(){return this.config.cssPath||""},setup(t={}){Object.entries(t).forEach(([t,n])=>{"object"!=typeof n||null===n||Array.isArray(n)?this.config[t]=n:this.config[t]={...this.config[t],...n}}),"undefined"!=typeof window&&(window.nine=window.nine||this)}};class X extends HTMLElement{constructor(){super(),S(this,n),S(this,e),R(this,"showModal",()=>{$(this,e).showModal()}),R(this,"close",()=>{$(this,e).close(),this.remove()}),S(this,o,()=>{this.querySelector(".head"),this.querySelectorAll(".close, .close2, .cancel").forEach(t=>{t.onclick=()=>this.closeWithAnimation(null)}),this.querySelectorAll(".ok").forEach(t=>{})}),S(this,i,t=>{if(t.target.closest("buttons"))return;if(0!==t.button||t.altKey||t.ctrlKey||t.shiftKey)return;const o=$(this,e).getBoundingClientRect();B(this,n,{x:t.clientX-o.left,y:t.clientY-o.top});const i=t=>{$(this,e).style.position="fixed",$(this,e).style.margin="0",$(this,e).style.left=t.clientX-$(this,n).x+"px",$(this,e).style.top=t.clientY-$(this,n).y+"px"},s=()=>{document.removeEventListener("mousemove",i),document.removeEventListener("mouseup",s)};document.addEventListener("mousemove",i),document.addEventListener("mouseup",s)}),S(this,s,t=>{if(t.target.closest("buttons"))return;const o=$(this,e).getBoundingClientRect(),i=t.changedTouches[0];B(this,n,{x:i.pageX-o.left,y:i.pageY-o.top});const s=t=>{const o=t.changedTouches[0];$(this,e).style.position="fixed",$(this,e).style.margin="0",$(this,e).style.left=o.pageX-$(this,n).x+"px",$(this,e).style.top=o.pageY-$(this,n).y+"px"},a=()=>{document.removeEventListener("touchmove",s),document.removeEventListener("touchend",a)};document.addEventListener("touchmove",s),document.addEventListener("touchend",a)})}connectedCallback(){const t=this.innerHTML,n=this.getAttribute("title")||"Details";trace.log("111111111"),this.innerHTML=`\n\t\t\t<style>\n\tdialog::backdrop {\n\t\tbackground: rgba(0, 0, 0, 0.3);\n\t}\n\t\n\tdialog:modal {\n\t\tdisplay: flex;\n\t\tflex-direction: column;\n\t\tpadding: 0;\n\t\toverflow: hidden;\n\t\tborder: 1px solid darkgreen;\n\t\toutline: none;\n\t\tresize: both;\n\t\tbox-shadow: 0 0 4px 0 darkgreen;\n width: 500px;\n height: 150px;\n min-width: 330px;\n min-height: 60px;\n }\n \n \n \n \n\tdiv.head .rect1, div.head .rect2, div.head .rect3 {\n\t\tdisplay: none;\n\t\twidth: 50px;\n\t\theight: 100%;\n\t}\n\tdiv.head .rect1 {\n\t\tbackground-color: red;\n\t}\n\tdiv.head .rect2 {\n\t\tbackground-color: darkgreen;\n\t}\n\tdiv.head .rect3 {\n\t\tbackground-color: olive;\n\t}\n\t\n\tdiv.head {\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\t--height: 30px;\n\t\tbackground-color: darkgreen;\n\t\tpadding: 4px;\n\t\tcursor: move;\n\t}\n\tdiv.head:hover {\n\t\tfilter: brightness(110%);\n\t}\n\t\n\tdiv.head span {\n\t\tfont-size: 12px;\n\t\tposition: relative;\n\t}\n\t\n\tdiv.head span.title {\n\t\tcolor: #ddd;\n\t\tmargin-left: 4px;\n\t\tfont-weight: bold;\n\t}\n\t\n\tdiv.head span.sub-title {\n\t\tcolor: #ccc;\n\t\tmargin-left: 8px;\n\t\tfont-style: italic;\n\t}\n\t\n\tdiv.head form {\n\t\tmargin: 0;\n\t}\n\tdiv.head button {\n\t\tmargin-right: 4px;\n\t\tbackground-color: transparent;\n\t\tborder: none;\n\t\tcolor: #ccc;\n\t\tfont-size: x-small;\n\t}\n\tdiv.head button:hover {\n\t\tcursor: pointer;\n\t}\n\t\n\tdiv.contents {\n\t\tdisplay: flex;\n\t\twidth: 100%;\n\t\theight: 100%;\n\t\toverflow: hidden;\n\t}\n\tdiv.left {\n\t\tposition: relative;\n\t\twidth: 16px;\n\t\theight: 100%;\n\t\tbackground-color: #ddd;\n\t\tdisplay: none;\n\t}\n\t\n\tdiv.left span {\n\t\twriting-mode: vertical-rl;\n\t\t-moz-user-select: none;\n\t\t-webkit-user-select: none;\n\t\t-ms-user-select: none;\n\t\tuser-select: none;\n\t\tcolor: #ccc;\n\t\tfont-weight: 700;\n\t\twidth: 100%;\n\t\theight: 100%;\n\t\tmargin-left: 3px;\n\t\tmargin-top: 3px;\n\t}\n\tdiv.close2 {\n\t\tdisplay: none;\n\t\tposition: absolute;\n\t\tright: 0;\n\t\ttop: 3px;\n\t\tcursor: pointer;\n\t\tcolor: #666;\n\t}\n\tdiv.close2 svg:hover {\n\t\tcolor: #999;\n\t}\n\t\n\tdiv.body {\n\t\tdisplay: flex;\n\t\twidth: 100%;\n\t\theight: unset;\n\t\t--border: 3px solid #999;\n\t\t--border-top: none;\n\t\toverflow-x: hidden;\n\t\toverflow-y: auto;\n\t\tpadding: 10px;\n\t\tgap: 8px;\n\t\tflex-direction: column;\n\t}\n\t\n\t\n\t\n\t\n\tng-sphere.icon {\n\t\tmargin-left: 8px;\n\t}\n\t\n\t.buttons {\n\t\tdisplay: flex;\n\t\tposition: absolute;\n\t\tright: 4px;\n\t}\n\t\n\tng-sphere {\n\t\tposition: relative;\n\t\t--width: 16px;\n\t\t--height: 16px;\n\t\tcursor: pointer;\n\t\tmargin-right: 4px;\n\t\tdisplay: flex;\n\t}\n\tng-sphere:hover {\n\t\tfilter: brightness(90%);\n\t}\n\tng-sphere:active {\n\t\tfilter: brightness(80%);\n\t}\n\t\n\tng-sphere:hover::after {\n\t\tcontent: "";\n\t\tposition: absolute;\n\t\twidth: 100%;\n\t\theight: 100%;\n\t\tbackground-repeat: no-repeat;\n\t\tbackground-position: center;\n\t}\n\tng-sphere.apply:hover::after {\n\t\tbackground-size: 14px 14px;\n\t\tbackground-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg"><polyline points="2.5,7 6,10 11,3" style="fill:none;stroke:white;stroke-width:2px;" /></svg>');\n\t}\n\t\n\tng-sphere.reset:hover::after {\n\t\tbackground-size: 12px 12px;\n\t\tbackground-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" style="fill:none;stroke:white;stroke-width:2px;" focusable="false" aria-hidden="true"><path d="M10 5h5V0"></path><path d="M15 8a6.957 6.957 0 0 1-7 7 6.957 6.957 0 0 1-7-7 6.957 6.957 0 0 1 7-7 6.87 6.87 0 0 1 6.3 4"></path></svg>');\n\t}\n\t\n\tng-sphere.close:hover::after {\n\t\tbackground-size: 12px 12px;\n\t\tbackground-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" style="fill:none;stroke:white;stroke-width:2px;" focusable="false" aria-hidden="true" viewBox="0 0 16 16"><path d="M2 2l12 12M14 2L2 14"></path></svg>');\n\t}\n\t\n\t\n\tbutton {\n cursor: pointer;\n }\n \n .input-area {\n position: relative;\n height: 100%;\n --display: flex;\n textarea {\n width: 100%;\n height: 100%;\n min-height: 100px;\n padding: 8px;\n box-sizing: border-box;\n resize: none;\n border-radius: 2px;\n border-color: #ccc;\n }\n textarea:focus {\n border-color: green;\n outline: none; /* 브라우저 기본 파란색 테두리 제거 */\n }\n }\n \n .buttons-confirm {\n position: relative;\n display: flex;\n justify-content: flex-end;\n --bottom: 8px;\n --right: 8px;\n }\n \n \n .buttons-confirm button {\n height: 32px;\n margin-right: 8px;\n border: none;\n outline: none;\n width: 60px;\n -moz-user-select: none;\n -webkit-user-select: none;\n -ms-user-select: none;\n user-select: none;\n }\n .buttons-confirm button:hover {\n filter: brightness(90%);\n }\n .buttons-confirm button:active {\n color: #ccc;\n }\n \n button.ok {\n --display: none;\n background-color: darkgreen;\n color: white;\n }\n button.cancel {\n color: white;\n background-color: #6c757d;\n }\n \n \n \n div.msg {\n position: relative;\n height: 100%;\n font-size: 14px;\n color: #333;\n }\n \n .reset, .apply {\n display: none;\n }\n \n \n \n :host(.classic) dialog:modal {\n border: 1px solid #007bff;\n box-shadow: 0 0 4px 0 #007bff;\n }\n \n :host(.classic) div.head {\n background-color: #007bff;\n }\n :host(.classic) div.head:hover {\n filter: brightness(110%);\n }\n \n :host(.classic) div.head span {\n font-size: 12px;\n }\n \n :host(.classic) div.head span.title {\n color: #ddd;\n margin-left: 4px;\n font-weight: bold;\n }\n \n :host(.classic) div.head span.sub-title {\n color: #ccc;\n margin-left: 8px;\n font-style: italic;\n }\n :host(.classic) div.head button {\n margin-right: 4px;\n background-color: transparent;\n border: none;\n color: #ccc;\n font-size: x-small;\n }\n \n \n \n \n :host(.rgb) dialog:modal {\n border: none;\n box-shadow: unset;\n border-top: none;\n }\n \n :host(.rgb) div.left {\n display: block;\n background-color: #ddd;\n }\n :host(.rgb) div.left span {\n color: #ccc;\n }\n :host(.rgb) div.close2 {\n display: block;\n color: #666;\n }\n :host(.rgb) div.close2 svg:hover {\n color: #999;\n }\n :host(.rgb) div.head {\n height: 4px;\n background-color: #999;\n padding: 0;\n }\n :host(.rgb) div.contents {\n height: calc(100% - 4px);\n }\n \n :host(.rgb) div.head ng-sphere,\n :host(.rgb) div.head span,\n :host(.rgb) div.head .buttons {\n display: none;\n }\n \n :host(.rgb) div.head .rect1,\n :host(.rgb) div.head .rect2,\n :host(.rgb) div.head .rect3 {\n display: flex;\n }\n \n \n :host(.rgb) div.head:hover {\n filter: unset;\n }\n \n \n /* --- Animation Core --- */\n:host {\n --nx-duration: 0.4s;\n --nx-timing: cubic-bezier(0.34, 1.56, 0.64, 1);\n}\n\n/* 🎯 수정: 애니메이션 클래스가 붙은 경우에만 초기 opacity를 0으로 설정 */\n:host(.fade) dialog,\n:host(.zoom) dialog,\n:host(.moveUp) dialog,\n:host(.moveDown) dialog,\n:host(.moveLeft) dialog,\n:host(.moveRight) dialog,\n:host(.roadRunner) dialog {\n opacity: 0;\n}\n\n/* shake는 애니메이션 내부에서 opacity를 다루므로 제외하거나 별도 처리 */\n:host(.shake) dialog { \n opacity: 1; \n}\n\n/* 1. Fade (서서히 나타남) */\n:host(.fade) dialog { animation: nx-fade-in var(--nx-duration) forwards; }\n@keyframes nx-fade-in { from { opacity: 0; } to { opacity: 1; } }\n\n/* 2. Zoom (커지며 나타남) */\n:host(.zoom) dialog { animation: nx-zoom-in var(--nx-duration) var(--nx-timing) forwards; }\n@keyframes nx-zoom-in { from { opacity: 0; transform: scale(0.5); } to { opacity: 1; transform: scale(1); } }\n\n/* 3. Slide (상하좌우) */\n:host(.moveUp) dialog { animation: nx-move-up var(--nx-duration) var(--nx-timing) forwards; }\n:host(.moveDown) dialog { animation: nx-move-down var(--nx-duration) var(--nx-timing) forwards; }\n:host(.moveLeft) dialog { animation: nx-move-left var(--nx-duration) var(--nx-timing) forwards; }\n:host(.moveRight) dialog { animation: nx-move-right var(--nx-duration) var(--nx-timing) forwards; }\n\n@keyframes nx-move-up { from { opacity: 0; transform: translateY(100px); } to { opacity: 1; transform: translateY(0); } }\n@keyframes nx-move-down { from { opacity: 0; transform: translateY(-100px); } to { opacity: 1; transform: translateY(0); } }\n@keyframes nx-move-left { from { opacity: 0; transform: translateX(100px); } to { opacity: 1; transform: translateX(0); } }\n@keyframes nx-move-right { from { opacity: 0; transform: translateX(-100px); } to { opacity: 1; transform: translateY(0); } }\n\n/* 4. Shake (상하좌우 격렬한 진동 - 에러 인지용) */\n:host(.shake) dialog { \n animation: nx-heavy-shake 0.5s cubic-bezier(.36,.07,.19,.97) both;\n opacity: 1; \n}\n\n@keyframes nx-heavy-shake {\n 10%, 90% { transform: translate3d(-1px, -2px, 0); }\n 20%, 80% { transform: translate3d(2px, 4px, 0); }\n 30%, 50%, 70% { transform: translate3d(-6px, -6px, 0); }\n 40%, 60% { transform: translate3d(6px, 6px, 0); }\n}\n\n/* 5. Road Runner (등장: 왼쪽에서 탄력 있게 / 퇴장: 움츠렸다가 광속 탈출) */\n:host(.roadRunner) dialog { \n animation: roadRunnerIn 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards; \n}\n\n@keyframes roadRunnerIn {\n 0% { transform: translateX(-1500px) skewX(30deg); opacity: 1; }\n 70% { transform: translateX(30px) skewX(-10deg); opacity: 1; }\n 100% { transform: translateX(0) skewX(0deg); opacity: 1; }\n}\n\n/* --- Out Animations (닫힐 때) --- */\ndialog.out { pointer-events: none; }\n\n/* Road Runner 퇴장: 슥 움츠렸다가(Anticipation) 쌩~! */\n:host(.roadRunner) dialog.out { \n animation: roadRunnerOut 0.5s cubic-bezier(0.6, -0.28, 0.735, 0.045) forwards; \n}\n\n@keyframes roadRunnerOut {\n 0% { \n transform: translateX(0) scale(1) skewX(0deg); \n opacity: 1; \n }\n 30% { \n /* 예비 동작: 뒤로 살짝 갔다가 움츠러들기 */\n transform: translateX(50px) scaleX(1.2) scaleY(0.8) skewX(-20deg); \n opacity: 1; \n }\n 100% { \n /* 발사: 길게 늘어나며 광속 탈출 */\n transform: translateX(2000px) scaleX(4) scaleY(0.3) skewX(50deg); \n opacity: 0; \n filter: blur(10px); /* 👈 잔상 느낌 추가 */\n }\n}\n\n/* 일반 퇴장 (기본) */\ndialog.out { animation: nx-fade-out 0.3s forwards; }\n@keyframes nx-fade-out { from { opacity: 1; transform: scale(1); } to { opacity: 0; transform: scale(0.9); } }\n</style>\n\t\t\n\t\t\t<dialog>\n\t\t\t\t<div class="head">\n\t\t\t\t\t<div class="rect1"></div>\n\t\t\t\t\t<div class="rect2"></div>\n\t\t\t\t\t<div class="rect3"></div>\n\t\t\t\t\t<ng-sphere class="icon" end-fill="#666" size="8"></ng-sphere>\n\t\t\t\t\t<span class="title">${n}</span>\n\t\t\t\t\t<span class="sub-title"></span>\n\t\t\t\t\t<div class="buttons">\n\t\t\t\t\t\t<ng-sphere class="apply" start-fill="#cc6" end-fill="#660" size="16" title="apply"></ng-sphere>\n\t\t\t\t\t\t<ng-sphere class="reset" start-fill="#99f" end-fill="#00f" size="16" title="reset"></ng-sphere>\n\t\t\t\t\t\t<ng-sphere class="close" start-fill="#f99" end-fill="#f00" size="16" title="close"></ng-sphere>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div class="contents">\n\t\t\t\t\t<div class="left">\n\t\t\t\t\t\t<span>가나다라마바사아자차카타파하가나다라마바사아자차카타파하가나다라마바사아자차카타파하가나다라마바사아자차카타파하가나다라마바사아자차카타파하가나다라마바사아자차카타파하가나다라마바사아자차카타파하가나다라마바사아자차카타파하</span>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class="body">\n\t\t\t\t\t\t${t}\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class="close2">\n\t\t\t\t\t\t<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">\n\t\t\t\t\t\t\t<path d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708"/>\n\t\t\t\t\t\t</svg>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</dialog>\n\t\t`,B(this,e,this.querySelector("dialog")),$(this,o).call(this)}closeWithAnimation(t){$(this,e).classList.add("out"),setTimeout(()=>{$(this,e).close(),this.dispatchEvent(new CustomEvent("closed",{detail:t})),this.remove()},300)}}n=new WeakMap,e=new WeakMap,o=new WeakMap,i=new WeakMap,s=new WeakMap;class O extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"})}static async open(t,n,e,o,i){var s,a,r;const l=t.tagName.toLowerCase(),c={"true-text":"확인","false-text":"취소",class:"classic",animation:"fade",...(null==(r=null==(a=null==(s=window.nine)?void 0:s.config)?void 0:a.ux)?void 0:r[l.replace("nine-","").replace("-popup","")])||{},...o};document.querySelectorAll(l).forEach(t=>t.remove());const d=document.createElement(l);c.class&&d.classList.add(c.class),c.animation&&d.classList.add(c.animation),document.body.appendChild(d),i(d,n,c);const h=d.shadowRoot.querySelector("nine-dialog");return e&&h.setAttribute("title",e),new Promise(t=>{h.addEventListener("closed",n=>t(n.detail)),d.setupEvents(t,h),h.showModal()})}}customElements.get("nine-dialog")||customElements.define("nine-dialog",X);const F=class extends O{constructor(){super()}render(t,n){this.shadowRoot.innerHTML=`\n <nine-dialog>\n <div class="msg">${t.replace(/\n/g,"<br/>")}</div>\n <div class="buttons-confirm">\n <button class="cancel">${n["false-text"]}</button>\n <button class="ok">${n["true-text"]}</button>\n </div>\n </nine-dialog>`}setupEvents(t,n){this.shadowRoot.querySelector(".ok").onclick=()=>n.closeWithAnimation(!0)}};R(F,"tagName","nine-confirm-popup"),R(F,"confirm",(t,n,e)=>O.open(F,t,n,e,(t,n,e)=>t.render(n,e)));let I=F;const j=class extends O{constructor(){super()}render(t,n){this.shadowRoot.innerHTML=`\n <nine-dialog>\n <div class="msg">${t.replace(/\n/g,"<br/>")}</div>\n <div class="buttons-confirm">\n <button class="cancel">확인</button>\n </div>\n </nine-dialog>`}setupEvents(t,n){}};R(j,"tagName","nine-alert-popup"),R(j,"alert",(t,n,e)=>O.open(j,t,n,e,(t,n,e)=>t.render(n,e)));let H=j;customElements.get("nine-confirm-popup")||customElements.define("nine-confirm-popup",I),customElements.get("nine-alert-popup")||customElements.define("nine-alert-popup",H);const Y=class extends O{constructor(){super()}render(t,n){trace.log(this),trace.log(this.shadowRoot),this.shadowRoot.innerHTML=`\n\t\t\t<style>\n\t\t\t\tdialog {\n\t\t\t\t\theight: 300px !important;\n\t\t\t\t}\n\t\t\t\t.msg {\n\t\t\t\t\theight: unset !important;\n\t\t\t\t}\n\t\t\t</style>\n\t\t\t\n <nine-dialog>\n <div class="msg">${t.replace(/\n/g,"<br/>")}</div>\n <div class="input-area">\n <textarea placeholder="내용을 입력하세요..."></textarea>\n </div>\n <div class="buttons-confirm">\n <button class="cancel">${n["false-text"]}</button>\n <button class="ok">${n["true-text"]}</button>\n </div>\n </nine-dialog>`}setupEvents(t,n){const e=this.shadowRoot.querySelector("textarea");this.shadowRoot.querySelector(".ok").onclick=()=>n.closeWithAnimation(e.value),requestAnimationFrame(()=>e.focus())}};R(Y,"tagName","nine-prompt-popup"),R(Y,"prompt",(t,n,e)=>O.open(Y,t,n,e,(t,n,e)=>t.render(n,e)));let q=Y;customElements.get("nine-prompt-popup")||customElements.define("nine-prompt-popup",q);class D{constructor(){S(this,a)}alert(t,n="Alert"){return z(this,a,r).call(this,"alert",t,n,"classic")}confirm(t,n="Confirm"){return z(this,a,r).call(this,"confirm",t,n,"classic")}prompt(t,n="Prompt"){return z(this,a,r).call(this,"prompt",t,n,"classic")}}a=new WeakSet,r=function(t,n,e,o){const i={class:o,animation:"fade"};let s=!1;const a={alert:H,confirm:I,prompt:q}[t],r={rgb:()=>(i.class="rgb",r),classic:()=>(i.class="classic",r),shake:()=>(i.animation="shake",r),run:()=>(i.animation="roadRunner",r),zoom:()=>(i.animation="zoom",r),then:(o,r)=>(s=!0,a[t](n,e,i).then(o,r))};return Promise.resolve().then(()=>{s||(s=!0,a[t](n,e,i))}),r},R(D,"cssPath","");class G{constructor(t=null,n="green"){S(this,h),S(this,l),S(this,c),S(this,d,!0),B(this,l,t),B(this,c,n),z(this,h,p).call(this)}initBAK(t,n="green"){B(this,l,t),B(this,c,n)}init(t,n="green"){return B(this,l,t),B(this,c,n),this}get log(){const t=`color: ${$(this,c)}; font-weight: bold;`;return $(this,l)?console.log.bind(console,`%c[${$(this,l)}]`,t):console.log.bind(console)}get warn(){return $(this,d)?$(this,l)?console.warn.bind(console,`%c[${$(this,l)}]`,"color: cyan; font-weight: bold;"):console.warn.bind(console):()=>{}}get error(){return $(this,l)?console.error.bind(console,`%c[${$(this,l)}]`,"color: red; font-weight: bold;"):console.error.bind(console)}enable(){B(this,d,!0)}disable(){B(this,d,!1)}}l=new WeakMap,c=new WeakMap,d=new WeakMap,h=new WeakSet,p=function(){if("undefined"==typeof window)return;"localhost"===window.location.hostname||"127.0.0.1"===window.location.hostname||window.location.hostname.startsWith("192.168.")?this.enable():(this.disable(),console.log(`%c[${$(this,l)||"Trace"}]%c 운영 모드: 로그 비활성화. %ctrace.enable()%c 로 활성화 가능`,"color: #4CAF50; font-weight: bold;","","background: #333; color: yellow; padding: 2px 5px;",""))};const K=new G;"undefined"!=typeof window&&(window.trace=K);g=new WeakMap,u=new WeakMap,m=new WeakMap,f=new WeakSet,v=function(){if(0===$(this,u).length)return;const t=$(this,u).splice(0,$(this,u).length),n=new Set;t.forEach(t=>{const e=`${t.func.name}_${JSON.stringify(t.args)}`;n.has(e)||(t.func(...t.args),n.add(e))}),B(this,g,null)};class U{static show(){let t=document.getElementById("global-loading-overlay");if(!t&&(t=document.createElement("div"),t.id="global-loading-overlay",t.style.cssText="\n position: fixed; inset: 0; z-index: 9999;\n background: rgba(0, 0, 0, 0.4); display: flex; \n justify-content: center; align-items: center;\n backdrop-filter: blur(2px);\n ",t.innerHTML='<div class="loading-spinner"></div>',document.body.appendChild(t),!document.getElementById("nine-util-style"))){const t=document.createElement("style");t.id="nine-util-style",t.innerHTML="\n .loading-spinner {\n width: 48px; height: 48px;\n border: 5px solid rgba(255, 255, 255, 0.3);\n border-top-color: white; border-radius: 50%;\n animation: nine-spin 1s linear infinite;\n }\n @keyframes nine-spin { to { transform: rotate(360deg); } }\n ",document.head.appendChild(t)}t.style.display="flex"}static hide(){const t=document.getElementById("global-loading-overlay");t&&(t.style.display="none")}}const J=class{};w=new WeakMap,R(J,"BASE_URL",window.__API_BASE_URL__||""),S(J,w,(t,n,e={},o=!0)=>{const i=n.startsWith("http")?n:`${J.BASE_URL}${n}`;o&&U.show();const s={};e instanceof FormData||(s["Content-Type"]="application/json");const a={method:t,headers:s};let r=i;return"GET"===t?r+=`?${new URLSearchParams(e)}`:a.body=e instanceof FormData?e:JSON.stringify(e),fetch(r,a).then(async t=>{if(!t.ok){const n=await t.text();throw new Error(`API 오류 (${t.status}): ${n}`)}return t.json()}).catch(n=>{throw K.error(`[IdeFetch.${t.toLowerCase()}] ${i} 실패:`,n),n}).finally(()=>{o&&U.hide()})}),R(J,"get",(t,n={},e=!0)=>{var o;return $(o=J,w).call(o,"GET",t,n,e)}),R(J,"post",(t,n={},e=!0)=>{var o;return $(o=J,w).call(o,"POST",t,n,e)}),R(J,"postMultipart",async(t,n=[],e={})=>{const{fileKey:o="fileContents",filePartName:i="files",jsonPartName:s="dataList",chunkSize:a=10}=e;U.show();let r=0,l=null;return(async()=>{for(let e=0;e<n.length;e+=a){const c=new FormData,d=n.slice(e,e+a),h=[];d.forEach(t=>{const{[o]:n,_fileObj:e,...s}=t;h.push(s),n instanceof File&&c.append(i,n)});const p=new Blob([JSON.stringify(h)],{type:"application/json"});if(c.append(s,p),l=await J.post(t,c,!1),!l||!l.success&&"OK"!==l.status)throw new Error(`청크 전송 실패: ${e}번째 섹션`);r+=d.length}return{...l,success:!0,totalCount:r}})().catch(t=>{throw K.error("[postChunk] Error:",t),t}).finally(()=>{U.hide()})});let V=J;const Z=V;class Q extends HTMLElement{constructor(){super(),S(this,b),S(this,x,t=>{const n=t.previousElementSibling,e=t.nextElementSibling;if(!n||!e)return void B(this,b,this.classList.contains("h")?"h":"v");const o=n.getBoundingClientRect(),i=e.getBoundingClientRect();this.classList.contains("h")?B(this,b,"h"):this.classList.contains("v")?B(this,b,"v"):B(this,b,Math.abs(o.top-i.top)<5?"h":"v")}),S(this,y,t=>{t.preventDefault(),t.stopPropagation();const n=this.getBoundingClientRect(),e="h"===$(this,b),o=e?t.clientX-n.left:t.clientY-n.top,i=document.createElement("div");i.className=`nx-splitter-drag-bar-${$(this,b)}`,Object.assign(i.style,{position:"absolute",zIndex:"999",background:"#666",opacity:"0.6",pointerEvents:"none"});const s=this.getRootNode({composed:!0}),a=s instanceof ShadowRoot?s.host:this.parentElement,r=this.previousElementSibling,l=this.nextElementSibling;if(!a||!r||!l)return void K.warn("Spliter's parent or siblings not found.");(a.shadowRoot||a).appendChild(i);const c=i.offsetParent.getBoundingClientRect(),d=r.getBoundingClientRect(),h=l.getBoundingClientRect(),p=(e?n.left-c.left:n.top-c.top)+o;e?(i.style.top="0",i.style.left=`${p}px`,i.style.width="2px",i.style.height="100%"):(i.style.left="0",i.style.top=`${p}px`,i.style.height="2px",i.style.width="100%"),i.style.mixBlendMode="difference",i.style.zIndex="99999";const g=e?d.left-c.left:d.top-c.top,u=e?h.right-c.left-n.width:h.bottom-c.top-n.height,m=t=>{const n=e?t.clientX:t.clientY,o=e?n-c.left:n-c.top,s=Math.max(g,Math.min(o,u));e?i.style.left=`${s}px`:i.style.top=`${s}px`},f=()=>{window.removeEventListener("mousemove",m),window.removeEventListener("mouseup",f),i.remove();const t=Array.from(a.children),n=t.filter(t=>"nx-splitter"!==t.tagName.toLowerCase()),o=window.getComputedStyle(a),s=e?o.getPropertyValue("column-gap"):o.getPropertyValue("row-gap"),c=parseFloat(s)||0,d=(t.length>1?t.length-1:0)*c,h=(e?parseFloat(i.style.left):parseFloat(i.style.top))-p,g=e?r.getBoundingClientRect().width:r.getBoundingClientRect().height,u=e?l.getBoundingClientRect().width:l.getBoundingClientRect().height;let v=g+h,w=u-h;v<0&&(w+=v,v=0),w<0&&(v+=w,w=0);const b=n.map(t=>e?t.getBoundingClientRect().width:t.getBoundingClientRect().height),x=t.reduce((t,n)=>"nx-splitter"===n.tagName.toLowerCase()?t+(e?n.getBoundingClientRect().width:n.getBoundingClientRect().height):t,0),y=(e?a.getBoundingClientRect().width:a.getBoundingClientRect().height)-x-d;let k=0;n.forEach((t,n)=>{let e;e=t===r?v:t===l?w:b[n];const o=e/y;K.log(t),t.classList.contains("sidebar")?t.style.flex=`0 0 ${e}px`:t.style.flex=`${o} ${o} 0`,k+=o}),K.log(`dragOffset: ${h}`),K.log(`Calculated FlexSum: ${k}`)};window.addEventListener("mousemove",m),window.addEventListener("mouseup",f)}),S(this,k,()=>{$(this,x).call(this,this),this.classList.add($(this,b));const t=this.innerHTML.trim(),n=""===t?'<div class="grip"></div>':`<div class="grip"></div><div class="inner-container">${t}</div><div class="grip"></div>`;this.innerHTML="";const e=document.createElement("template");e.innerHTML=`\n\t\t\t<style>\n\t\t\t\t@import "https://cdn.jsdelivr.net/npm/@nine-lab/nine-util@0.9.125/dist/css/nine-util.css";\n\t\t\t\t${this.cssPath?`@import "${this.cssPath}";`:""}\n\t\t\t</style>\n\t\t\t${n}\n `,this.shadowRoot.appendChild(e.content.cloneNode(!0)),this.shadowRoot.querySelectorAll(".grip").forEach(t=>{t.addEventListener("mousedown",t=>$(this,y).call(this,t))}),$(this,E).call(this),window.addEventListener("resize",()=>$(this,E).call(this))}),S(this,E,()=>{const t="h"===$(this,b),n=this.parentElement,e=Array.from(n.children).filter(t=>"nx-splitter"!==t.tagName.toLowerCase());if(e.length<2)return;const o=n.getBoundingClientRect(),i=e.reduce((n,e)=>n+(t?e.getBoundingClientRect().width:e.getBoundingClientRect().height),0),s=t?o.width:o.height;e.forEach(n=>{const e=t?n.getBoundingClientRect().width:n.getBoundingClientRect().height,o=s*(e/i)/s;n.style.flex=`${o} ${o} 0`})}),this.attachShadow({mode:"open"})}connectedCallback(){$(this,k).call(this)}get cssPath(){return this.getAttribute("css-path")||D.cssPath}}b=new WeakMap,x=new WeakMap,y=new WeakMap,k=new WeakMap,E=new WeakMap,customElements.get("nine-splitter")||customElements.define("nine-splitter",Q);const tt=new D;N.alert=tt.alert.bind(tt),N.confirm=tt.confirm.bind(tt),N.prompt=tt.prompt.bind(tt),N.api=Z,N.trace=K,N.subscribeConfig=W,N.config=_||{},"undefined"!=typeof window&&(window.nine=N),t.Fetch=V,t.NineUtil=D,t.TaskDebouncer=class{constructor(t=50){S(this,f),S(this,g,null),S(this,u,[]),S(this,m),B(this,m,t)}exec(t,...n){$(this,u).push({func:t,args:n}),$(this,g)&&clearTimeout($(this,g)),B(this,g,setTimeout(()=>z(this,f,v).call(this),$(this,m)))}execWithKey(t,n,...e){B(this,u,$(this,u).filter(n=>n.key!==t)),$(this,u).push({key:t,func:n,args:e}),$(this,g)&&clearTimeout($(this,g)),B(this,g,setTimeout(()=>z(this,f,v).call(this),$(this,m)))}},t.Trace=G,t.api=Z,t.config=_,t.loading=U,t.nine=N,t.nineAlertPopup=H,t.nineConfirmPopup=I,t.nineDialog=X,t.ninePromptPopup=q,t.subscribeConfig=W,t.trace=K,Object.defineProperty(t,Symbol.toStringTag,{value:"Module"})});
1
+ !function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n((t="undefined"!=typeof globalThis?globalThis:t||self)["nine-util"]={})}(this,function(t){"use strict";var n,e,o,i,s,a,r,l,c,d,h,p,g,u,m,f,v,w,b,x,y,k,E,L,C=Object.defineProperty,R=t=>{throw TypeError(t)},M=(t,n,e)=>((t,n,e)=>n in t?C(t,n,{enumerable:!0,configurable:!0,writable:!0,value:e}):t[n]=e)(t,"symbol"!=typeof n?n+"":n,e),$=(t,n,e)=>n.has(t)||R("Cannot "+e),S=(t,n,e)=>($(t,n,"read from private field"),e?e.call(t):n.get(t)),B=(t,n,e)=>n.has(t)?R("Cannot add the same private member more than once"):n instanceof WeakSet?n.add(t):n.set(t,e),z=(t,n,e,o)=>($(t,n,"write to private field"),o?o.call(t,e):n.set(t,e),e),T=(t,n,e)=>($(t,n,"access private method"),e);class A extends HTMLElement{constructor(){super(),B(this,n),B(this,e),M(this,"showModal",()=>{S(this,e).showModal()}),M(this,"close",()=>{S(this,e).close(),this.remove()}),B(this,o,()=>{this.querySelector(".head"),this.querySelectorAll(".close, .close2, .cancel").forEach(t=>{t.onclick=()=>this.closeWithAnimation(null)}),this.querySelectorAll(".ok").forEach(t=>{})}),B(this,i,t=>{if(t.target.closest("buttons"))return;if(0!==t.button||t.altKey||t.ctrlKey||t.shiftKey)return;const o=S(this,e).getBoundingClientRect();z(this,n,{x:t.clientX-o.left,y:t.clientY-o.top});const i=t=>{S(this,e).style.position="fixed",S(this,e).style.margin="0",S(this,e).style.left=t.clientX-S(this,n).x+"px",S(this,e).style.top=t.clientY-S(this,n).y+"px"},s=()=>{document.removeEventListener("mousemove",i),document.removeEventListener("mouseup",s)};document.addEventListener("mousemove",i),document.addEventListener("mouseup",s)}),B(this,s,t=>{if(t.target.closest("buttons"))return;const o=S(this,e).getBoundingClientRect(),i=t.changedTouches[0];z(this,n,{x:i.pageX-o.left,y:i.pageY-o.top});const s=t=>{const o=t.changedTouches[0];S(this,e).style.position="fixed",S(this,e).style.margin="0",S(this,e).style.left=o.pageX-S(this,n).x+"px",S(this,e).style.top=o.pageY-S(this,n).y+"px"},a=()=>{document.removeEventListener("touchmove",s),document.removeEventListener("touchend",a)};document.addEventListener("touchmove",s),document.addEventListener("touchend",a)})}connectedCallback(){const t=this.innerHTML,n=this.getAttribute("title")||"Details";trace.log("111111111"),this.innerHTML=`\n\t\t\t<style>\n\tdialog::backdrop {\n\t\tbackground: rgba(0, 0, 0, 0.3);\n\t}\n\t\n\tdialog:modal {\n\t\tdisplay: flex;\n\t\tflex-direction: column;\n\t\tpadding: 0;\n\t\toverflow: hidden;\n\t\tborder: 1px solid darkgreen;\n\t\toutline: none;\n\t\tresize: both;\n\t\tbox-shadow: 0 0 4px 0 darkgreen;\n width: 500px;\n height: 150px;\n min-width: 330px;\n min-height: 60px;\n }\n \n \n \n \n\tdiv.head .rect1, div.head .rect2, div.head .rect3 {\n\t\tdisplay: none;\n\t\twidth: 50px;\n\t\theight: 100%;\n\t}\n\tdiv.head .rect1 {\n\t\tbackground-color: red;\n\t}\n\tdiv.head .rect2 {\n\t\tbackground-color: darkgreen;\n\t}\n\tdiv.head .rect3 {\n\t\tbackground-color: olive;\n\t}\n\t\n\tdiv.head {\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\t--height: 30px;\n\t\tbackground-color: darkgreen;\n\t\tpadding: 4px;\n\t\tcursor: move;\n\t}\n\tdiv.head:hover {\n\t\tfilter: brightness(110%);\n\t}\n\t\n\tdiv.head span {\n\t\tfont-size: 12px;\n\t\tposition: relative;\n\t}\n\t\n\tdiv.head span.title {\n\t\tcolor: #ddd;\n\t\tmargin-left: 4px;\n\t\tfont-weight: bold;\n\t}\n\t\n\tdiv.head span.sub-title {\n\t\tcolor: #ccc;\n\t\tmargin-left: 8px;\n\t\tfont-style: italic;\n\t}\n\t\n\tdiv.head form {\n\t\tmargin: 0;\n\t}\n\tdiv.head button {\n\t\tmargin-right: 4px;\n\t\tbackground-color: transparent;\n\t\tborder: none;\n\t\tcolor: #ccc;\n\t\tfont-size: x-small;\n\t}\n\tdiv.head button:hover {\n\t\tcursor: pointer;\n\t}\n\t\n\tdiv.contents {\n\t\tdisplay: flex;\n\t\twidth: 100%;\n\t\theight: 100%;\n\t\toverflow: hidden;\n\t}\n\tdiv.left {\n\t\tposition: relative;\n\t\twidth: 16px;\n\t\theight: 100%;\n\t\tbackground-color: #ddd;\n\t\tdisplay: none;\n\t}\n\t\n\tdiv.left span {\n\t\twriting-mode: vertical-rl;\n\t\t-moz-user-select: none;\n\t\t-webkit-user-select: none;\n\t\t-ms-user-select: none;\n\t\tuser-select: none;\n\t\tcolor: #ccc;\n\t\tfont-weight: 700;\n\t\twidth: 100%;\n\t\theight: 100%;\n\t\tmargin-left: 3px;\n\t\tmargin-top: 3px;\n\t}\n\tdiv.close2 {\n\t\tdisplay: none;\n\t\tposition: absolute;\n\t\tright: 0;\n\t\ttop: 3px;\n\t\tcursor: pointer;\n\t\tcolor: #666;\n\t}\n\tdiv.close2 svg:hover {\n\t\tcolor: #999;\n\t}\n\t\n\tdiv.body {\n\t\tdisplay: flex;\n\t\twidth: 100%;\n\t\theight: unset;\n\t\t--border: 3px solid #999;\n\t\t--border-top: none;\n\t\toverflow-x: hidden;\n\t\toverflow-y: auto;\n\t\tpadding: 10px;\n\t\tgap: 8px;\n\t\tflex-direction: column;\n\t}\n\t\n\t\n\t\n\t\n\tng-sphere.icon {\n\t\tmargin-left: 8px;\n\t}\n\t\n\t.buttons {\n\t\tdisplay: flex;\n\t\tposition: absolute;\n\t\tright: 4px;\n\t}\n\t\n\tng-sphere {\n\t\tposition: relative;\n\t\t--width: 16px;\n\t\t--height: 16px;\n\t\tcursor: pointer;\n\t\tmargin-right: 4px;\n\t\tdisplay: flex;\n\t}\n\tng-sphere:hover {\n\t\tfilter: brightness(90%);\n\t}\n\tng-sphere:active {\n\t\tfilter: brightness(80%);\n\t}\n\t\n\tng-sphere:hover::after {\n\t\tcontent: "";\n\t\tposition: absolute;\n\t\twidth: 100%;\n\t\theight: 100%;\n\t\tbackground-repeat: no-repeat;\n\t\tbackground-position: center;\n\t}\n\tng-sphere.apply:hover::after {\n\t\tbackground-size: 14px 14px;\n\t\tbackground-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg"><polyline points="2.5,7 6,10 11,3" style="fill:none;stroke:white;stroke-width:2px;" /></svg>');\n\t}\n\t\n\tng-sphere.reset:hover::after {\n\t\tbackground-size: 12px 12px;\n\t\tbackground-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" style="fill:none;stroke:white;stroke-width:2px;" focusable="false" aria-hidden="true"><path d="M10 5h5V0"></path><path d="M15 8a6.957 6.957 0 0 1-7 7 6.957 6.957 0 0 1-7-7 6.957 6.957 0 0 1 7-7 6.87 6.87 0 0 1 6.3 4"></path></svg>');\n\t}\n\t\n\tng-sphere.close:hover::after {\n\t\tbackground-size: 12px 12px;\n\t\tbackground-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" style="fill:none;stroke:white;stroke-width:2px;" focusable="false" aria-hidden="true" viewBox="0 0 16 16"><path d="M2 2l12 12M14 2L2 14"></path></svg>');\n\t}\n\t\n\t\n\tbutton {\n cursor: pointer;\n }\n \n .input-area {\n position: relative;\n height: 100%;\n --display: flex;\n textarea {\n width: 100%;\n height: 100%;\n min-height: 100px;\n padding: 8px;\n box-sizing: border-box;\n resize: none;\n border-radius: 2px;\n border-color: #ccc;\n }\n textarea:focus {\n border-color: green;\n outline: none; /* 브라우저 기본 파란색 테두리 제거 */\n }\n }\n \n .buttons-confirm {\n position: relative;\n display: flex;\n justify-content: flex-end;\n --bottom: 8px;\n --right: 8px;\n }\n \n \n .buttons-confirm button {\n height: 32px;\n margin-right: 8px;\n border: none;\n outline: none;\n width: 60px;\n -moz-user-select: none;\n -webkit-user-select: none;\n -ms-user-select: none;\n user-select: none;\n }\n .buttons-confirm button:hover {\n filter: brightness(90%);\n }\n .buttons-confirm button:active {\n color: #ccc;\n }\n \n button.ok {\n --display: none;\n background-color: darkgreen;\n color: white;\n }\n button.cancel {\n color: white;\n background-color: #6c757d;\n }\n \n \n \n div.msg {\n position: relative;\n height: 100%;\n font-size: 14px;\n color: #333;\n }\n \n .reset, .apply {\n display: none;\n }\n \n \n \n :host(.classic) dialog:modal {\n border: 1px solid #007bff;\n box-shadow: 0 0 4px 0 #007bff;\n }\n \n :host(.classic) div.head {\n background-color: #007bff;\n }\n :host(.classic) div.head:hover {\n filter: brightness(110%);\n }\n \n :host(.classic) div.head span {\n font-size: 12px;\n }\n \n :host(.classic) div.head span.title {\n color: #ddd;\n margin-left: 4px;\n font-weight: bold;\n }\n \n :host(.classic) div.head span.sub-title {\n color: #ccc;\n margin-left: 8px;\n font-style: italic;\n }\n :host(.classic) div.head button {\n margin-right: 4px;\n background-color: transparent;\n border: none;\n color: #ccc;\n font-size: x-small;\n }\n \n \n \n \n :host(.rgb) dialog:modal {\n border: none;\n box-shadow: unset;\n border-top: none;\n }\n \n :host(.rgb) div.left {\n display: block;\n background-color: #ddd;\n }\n :host(.rgb) div.left span {\n color: #ccc;\n }\n :host(.rgb) div.close2 {\n display: block;\n color: #666;\n }\n :host(.rgb) div.close2 svg:hover {\n color: #999;\n }\n :host(.rgb) div.head {\n height: 4px;\n background-color: #999;\n padding: 0;\n }\n :host(.rgb) div.contents {\n height: calc(100% - 4px);\n }\n \n :host(.rgb) div.head ng-sphere,\n :host(.rgb) div.head span,\n :host(.rgb) div.head .buttons {\n display: none;\n }\n \n :host(.rgb) div.head .rect1,\n :host(.rgb) div.head .rect2,\n :host(.rgb) div.head .rect3 {\n display: flex;\n }\n \n \n :host(.rgb) div.head:hover {\n filter: unset;\n }\n \n \n /* --- Animation Core --- */\n:host {\n --nx-duration: 0.4s;\n --nx-timing: cubic-bezier(0.34, 1.56, 0.64, 1);\n}\n\n/* 🎯 수정: 애니메이션 클래스가 붙은 경우에만 초기 opacity를 0으로 설정 */\n:host(.fade) dialog,\n:host(.zoom) dialog,\n:host(.moveUp) dialog,\n:host(.moveDown) dialog,\n:host(.moveLeft) dialog,\n:host(.moveRight) dialog,\n:host(.roadRunner) dialog {\n opacity: 0;\n}\n\n/* shake는 애니메이션 내부에서 opacity를 다루므로 제외하거나 별도 처리 */\n:host(.shake) dialog { \n opacity: 1; \n}\n\n/* 1. Fade (서서히 나타남) */\n:host(.fade) dialog { animation: nx-fade-in var(--nx-duration) forwards; }\n@keyframes nx-fade-in { from { opacity: 0; } to { opacity: 1; } }\n\n/* 2. Zoom (커지며 나타남) */\n:host(.zoom) dialog { animation: nx-zoom-in var(--nx-duration) var(--nx-timing) forwards; }\n@keyframes nx-zoom-in { from { opacity: 0; transform: scale(0.5); } to { opacity: 1; transform: scale(1); } }\n\n/* 3. Slide (상하좌우) */\n:host(.moveUp) dialog { animation: nx-move-up var(--nx-duration) var(--nx-timing) forwards; }\n:host(.moveDown) dialog { animation: nx-move-down var(--nx-duration) var(--nx-timing) forwards; }\n:host(.moveLeft) dialog { animation: nx-move-left var(--nx-duration) var(--nx-timing) forwards; }\n:host(.moveRight) dialog { animation: nx-move-right var(--nx-duration) var(--nx-timing) forwards; }\n\n@keyframes nx-move-up { from { opacity: 0; transform: translateY(100px); } to { opacity: 1; transform: translateY(0); } }\n@keyframes nx-move-down { from { opacity: 0; transform: translateY(-100px); } to { opacity: 1; transform: translateY(0); } }\n@keyframes nx-move-left { from { opacity: 0; transform: translateX(100px); } to { opacity: 1; transform: translateX(0); } }\n@keyframes nx-move-right { from { opacity: 0; transform: translateX(-100px); } to { opacity: 1; transform: translateY(0); } }\n\n/* 4. Shake (상하좌우 격렬한 진동 - 에러 인지용) */\n:host(.shake) dialog { \n animation: nx-heavy-shake 0.5s cubic-bezier(.36,.07,.19,.97) both;\n opacity: 1; \n}\n\n@keyframes nx-heavy-shake {\n 10%, 90% { transform: translate3d(-1px, -2px, 0); }\n 20%, 80% { transform: translate3d(2px, 4px, 0); }\n 30%, 50%, 70% { transform: translate3d(-6px, -6px, 0); }\n 40%, 60% { transform: translate3d(6px, 6px, 0); }\n}\n\n/* 5. Road Runner (등장: 왼쪽에서 탄력 있게 / 퇴장: 움츠렸다가 광속 탈출) */\n:host(.roadRunner) dialog { \n animation: roadRunnerIn 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards; \n}\n\n@keyframes roadRunnerIn {\n 0% { transform: translateX(-1500px) skewX(30deg); opacity: 1; }\n 70% { transform: translateX(30px) skewX(-10deg); opacity: 1; }\n 100% { transform: translateX(0) skewX(0deg); opacity: 1; }\n}\n\n/* --- Out Animations (닫힐 때) --- */\ndialog.out { pointer-events: none; }\n\n/* Road Runner 퇴장: 슥 움츠렸다가(Anticipation) 쌩~! */\n:host(.roadRunner) dialog.out { \n animation: roadRunnerOut 0.5s cubic-bezier(0.6, -0.28, 0.735, 0.045) forwards; \n}\n\n@keyframes roadRunnerOut {\n 0% { \n transform: translateX(0) scale(1) skewX(0deg); \n opacity: 1; \n }\n 30% { \n /* 예비 동작: 뒤로 살짝 갔다가 움츠러들기 */\n transform: translateX(50px) scaleX(1.2) scaleY(0.8) skewX(-20deg); \n opacity: 1; \n }\n 100% { \n /* 발사: 길게 늘어나며 광속 탈출 */\n transform: translateX(2000px) scaleX(4) scaleY(0.3) skewX(50deg); \n opacity: 0; \n filter: blur(10px); /* 👈 잔상 느낌 추가 */\n }\n}\n\n/* 일반 퇴장 (기본) */\ndialog.out { animation: nx-fade-out 0.3s forwards; }\n@keyframes nx-fade-out { from { opacity: 1; transform: scale(1); } to { opacity: 0; transform: scale(0.9); } }\n</style>\n\t\t\n\t\t\t<dialog>\n\t\t\t\t<div class="head">\n\t\t\t\t\t<div class="rect1"></div>\n\t\t\t\t\t<div class="rect2"></div>\n\t\t\t\t\t<div class="rect3"></div>\n\t\t\t\t\t<ng-sphere class="icon" end-fill="#666" size="8"></ng-sphere>\n\t\t\t\t\t<span class="title">${n}</span>\n\t\t\t\t\t<span class="sub-title"></span>\n\t\t\t\t\t<div class="buttons">\n\t\t\t\t\t\t<ng-sphere class="apply" start-fill="#cc6" end-fill="#660" size="16" title="apply"></ng-sphere>\n\t\t\t\t\t\t<ng-sphere class="reset" start-fill="#99f" end-fill="#00f" size="16" title="reset"></ng-sphere>\n\t\t\t\t\t\t<ng-sphere class="close" start-fill="#f99" end-fill="#f00" size="16" title="close"></ng-sphere>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div class="contents">\n\t\t\t\t\t<div class="left">\n\t\t\t\t\t\t<span>가나다라마바사아자차카타파하가나다라마바사아자차카타파하가나다라마바사아자차카타파하가나다라마바사아자차카타파하가나다라마바사아자차카타파하가나다라마바사아자차카타파하가나다라마바사아자차카타파하가나다라마바사아자차카타파하</span>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class="body">\n\t\t\t\t\t\t${t}\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class="close2">\n\t\t\t\t\t\t<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">\n\t\t\t\t\t\t\t<path d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708"/>\n\t\t\t\t\t\t</svg>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</dialog>\n\t\t`,z(this,e,this.querySelector("dialog")),S(this,o).call(this)}closeWithAnimation(t){S(this,e).classList.add("out"),setTimeout(()=>{S(this,e).close(),this.dispatchEvent(new CustomEvent("closed",{detail:t})),this.remove()},300)}}n=new WeakMap,e=new WeakMap,o=new WeakMap,i=new WeakMap,s=new WeakMap;class P extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"})}static async open(t,n,e,o,i){var s,a,r;const l=t.tagName.toLowerCase(),c={"true-text":"확인","false-text":"취소",class:"classic",animation:"fade",...(null==(r=null==(a=null==(s=window.nine)?void 0:s.config)?void 0:a.ux)?void 0:r[l.replace("nine-","").replace("-popup","")])||{},...o};document.querySelectorAll(l).forEach(t=>t.remove());const d=document.createElement(l);c.class&&d.classList.add(c.class),c.animation&&d.classList.add(c.animation),document.body.appendChild(d),i(d,n,c);const h=d.shadowRoot.querySelector("nine-dialog");return e&&h.setAttribute("title",e),new Promise(t=>{h.addEventListener("closed",n=>t(n.detail)),d.setupEvents(t,h),h.showModal()})}}customElements.get("nine-dialog")||customElements.define("nine-dialog",A);const W=class extends P{constructor(){super()}render(t,n){this.shadowRoot.innerHTML=`\n <nine-dialog>\n <div class="msg">${t.replace(/\n/g,"<br/>")}</div>\n <div class="buttons-confirm">\n <button class="cancel">${n["false-text"]}</button>\n <button class="ok">${n["true-text"]}</button>\n </div>\n </nine-dialog>`}setupEvents(t,n){this.shadowRoot.querySelector(".ok").onclick=()=>n.closeWithAnimation(!0)}};M(W,"tagName","nine-confirm-popup"),M(W,"confirm",(t,n,e)=>P.open(W,t,n,e,(t,n,e)=>t.render(n,e)));let _=W;const N=class extends P{constructor(){super()}render(t,n){this.shadowRoot.innerHTML=`\n <nine-dialog>\n <div class="msg">${t.replace(/\n/g,"<br/>")}</div>\n <div class="buttons-confirm">\n <button class="cancel">확인</button>\n </div>\n </nine-dialog>`}setupEvents(t,n){}};M(N,"tagName","nine-alert-popup"),M(N,"alert",(t,n,e)=>P.open(N,t,n,e,(t,n,e)=>t.render(n,e)));let X=N;customElements.get("nine-confirm-popup")||customElements.define("nine-confirm-popup",_),customElements.get("nine-alert-popup")||customElements.define("nine-alert-popup",X);const O=class extends P{constructor(){super()}render(t,n){trace.log(this),trace.log(this.shadowRoot),this.shadowRoot.innerHTML=`\n\t\t\t<style>\n\t\t\t\tdialog {\n\t\t\t\t\theight: 300px !important;\n\t\t\t\t}\n\t\t\t\t.msg {\n\t\t\t\t\theight: unset !important;\n\t\t\t\t}\n\t\t\t</style>\n\t\t\t\n <nine-dialog>\n <div class="msg">${t.replace(/\n/g,"<br/>")}</div>\n <div class="input-area">\n <textarea placeholder="내용을 입력하세요..."></textarea>\n </div>\n <div class="buttons-confirm">\n <button class="cancel">${n["false-text"]}</button>\n <button class="ok">${n["true-text"]}</button>\n </div>\n </nine-dialog>`}setupEvents(t,n){const e=this.shadowRoot.querySelector("textarea");this.shadowRoot.querySelector(".ok").onclick=()=>n.closeWithAnimation(e.value),requestAnimationFrame(()=>e.focus())}};M(O,"tagName","nine-prompt-popup"),M(O,"prompt",(t,n,e)=>P.open(O,t,n,e,(t,n,e)=>t.render(n,e)));let F=O;customElements.get("nine-prompt-popup")||customElements.define("nine-prompt-popup",F);class I{constructor(){B(this,a)}alert(t,n="Alert"){return T(this,a,r).call(this,"alert",t,n,"classic")}confirm(t,n="Confirm"){return T(this,a,r).call(this,"confirm",t,n,"classic")}prompt(t,n="Prompt"){return T(this,a,r).call(this,"prompt",t,n,"classic")}}a=new WeakSet,r=function(t,n,e,o){const i={class:o,animation:"fade"};let s=!1;const a={alert:X,confirm:_,prompt:F}[t],r={rgb:()=>(i.class="rgb",r),classic:()=>(i.class="classic",r),shake:()=>(i.animation="shake",r),run:()=>(i.animation="roadRunner",r),zoom:()=>(i.animation="zoom",r),then:(o,r)=>(s=!0,a[t](n,e,i).then(o,r))};return Promise.resolve().then(()=>{s||(s=!0,a[t](n,e,i))}),r},M(I,"cssPath","");const j=new Set,H={ux:{nativeOverride:!1,theme:"light"},board:{readOnly:!1},cssPath:"",debug:!1};"undefined"==typeof window||window.__NINE_GLOBAL_CONFIG__||(window.__NINE_GLOBAL_CONFIG__=H);const Y="undefined"!=typeof window?window.__NINE_GLOBAL_CONFIG__:H,q=t=>(j.add(t),t("all",Y),()=>j.delete(t)),D=new Proxy(Y,{set:(t,n,e)=>(t[n]=e,j.forEach(e=>e(n,t)),!0),get:(t,n)=>t[n]}),G={config:D,get cssPath(){return this.config.cssPath||""},setup(t={}){Object.entries(t).forEach(([t,n])=>{"object"!=typeof n||null===n||Array.isArray(n)?this.config[t]=n:this.config[t]={...this.config[t],...n}}),"undefined"!=typeof window&&(window.nine=window.nine||this)}};let K=(g=class{constructor(t=null,n="green"){B(this,h),B(this,l),B(this,c),B(this,d,!0),z(this,l,t),z(this,c,n),T(this,h,p).call(this)}initBAK(t,n="green"){z(this,l,t),z(this,c,n)}init(t,n="green"){return z(this,l,t),z(this,c,n),this}get log(){const t=`color: ${S(this,c)}; font-weight: bold;`;return S(this,l)?console.log.bind(console,`%c[${S(this,l)}]`,t):console.log.bind(console)}get warn(){return S(this,d)?S(this,l)?console.warn.bind(console,`%c[${S(this,l)}]`,"color: cyan; font-weight: bold;"):console.warn.bind(console):()=>{}}get error(){return S(this,l)?console.error.bind(console,`%c[${S(this,l)}]`,"color: red; font-weight: bold;"):console.error.bind(console)}enable(){z(this,d,!0)}disable(){z(this,d,!1)}},l=new WeakMap,c=new WeakMap,d=new WeakMap,h=new WeakSet,p=function(){if("undefined"==typeof window)return;"localhost"===window.location.hostname||"127.0.0.1"===window.location.hostname||window.location.hostname.startsWith("192.168.")?this.enable():(this.disable(),console.log(`%c[${S(this,l)||"Trace"}]%c 운영 모드: 로그 비활성화. %ctrace.enable()%c 로 활성화 가능`,"color: #4CAF50; font-weight: bold;","","background: #333; color: yellow; padding: 2px 5px;",""))},g);const U=new K;"undefined"!=typeof window&&(window.trace=U);u=new WeakMap,m=new WeakMap,f=new WeakMap,v=new WeakSet,w=function(){if(0===S(this,m).length)return;const t=S(this,m).splice(0,S(this,m).length),n=new Set;t.forEach(t=>{const e=`${t.func.name}_${JSON.stringify(t.args)}`;n.has(e)||(t.func(...t.args),n.add(e))}),z(this,u,null)};class J extends U.constructor{constructor(){super(),this.init("nine-util","green")}}const V=new J;class Z{static show(){let t=document.getElementById("global-loading-overlay");if(!t&&(t=document.createElement("div"),t.id="global-loading-overlay",t.style.cssText="\n position: fixed; inset: 0; z-index: 9999;\n background: rgba(0, 0, 0, 0.4); display: flex; \n justify-content: center; align-items: center;\n backdrop-filter: blur(2px);\n ",t.innerHTML='<div class="loading-spinner"></div>',document.body.appendChild(t),!document.getElementById("nine-util-style"))){const t=document.createElement("style");t.id="nine-util-style",t.innerHTML="\n .loading-spinner {\n width: 48px; height: 48px;\n border: 5px solid rgba(255, 255, 255, 0.3);\n border-top-color: white; border-radius: 50%;\n animation: nine-spin 1s linear infinite;\n }\n @keyframes nine-spin { to { transform: rotate(360deg); } }\n ",document.head.appendChild(t)}t.style.display="flex"}static hide(){const t=document.getElementById("global-loading-overlay");t&&(t.style.display="none")}}const Q=class{};b=new WeakMap,M(Q,"BASE_URL",window.__API_BASE_URL__||""),B(Q,b,(t,n,e={},o=!0)=>{const i=n.startsWith("http")?n:`${Q.BASE_URL}${n}`;o&&Z.show();const s={};e instanceof FormData||(s["Content-Type"]="application/json");const a={method:t,headers:s};let r=i;return"GET"===t?r+=`?${new URLSearchParams(e)}`:a.body=e instanceof FormData?e:JSON.stringify(e),fetch(r,a).then(async t=>{if(!t.ok){const n=await t.text();throw new Error(`API 오류 (${t.status}): ${n}`)}return t.json()}).catch(n=>{throw V.error(`[IdeFetch.${t.toLowerCase()}] ${i} 실패:`,n),n}).finally(()=>{o&&Z.hide()})}),M(Q,"get",(t,n={},e=!0)=>{var o;return S(o=Q,b).call(o,"GET",t,n,e)}),M(Q,"post",(t,n={},e=!0)=>{var o;return S(o=Q,b).call(o,"POST",t,n,e)}),M(Q,"postMultipart",async(t,n=[],e={})=>{const{fileKey:o="fileContents",filePartName:i="files",jsonPartName:s="dataList",chunkSize:a=10}=e;Z.show();let r=0,l=null;return(async()=>{for(let e=0;e<n.length;e+=a){const c=new FormData,d=n.slice(e,e+a),h=[];d.forEach(t=>{const{[o]:n,_fileObj:e,...s}=t;h.push(s),n instanceof File&&c.append(i,n)});const p=new Blob([JSON.stringify(h)],{type:"application/json"});if(c.append(s,p),l=await Q.post(t,c,!1),!l||!l.success&&"OK"!==l.status)throw new Error(`청크 전송 실패: ${e}번째 섹션`);r+=d.length}return{...l,success:!0,totalCount:r}})().catch(t=>{throw V.error("[postChunk] Error:",t),t}).finally(()=>{Z.hide()})});let tt=Q;const nt=tt;class et extends HTMLElement{constructor(){super(),B(this,x),B(this,y,t=>{const n=t.previousElementSibling,e=t.nextElementSibling;if(!n||!e)return void z(this,x,this.classList.contains("h")?"h":"v");const o=n.getBoundingClientRect(),i=e.getBoundingClientRect();this.classList.contains("h")?z(this,x,"h"):this.classList.contains("v")?z(this,x,"v"):z(this,x,Math.abs(o.top-i.top)<5?"h":"v")}),B(this,k,t=>{t.preventDefault(),t.stopPropagation();const n=this.getBoundingClientRect(),e="h"===S(this,x),o=e?t.clientX-n.left:t.clientY-n.top,i=document.createElement("div");i.className=`nx-splitter-drag-bar-${S(this,x)}`,Object.assign(i.style,{position:"absolute",zIndex:"999",background:"#666",opacity:"0.6",pointerEvents:"none"});const s=this.getRootNode({composed:!0}),a=s instanceof ShadowRoot?s.host:this.parentElement,r=this.previousElementSibling,l=this.nextElementSibling;if(!a||!r||!l)return void V.warn("Spliter's parent or siblings not found.");(a.shadowRoot||a).appendChild(i);const c=i.offsetParent.getBoundingClientRect(),d=r.getBoundingClientRect(),h=l.getBoundingClientRect(),p=(e?n.left-c.left:n.top-c.top)+o;e?(i.style.top="0",i.style.left=`${p}px`,i.style.width="2px",i.style.height="100%"):(i.style.left="0",i.style.top=`${p}px`,i.style.height="2px",i.style.width="100%"),i.style.mixBlendMode="difference",i.style.zIndex="99999";const g=e?d.left-c.left:d.top-c.top,u=e?h.right-c.left-n.width:h.bottom-c.top-n.height,m=t=>{const n=e?t.clientX:t.clientY,o=e?n-c.left:n-c.top,s=Math.max(g,Math.min(o,u));e?i.style.left=`${s}px`:i.style.top=`${s}px`},f=()=>{window.removeEventListener("mousemove",m),window.removeEventListener("mouseup",f),i.remove();const t=Array.from(a.children),n=t.filter(t=>"nx-splitter"!==t.tagName.toLowerCase()),o=window.getComputedStyle(a),s=e?o.getPropertyValue("column-gap"):o.getPropertyValue("row-gap"),c=parseFloat(s)||0,d=(t.length>1?t.length-1:0)*c,h=(e?parseFloat(i.style.left):parseFloat(i.style.top))-p,g=e?r.getBoundingClientRect().width:r.getBoundingClientRect().height,u=e?l.getBoundingClientRect().width:l.getBoundingClientRect().height;let v=g+h,w=u-h;v<0&&(w+=v,v=0),w<0&&(v+=w,w=0);const b=n.map(t=>e?t.getBoundingClientRect().width:t.getBoundingClientRect().height),x=t.reduce((t,n)=>"nx-splitter"===n.tagName.toLowerCase()?t+(e?n.getBoundingClientRect().width:n.getBoundingClientRect().height):t,0),y=(e?a.getBoundingClientRect().width:a.getBoundingClientRect().height)-x-d;let k=0;n.forEach((t,n)=>{let e;e=t===r?v:t===l?w:b[n];const o=e/y;V.log(t),t.classList.contains("sidebar")?t.style.flex=`0 0 ${e}px`:t.style.flex=`${o} ${o} 0`,k+=o}),V.log(`dragOffset: ${h}`),V.log(`Calculated FlexSum: ${k}`)};window.addEventListener("mousemove",m),window.addEventListener("mouseup",f)}),B(this,E,()=>{S(this,y).call(this,this),this.classList.add(S(this,x));const t=this.innerHTML.trim(),n=""===t?'<div class="grip"></div>':`<div class="grip"></div><div class="inner-container">${t}</div><div class="grip"></div>`;this.innerHTML="";const e=document.createElement("template");e.innerHTML=`\n\t\t\t<style>\n\t\t\t\t@import "https://cdn.jsdelivr.net/npm/@nine-lab/nine-util@0.9.127/dist/css/nine-util.css";\n\t\t\t\t${this.cssPath?`@import "${this.cssPath}";`:""}\n\t\t\t</style>\n\t\t\t${n}\n `,this.shadowRoot.appendChild(e.content.cloneNode(!0)),this.shadowRoot.querySelectorAll(".grip").forEach(t=>{t.addEventListener("mousedown",t=>S(this,k).call(this,t))}),S(this,L).call(this),window.addEventListener("resize",()=>S(this,L).call(this))}),B(this,L,()=>{const t="h"===S(this,x),n=this.parentElement,e=Array.from(n.children).filter(t=>"nx-splitter"!==t.tagName.toLowerCase());if(e.length<2)return;const o=n.getBoundingClientRect(),i=e.reduce((n,e)=>n+(t?e.getBoundingClientRect().width:e.getBoundingClientRect().height),0),s=t?o.width:o.height;e.forEach(n=>{const e=t?n.getBoundingClientRect().width:n.getBoundingClientRect().height,o=s*(e/i)/s;n.style.flex=`${o} ${o} 0`})}),this.attachShadow({mode:"open"})}connectedCallback(){S(this,E).call(this)}get cssPath(){return this.getAttribute("css-path")||I.cssPath}}x=new WeakMap,y=new WeakMap,k=new WeakMap,E=new WeakMap,L=new WeakMap,customElements.get("nine-splitter")||customElements.define("nine-splitter",et);const ot=new I;G.alert=ot.alert.bind(ot),G.confirm=ot.confirm.bind(ot),G.prompt=ot.prompt.bind(ot),G.safe=async t=>{try{return[await t,null]}catch(n){return[null,n]}},G.api=nt,G.trace=U,G.subscribeConfig=q,G.config=D||{},"undefined"!=typeof window&&(window.nine=G),t.Fetch=tt,t.NineUtil=I,t.TaskDebouncer=class{constructor(t=50){B(this,v),B(this,u,null),B(this,m,[]),B(this,f),z(this,f,t)}exec(t,...n){S(this,m).push({func:t,args:n}),S(this,u)&&clearTimeout(S(this,u)),z(this,u,setTimeout(()=>T(this,v,w).call(this),S(this,f)))}execWithKey(t,n,...e){z(this,m,S(this,m).filter(n=>n.key!==t)),S(this,m).push({key:t,func:n,args:e}),S(this,u)&&clearTimeout(S(this,u)),z(this,u,setTimeout(()=>T(this,v,w).call(this),S(this,f)))}},t.Trace=K,t.api=nt,t.config=D,t.loading=Z,t.nine=G,t.nineAlertPopup=X,t.nineConfirmPopup=_,t.nineDialog=A,t.ninePromptPopup=F,t.subscribeConfig=q,t.trace=U,Object.defineProperty(t,Symbol.toStringTag,{value:"Module"})});
2
2
  //# sourceMappingURL=nine-util.umd.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"nine-util.umd.js","sources":["../src/core/Config.js","../src/ux/dialog/nineDialog.js","../src/ux/dialog/nineConfirm.js","../src/ux/dialog/ninePrompt.js","../src/ux/dialog/NineUtil.js","../src/core/Trace.js","../src/core/TaskDebouncer.js","../src/ux/Loading.js","../src/net/Fetch.js","../src/ux/UxSplitter.js","../src/index.js"],"sourcesContent":["// @nine-lab/nine-util/core/Config.js\r\n\r\nconst listeners = new Set();\r\n\r\n// 💡 [핵심] 전역 저장소를 단일화합니다.\r\n// window에 이미 있으면 그것을 쓰고, 없으면 초기값을 생성하여 등록합니다.\r\nconst _initialConfig = {\r\n\tux: { nativeOverride: false, theme: 'light' },\r\n\tboard: { readOnly: false },\r\n\tcssPath: \"\",\r\n\tdebug: false\r\n};\r\n\r\nif (typeof window !== 'undefined' && !window.__NINE_GLOBAL_CONFIG__) {\r\n\twindow.__NINE_GLOBAL_CONFIG__ = _initialConfig;\r\n}\r\n\r\n// 이제 모든 모듈의 _config는 동일한 window 객체 메모리를 가리킵니다.\r\nconst _config = typeof window !== 'undefined' ? window.__NINE_GLOBAL_CONFIG__ : _initialConfig;\r\n\r\nexport const subscribeConfig = (fn) => {\r\n\tlisteners.add(fn);\r\n\tfn('all', _config);\r\n\treturn () => listeners.delete(fn);\r\n};\r\n\r\n// Proxy 역시 전역 저장소인 _config를 조작합니다.\r\nexport const config = new Proxy(_config, {\r\n\tset(target, prop, value) {\r\n\t\ttarget[prop] = value;\r\n\t\tlisteners.forEach(fn => fn(prop, target));\r\n\t\treturn true;\r\n\t},\r\n\tget(target, prop) {\r\n\t\treturn target[prop];\r\n\t}\r\n});\r\n\r\nexport const nine = {\r\n\tconfig: config,\r\n\r\n\t// Getter에서 window.nine까지 확인할 필요도 없습니다.\r\n\t// 이미 config 자체가 전역 저장소(__NINE_GLOBAL_CONFIG__)를 바라보고 있기 때문입니다.\r\n\tget cssPath() {\r\n\t\treturn this.config.cssPath || \"\";\r\n\t},\r\n\r\n\tsetup(options = {}) {\r\n\t\tObject.entries(options).forEach(([key, value]) => {\r\n\t\t\t// 깊은 병합 지원\r\n\t\t\tif (typeof value === 'object' && value !== null && !Array.isArray(value)) {\r\n\t\t\t\tthis.config[key] = { ...this.config[key], ...value };\r\n\t\t\t} else {\r\n\t\t\t\tthis.config[key] = value;\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\t// 다른 모듈에서 window.nine으로 접근할 수 있도록 보장\r\n\t\tif (typeof window !== 'undefined') {\r\n\t\t\twindow.nine = window.nine || this;\r\n\t\t}\r\n\t}\r\n};","import { dialogStyles } from './style.dialog.js';\n\nexport class nineDialog extends HTMLElement\n{\n\t#shift;\n\t#dialog;\n\n\n\tconstructor () {\n\t\tsuper();\n\t}\n\n\tconnectedCallback() {\n\n\t\tconst v = this.innerHTML;\n\t\tconst titleText = this.getAttribute(\"title\") || \"Details\";\n\n\t\ttrace.log(\"111111111\")\n\n\t\tthis.innerHTML = `\n\t\t\t<style>${dialogStyles}</style>\n\t\t\n\t\t\t<dialog>\n\t\t\t\t<div class=\"head\">\n\t\t\t\t\t<div class=\"rect1\"></div>\n\t\t\t\t\t<div class=\"rect2\"></div>\n\t\t\t\t\t<div class=\"rect3\"></div>\n\t\t\t\t\t<ng-sphere class=\"icon\" end-fill=\"#666\" size=\"8\"></ng-sphere>\n\t\t\t\t\t<span class=\"title\">${titleText}</span>\n\t\t\t\t\t<span class=\"sub-title\"></span>\n\t\t\t\t\t<div class=\"buttons\">\n\t\t\t\t\t\t<ng-sphere class=\"apply\" start-fill=\"#cc6\" end-fill=\"#660\" size=\"16\" title=\"apply\"></ng-sphere>\n\t\t\t\t\t\t<ng-sphere class=\"reset\" start-fill=\"#99f\" end-fill=\"#00f\" size=\"16\" title=\"reset\"></ng-sphere>\n\t\t\t\t\t\t<ng-sphere class=\"close\" start-fill=\"#f99\" end-fill=\"#f00\" size=\"16\" title=\"close\"></ng-sphere>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"contents\">\n\t\t\t\t\t<div class=\"left\">\n\t\t\t\t\t\t<span>가나다라마바사아자차카타파하가나다라마바사아자차카타파하가나다라마바사아자차카타파하가나다라마바사아자차카타파하가나다라마바사아자차카타파하가나다라마바사아자차카타파하가나다라마바사아자차카타파하가나다라마바사아자차카타파하</span>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"body\">\n\t\t\t\t\t\t${v}\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"close2\">\n\t\t\t\t\t\t<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" viewBox=\"0 0 16 16\">\n\t\t\t\t\t\t\t<path d=\"M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708\"/>\n\t\t\t\t\t\t</svg>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</dialog>\n\t\t`;\n\n\t\t//this.#owner = this.getRootNode().host.closest(\"nine-grid\");\n\n\t\t//$(\".title\", this).html(\"Details\");\n\n\t\tthis.#dialog = this.querySelector('dialog');\n\t\tthis.#init();\n\t};\n\n\tshowModal = () => {\n\t\tthis.#dialog.showModal();\n\t};\n\n\tclose = () => {\n\t\t// 이벤트 리스너 제거 (표준 방식은 핸들러 참조가 필요하지만,\n\t\t// 여기서는 요소가 사라지므로 메모리 관리를 위해 정리)\n\t\tthis.#dialog.close();\n\t\tthis.remove();\n\t};\n\n\t#init = () => {\n\t\tconst head = this.querySelector('.head');\n\n\t\t// 1. 모든 닫기 성격의 버튼 (.close, .close2, .cancel) 공통 처리\n\t\tthis.querySelectorAll('.close, .close2, .cancel').forEach(btn => {\n\t\t\tbtn.onclick = () => this.closeWithAnimation(null); // 취소/닫기는 null 리턴\n\t\t});\n\n\t\t// 2. 확인 버튼 (.ok) 처리\n\t\t// 확인 버튼은 텍스트 입력값 등 데이터가 필요하므로\n\t\t// 실제 데이터 추출은 각 팝업 클래스(prompt 등)에서 하되,\n\t\t// 닫기 애니메이션 실행은 여기서 담당하도록 가이드합니다.\n\t\tthis.querySelectorAll('.ok').forEach(btn => {\n\t\t\t// .ok 버튼의 로직은 각 팝업의 setupEvents에서 덮어쓰거나\n\t\t\t// 델리게이트 이벤트를 통해 처리합니다.\n\t\t});\n\n\t\t// 드래그 로직 생략...\n\t};\n\n\t// --- 드래그 로직 (Vanilla JS) ---\n\t#onMouseDown = e => {\n\t\tif (e.target.closest(\"buttons\")) return;\n\t\tif (e.button !== 0 || e.altKey || e.ctrlKey || e.shiftKey) return;\n\n\t\tconst rect = this.#dialog.getBoundingClientRect();\n\t\tthis.#shift = {\n\t\t\tx: e.clientX - rect.left,\n\t\t\ty: e.clientY - rect.top\n\t\t};\n\n\t\tconst onMouseMove = (ev) => {\n\t\t\tthis.#dialog.style.position = 'fixed';\n\t\t\tthis.#dialog.style.margin = '0';\n\t\t\tthis.#dialog.style.left = `${ev.clientX - this.#shift.x}px`;\n\t\t\tthis.#dialog.style.top = `${ev.clientY - this.#shift.y}px`;\n\t\t};\n\n\t\tconst onMouseUp = () => {\n\t\t\tdocument.removeEventListener('mousemove', onMouseMove);\n\t\t\tdocument.removeEventListener('mouseup', onMouseUp);\n\t\t};\n\n\t\tdocument.addEventListener('mousemove', onMouseMove);\n\t\tdocument.addEventListener('mouseup', onMouseUp);\n\t};\n\n\t#onTouchStart = e => {\n\t\tif (e.target.closest(\"buttons\")) return;\n\n\t\tconst rect = this.#dialog.getBoundingClientRect();\n\t\tconst touch = e.changedTouches[0];\n\t\tthis.#shift = {\n\t\t\tx: touch.pageX - rect.left,\n\t\t\ty: touch.pageY - rect.top\n\t\t};\n\n\t\tconst onTouchMove = (ev) => {\n\t\t\tconst t = ev.changedTouches[0];\n\t\t\tthis.#dialog.style.position = 'fixed';\n\t\t\tthis.#dialog.style.margin = '0';\n\t\t\tthis.#dialog.style.left = `${t.pageX - this.#shift.x}px`;\n\t\t\tthis.#dialog.style.top = `${t.pageY - this.#shift.y}px`;\n\t\t};\n\n\t\tconst onTouchEnd = () => {\n\t\t\tdocument.removeEventListener('touchmove', onTouchMove);\n\t\t\tdocument.removeEventListener('touchend', onTouchEnd);\n\t\t};\n\n\t\tdocument.addEventListener('touchmove', onTouchMove);\n\t\tdocument.addEventListener('touchend', onTouchEnd);\n\t};\n\n\tcloseWithAnimation(returnValue) {\n\t\tthis.#dialog.classList.add(\"out\"); // 퇴장 애니메이션 시작\n\n\t\t// 애니메이션(0.3s)이 끝난 후 제거 및 이벤트 발생\n\t\tsetTimeout(() => {\n\t\t\tthis.#dialog.close();\n\t\t\t// 부모(BasePopup)에게 작업 완료와 결과값을 알림\n\t\t\tthis.dispatchEvent(new CustomEvent('closed', { detail: returnValue }));\n\t\t\tthis.remove();\n\t\t}, 300);\n\t}\n}\n\n// BasePopup.js\nexport class BasePopup extends HTMLElement {\n\n\tconstructor() {\n\t\tsuper();\n\t\tthis.attachShadow({ mode: 'open' });\n\t}\n\n\tstatic async open(PopupClass, message, title, options, renderFn) {\n\t\t// 1. 설정 병합\n\t\tconst tagName = PopupClass.tagName.toLowerCase();\n\t\tconst config = {\n\t\t\t\"true-text\": \"확인\",\n\t\t\t\"false-text\": \"취소\",\n\t\t\tclass: \"classic\",\n\t\t\tanimation: \"fade\",\n\t\t\t...(window.nine?.config?.ux?.[tagName.replace('nine-', '').replace('-popup', '')] || {}),\n\t\t\t...options\n\t\t};\n\n\t\t// 2. 중복 제거 및 엘리먼트 생성\n\t\tdocument.querySelectorAll(tagName).forEach(el => el.remove());\n\t\tconst el = document.createElement(tagName);\n\t\tif (config.class) el.classList.add(config.class);\n\t\tif (config.animation) el.classList.add(config.animation);\n\t\tdocument.body.appendChild(el);\n\n\t\t// 3. 렌더링 (각 팝업의 UI 그리기)\n\t\trenderFn(el, message, config);\n\n\t\tconst dialogComp = el.shadowRoot.querySelector(\"nine-dialog\");\n\t\tif (title) dialogComp.setAttribute(\"title\", title);\n\n\t\treturn new Promise((resolve) => {\n\t\t\t// [중요] nine-dialog의 애니메이션이 끝난 후 던지는 이벤트를 수신\n\t\t\tdialogComp.addEventListener('closed', (e) => resolve(e.detail));\n\n\t\t\t// 각 팝업 클래스에서 버튼 클릭 시 dialogComp.closeWithAnimation(값)을\n\t\t\t// 호출하도록 이벤트를 바인딩해줌\n\t\t\tel.setupEvents(resolve, dialogComp);\n\n\t\t\tdialogComp.showModal();\n\t\t});\n\t}\n}\n\nif (!customElements.get('nine-dialog')) {\n\tcustomElements.define(\"nine-dialog\", nineDialog);\n}\n","import { nine } from \"../../core/Config.js\"; // 설정 참조용\nimport { BasePopup } from \"./nineDialog.js\";\n\nexport class nineConfirmPopup extends BasePopup {\n\tstatic tagName = 'nine-confirm-popup';\n\n\tconstructor() {\n\t\tsuper();\n\t}\n\n\trender(message, config) {\n\t\tthis.shadowRoot.innerHTML = `\n <nine-dialog>\n <div class=\"msg\">${message.replace(/\\n/g, \"<br/>\")}</div>\n <div class=\"buttons-confirm\">\n <button class=\"cancel\">${config[\"false-text\"]}</button>\n <button class=\"ok\">${config[\"true-text\"]}</button>\n </div>\n </nine-dialog>`;\n\t}\n\n\tsetupEvents(resolve, dialogComp) {\n\t\tthis.shadowRoot.querySelector(\".ok\").onclick = () => dialogComp.closeWithAnimation(true);\n\t\t// 취소는 nine-dialog 내부 기본 로직(closeWithAnimation(null))이 처리함\n\t}\n\n\tstatic confirm = (m, t, o) => BasePopup.open(nineConfirmPopup, m, t, o, (el, msg, conf) => el.render(msg, conf));\n}\n\n// --- 3. ALERT (단순 알림) ---\nexport class nineAlertPopup extends BasePopup {\n\tstatic tagName = 'nine-alert-popup';\n\n\tconstructor() {\n\t\tsuper();\n\t}\n\n\trender(message, config) {\n\t\tthis.shadowRoot.innerHTML = `\n <nine-dialog>\n <div class=\"msg\">${message.replace(/\\n/g, \"<br/>\")}</div>\n <div class=\"buttons-confirm\">\n <button class=\"cancel\">확인</button>\n </div>\n </nine-dialog>`;\n\t}\n\n\tsetupEvents(resolve, dialogComp) {\n\t\t// 얼럿은 취소 버튼 하나만 두거나, 확인 버튼이 cancel 역할을 수행하게 함\n\t}\n\n\tstatic alert = (m, t, o) => BasePopup.open(nineAlertPopup, m, t, o, (el, msg, conf) => el.render(msg, conf));\n}\n\n// Custom Element 등록\nif (!customElements.get('nine-confirm-popup')) customElements.define('nine-confirm-popup', nineConfirmPopup);\nif (!customElements.get('nine-alert-popup')) customElements.define(\"nine-alert-popup\", nineAlertPopup);","import { nine } from \"../../core/Config.js\";\nimport { BasePopup } from \"./nineDialog.js\";\n\n/**\n *\n */\nexport class ninePromptPopup extends BasePopup {\n\tstatic tagName = 'nine-prompt-popup';\n\n\tconstructor() {\n\t\tsuper();\n\t}\n\n\trender(message, config) {\n\n\t\ttrace.log(this);\n\t\ttrace.log(this.shadowRoot);\n\n\t\tthis.shadowRoot.innerHTML = `\n\t\t\t<style>\n\t\t\t\tdialog {\n\t\t\t\t\theight: 300px !important;\n\t\t\t\t}\n\t\t\t\t.msg {\n\t\t\t\t\theight: unset !important;\n\t\t\t\t}\n\t\t\t</style>\n\t\t\t\n <nine-dialog>\n <div class=\"msg\">${message.replace(/\\n/g, \"<br/>\")}</div>\n <div class=\"input-area\">\n <textarea placeholder=\"내용을 입력하세요...\"></textarea>\n </div>\n <div class=\"buttons-confirm\">\n <button class=\"cancel\">${config[\"false-text\"]}</button>\n <button class=\"ok\">${config[\"true-text\"]}</button>\n </div>\n </nine-dialog>`;\n\t}\n\n\tsetupEvents(resolve, dialogComp) {\n\t\tconst textarea = this.shadowRoot.querySelector(\"textarea\");\n\t\tconst okBtn = this.shadowRoot.querySelector(\".ok\");\n\n\t\t// 확인 버튼 클릭 시 textarea 값을 가지고 애니메이션 닫기\n\t\tokBtn.onclick = () => dialogComp.closeWithAnimation(textarea.value);\n\n\t\t// 렌더링 후 포커스\n\t\trequestAnimationFrame(() => textarea.focus());\n\t}\n\n\tstatic prompt = (m, t, o) => BasePopup.open(ninePromptPopup, m, t, o, (el, msg, conf) => el.render(msg, conf));\n}\n\nif (!customElements.get('nine-prompt-popup')) {\n\tcustomElements.define('nine-prompt-popup', ninePromptPopup);\n}","// src/core/NineUtil.js\r\nimport { nineAlertPopup, nineConfirmPopup } from './nineConfirm.js';\r\nimport { ninePromptPopup } from \"./ninePrompt.js\";\r\n\r\nexport class NineUtil {\r\n\t// static 필드는 클래스 자체에 저장됨\r\n\tstatic cssPath = \"\";\r\n\r\n\t/**\r\n\t * 팝업 준비 로직 (Private 메서드)\r\n\t */\r\n\t#prepare(type, message, title, defaultClass) {\r\n\r\n\t\tconst options = { class: defaultClass, animation: 'fade' };\r\n\t\t//const popup = type === 'alert' ? nineAlertPopup : (type === 'confirm' ? nineConfirmPopup : ninePromptPopup);\r\n\t\tlet isExecuted = false;\r\n\r\n\t\tconst popupMap = {\r\n\t\t\talert: nineAlertPopup,\r\n\t\t\tconfirm: nineConfirmPopup,\r\n\t\t\tprompt: ninePromptPopup\r\n\t\t};\r\n\r\n\t\tconst popup = popupMap[type];\r\n\r\n\t\tconst runner = {\r\n\t\t\trgb: () => { options.class = 'rgb'; return runner; },\r\n\t\t\tclassic: () => { options.class = 'classic'; return runner; },\r\n\t\t\tshake: () => { options.animation = 'shake'; return runner; },\r\n\t\t\trun: () => { options.animation = 'roadRunner'; return runner; },\r\n\t\t\tzoom: () => { options.animation = 'zoom'; return runner; },\r\n\r\n\t\t\tthen: (resolve, reject) => {\r\n\t\t\t\tisExecuted = true;\r\n\t\t\t\treturn popup[type](message, title, options).then(resolve, reject);\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\t// Microtask: 동기 체이닝이 모두 끝난 후 실행\r\n\t\tPromise.resolve().then(() => {\r\n\t\t\tif (!isExecuted) {\r\n\t\t\t\tisExecuted = true;\r\n\t\t\t\tpopup[type](message, title, options);\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\treturn runner;\r\n\t}\r\n\r\n\talert(message, title = \"Alert\") {\r\n\t\treturn this.#prepare('alert', message, title, 'classic');\r\n\t}\r\n\r\n\tconfirm(message, title = \"Confirm\") {\r\n\t\treturn this.#prepare('confirm', message, title, 'classic');\r\n\t}\r\n\r\n\tprompt(message, title = \"Prompt\") {\r\n\t\treturn this.#prepare('prompt', message, title, 'classic');\r\n\t}\r\n}","export class Trace {\r\n\t#name;\r\n\t#color;\r\n\t#enabled = true;\r\n\r\n\tconstructor(name = null, color = \"green\") {\r\n\t\tthis.#name = name;\r\n\t\tthis.#color = color;\r\n\t\tthis.#autoConfig();\r\n\t\t/**\r\n\t\t// 1. 쪼개진 인스턴스들을 하나로 합치는 '본드' 역할 (이게 핵심!)\r\n\t\tif (typeof window !== 'undefined' && window.__NINE_TRACE__) {\r\n\t\t\treturn window.__NINE_TRACE__;\r\n\t\t}\r\n\t\tthis.#autoConfig();\r\n\t\tif (typeof window !== 'undefined') window.__NINE_TRACE__ = this;\r\n\t\t\t*/\r\n\t}\r\n\r\n\t#autoConfig() {\r\n\t\tif (typeof window === 'undefined') return;\r\n\t\tconst isLocal = window.location.hostname === 'localhost' ||\r\n\t\t\twindow.location.hostname === '127.0.0.1' ||\r\n\t\t\twindow.location.hostname.startsWith('192.168.');\r\n\r\n\t\tif (isLocal) {\r\n\t\t\tthis.enable();\r\n\t\t} else {\r\n\t\t\tthis.disable();\r\n\t\t\tconsole.log(\r\n\t\t\t\t`%c[${this.#name || 'Trace'}]%c 운영 모드: 로그 비활성화. %ctrace.enable()%c 로 활성화 가능`,\r\n\t\t\t\t\"color: #4CAF50; font-weight: bold;\", \"\",\r\n\t\t\t\t\"background: #333; color: yellow; padding: 2px 5px;\", \"\"\r\n\t\t\t);\r\n\t\t}\r\n\t}\r\n\r\n\t// 🟢 빼먹었던 init 메서드 다시 추가!\r\n\tinitBAK(name, color = \"green\") {\r\n\t\tthis.#name = name;\r\n\t\tthis.#color = color;\r\n\t}\r\n\r\n\tinit(name, color = \"green\") {\r\n\t\t//const style = `color: ${color}; font-weight: bold;`;\r\n\t\tthis.#name = name;\r\n\t\tthis.#color = color;\r\n\r\n\t\treturn this;\r\n\t\t/**\r\n\t\tconsole.log(name, color);\r\n\t\treturn {\r\n\t\t\tlog: console.log.bind(console, `%c[${name}]`, style),\r\n\t\t\twarn: console.warn.bind(console, `%c[${name}]`, \"color: cyan; font-weight: bold;\"),\r\n\t\t\terror: console.error.bind(console, `%c[${name}]`, \"color: red; font-weight: bold;\")\r\n\t\t}; */\r\n\t}\r\n\r\n\t//get log() { return console.log.bind(console); }\r\n\r\n\t// 🔴 핵심: 소스 위치를 호출부로 찍어주는 Getter 로직\r\n\tget log() {\r\n\t\t//if (!this.#enabled) return () => {};\r\n\t\tconst style = `color: ${this.#color}; font-weight: bold;`;\r\n\t\t// 이름이 있으면 프리픽스를 붙이고, 없으면 그냥 로그를 바인딩합니다.\r\n\t\treturn (this.#name)\r\n\t\t\t? console.log.bind(console, `%c[${this.#name}]`, style)\r\n\t\t\t: console.log.bind(console);\r\n\t}\r\n\r\n\tget warn() {\r\n\t\tif (!this.#enabled) return () => {};\r\n\t\treturn (this.#name)\r\n\t\t\t? console.warn.bind(console, `%c[${this.#name}]`, \"color: cyan; font-weight: bold;\")\r\n\t\t\t: console.warn.bind(console);\r\n\t}\r\n\r\n\tget error() {\r\n\t\t// 에러는 enabled 상태와 상관없이 찍고 싶으시면 if 체크를 주석 처리하세요.\r\n\t\t// if (!this.#enabled) return () => {};\r\n\t\treturn (this.#name)\r\n\t\t\t? console.error.bind(console, `%c[${this.#name}]`, \"color: red; font-weight: bold;\")\r\n\t\t\t: console.error.bind(console);\r\n\t}\r\n\r\n\tenable() { this.#enabled = true; }\r\n\tdisable() { this.#enabled = false; }\r\n}\r\n\r\nexport const trace = new Trace();\r\nif (typeof window !== 'undefined') window.trace = trace;","export class TaskDebouncer {\r\n\t#timer = null;\r\n\t#queue = [];\r\n\t#delay;\r\n\r\n\tconstructor(delay = 50) {\r\n\t\tthis.#delay = delay;\r\n\t}\r\n\r\n\t/**\r\n\t * @param {Function} func - 실행할 함수\r\n\t * @param {...any} args - 함수에 전달할 임의의 파라미터들\r\n\t */\r\n\texec(func, ...args) {\r\n\t\t// 1. 어떤 함수와 어떤 인자들이 들어왔는지 큐에 저장\r\n\t\tthis.#queue.push({ func, args });\r\n\r\n\t\t// 2. 디바운스 타이머 설정\r\n\t\tif (this.#timer) clearTimeout(this.#timer);\r\n\r\n\t\tthis.#timer = setTimeout(() => this.#flush(), this.#delay);\r\n\t}\r\n\r\n\texecWithKey(key, func, ...args) {\r\n\t\t// 1. 같은 키(예: 'resize')가 들어오면 이전 큐에서 해당 키 삭제 (중복 제거)\r\n\t\tthis.#queue = this.#queue.filter(task => task.key !== key);\r\n\r\n\t\t// 2. 새로운 태스크 추가\r\n\t\tthis.#queue.push({ key, func, args });\r\n\r\n\t\tif (this.#timer) clearTimeout(this.#timer);\r\n\t\tthis.#timer = setTimeout(() => this.#flush(), this.#delay);\r\n\t}\r\n\r\n\t#flush() {\r\n\t\tif (this.#queue.length === 0) return;\r\n\r\n\t\t// 3. 현재까지 쌓인 큐를 쏙 빼옴\r\n\t\tconst tasks = this.#queue.splice(0, this.#queue.length);\r\n\t\tconst seen = new Set();\r\n\r\n\t\ttasks.forEach(task => {\r\n\t\t\t// 4. 핵심: 함수 이름과 인자들을 문자열로 합쳐서 유니크 키 생성\r\n\t\t\t// JSON.stringify를 통해 [1, {a:1}] 같은 파라미터도 문자열로 비교 가능\r\n\t\t\tconst identifier = `${task.func.name}_${JSON.stringify(task.args)}`;\r\n\r\n\t\t\tif (!seen.has(identifier)) {\r\n\t\t\t\t// 5. 중복이 아닐 때만 원래 인자들(...args) 그대로 실행\r\n\t\t\t\ttask.func(...task.args);\r\n\t\t\t\tseen.add(identifier);\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tthis.#timer = null;\r\n\t}\r\n}","export class Loading {\n\tstatic show() {\n\t\tlet overlay = document.getElementById(\"global-loading-overlay\");\n\t\tif (!overlay) {\n\t\t\toverlay = document.createElement(\"div\");\n\t\t\toverlay.id = \"global-loading-overlay\";\n\t\t\toverlay.style.cssText = `\n position: fixed; inset: 0; z-index: 9999;\n background: rgba(0, 0, 0, 0.4); display: flex; \n justify-content: center; align-items: center;\n backdrop-filter: blur(2px);\n `;\n\t\t\toverlay.innerHTML = `<div class=\"loading-spinner\"></div>`;\n\t\t\tdocument.body.appendChild(overlay);\n\n\t\t\tif (!document.getElementById(\"nine-util-style\")) {\n\t\t\t\tconst style = document.createElement(\"style\");\n\t\t\t\tstyle.id = \"nine-util-style\";\n\t\t\t\tstyle.innerHTML = `\n .loading-spinner {\n width: 48px; height: 48px;\n border: 5px solid rgba(255, 255, 255, 0.3);\n border-top-color: white; border-radius: 50%;\n animation: nine-spin 1s linear infinite;\n }\n @keyframes nine-spin { to { transform: rotate(360deg); } }\n `;\n\t\t\t\tdocument.head.appendChild(style);\n\t\t\t}\n\t\t}\n\t\toverlay.style.display = \"flex\";\n\t}\n\n\tstatic hide() {\n\t\tconst overlay = document.getElementById(\"global-loading-overlay\");\n\t\tif (overlay) overlay.style.display = \"none\";\n\t}\n}","import { Loading } from \"../ux/Loading.js\";\nimport { trace } from \"../core/Trace.js\";\n\nexport class Fetch {\n\tstatic BASE_URL = window.__API_BASE_URL__ || \"\";\n\n\tstatic #request = (method, url, data = {}, showLoading = true) => {\n\t\tconst finalUrl = url.startsWith('http') ? url : `${this.BASE_URL}${url}`;\n\n\t\tif (showLoading) {\n\t\t\tLoading.show();\n\t\t}\n\n\t\t// 1. 기본 헤더 설정\n\t\tconst headers = {};\n\n\t\t// 🔴 핵심: 데이터가 FormData가 아닐 때만 JSON 헤더를 추가합니다.\n\t\tif (!(data instanceof FormData)) {\n\t\t\theaders[\"Content-Type\"] = \"application/json\";\n\t\t}\n\n\t\tconst options = {\n\t\t\tmethod,\n\t\t\theaders\n\t\t};\n\n\t\tlet targetUrl = finalUrl;\n\t\tif (method === \"GET\") {\n\t\t\ttargetUrl += `?${new URLSearchParams(data)}`;\n\t\t} else {\n\t\t\t// 🔴 핵심: FormData는 그대로 body에 넣고, 일반 객체는 JSON.stringify 처리합니다.\n\t\t\toptions.body = data instanceof FormData ? data : JSON.stringify(data);\n\t\t}\n\n\t\treturn fetch(targetUrl, options)\n\t\t\t.then(async res => {\n\t\t\t\tif (!res.ok) {\n\t\t\t\t\tconst text = await res.text();\n\t\t\t\t\tthrow new Error(`API 오류 (${res.status}): ${text}`);\n\t\t\t\t}\n\t\t\t\treturn res.json();\n\t\t\t})\n\t\t\t.catch(err => {\n\t\t\t\ttrace.error(`[IdeFetch.${method.toLowerCase()}] ${finalUrl} 실패:`, err);\n\t\t\t\tthrow err;\n\t\t\t})\n\t\t\t.finally(() => {\n\t\t\t\tif (showLoading) {\n\t\t\t\t\tLoading.hide();\n\t\t\t\t}\n\t\t\t});\n\t};\n\n\t// 기존 post/get 메서드도 인자를 넘겨주도록 수정\n\tstatic get = (url, data = {}, showLoading = true) => this.#request(\"GET\", url, data, showLoading);\n\tstatic post = (url, data = {}, showLoading = true) => this.#request(\"POST\", url, data, showLoading);\n\n\t/**\n\t * 🚀 범용 청크 전송 (파라미터 이름까지 동적 설정)\n\t * @param {string} url - API 주소\n\t * @param {Array} rows - 데이터 배열\n\t * @param {object} options - 상세 옵션\n\t * - fileKey: 객체 내 파일 속성명 (기본: 'fileContents')\n\t * - filePartName: 서버에서 받을 파일 파트명 (기본: 'files')\n\t * - jsonPartName: 서버에서 받을 JSON 파트명 (기본: 'dataList')\n\t * - chunkSize: 분할 단위 (기본: 10)\n\t */\n\tstatic postMultipart = async (url, rows = [], options = {}) => {\n\t\tconst {\n\t\t\tfileKey = 'fileContents',\n\t\t\tfilePartName = 'files',\n\t\t\tjsonPartName = 'dataList',\n\t\t\tchunkSize = 10\n\t\t} = options;\n\n\t\t// 1. 시작 전 로딩바 띄우기\n\t\tLoading.show();\n\n\t\tlet totalCount = 0;\n\t\tlet lastResponse = null;\n\n\t\t// 🔴 2. 전체 루프를 Promise 체인처럼 관리 (내부는 await 유지)\n\t\treturn (async () => {\n\t\t\tfor (let i = 0; i < rows.length; i += chunkSize) {\n\t\t\t\tconst formData = new FormData();\n\t\t\t\tconst chunk = rows.slice(i, i + chunkSize);\n\t\t\t\tconst rowDataList = [];\n\n\t\t\t\tchunk.forEach((row) => {\n\t\t\t\t\tconst { [fileKey]: fileObj, _fileObj, ...rest } = row;\n\t\t\t\t\trowDataList.push(rest);\n\t\t\t\t\tif (fileObj instanceof File) {\n\t\t\t\t\t\tformData.append(filePartName, fileObj);\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tconst jsonBlob = new Blob([JSON.stringify(rowDataList)], { type: 'application/json' });\n\t\t\t\tformData.append(jsonPartName, jsonBlob);\n\n\t\t\t\t// showLoading = false로 내부 호출\n\t\t\t\tlastResponse = await this.post(url, formData, false);\n\n\t\t\t\tif (lastResponse && (lastResponse.success || lastResponse.status === 'OK')) {\n\t\t\t\t\ttotalCount += chunk.length;\n\t\t\t\t} else {\n\t\t\t\t\tthrow new Error(`청크 전송 실패: ${i}번째 섹션`);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn { ...lastResponse, success: true, totalCount };\n\t\t})()\n\t\t\t.catch(err => {\n\t\t\t\ttrace.error(\"[postChunk] Error:\", err);\n\t\t\t\tthrow err;\n\t\t\t})\n\t\t\t.finally(() => {\n\t\t\t\t// 🔴 3. 성공하든 실패하든 여기서 깔끔하게 닫기!\n\t\t\t\tLoading.hide();\n\t\t\t});\n\t};\n}\n\nexport const api = Fetch;","import { NineUtil } from \"./dialog/NineUtil.js\";\r\nimport { trace } from \"../core/Trace.js\";\r\n\r\nclass UxSplitter extends HTMLElement {\r\n\r\n\t#mode;\r\n\r\n\tconstructor() {\r\n\t\tsuper();\r\n\t\tthis.attachShadow({ mode: \"open\" });\r\n\t}\r\n\r\n\tconnectedCallback() {\r\n\r\n\t\tthis.#init();\r\n\t}\r\n\r\n\t#detectMode = (el) => {\r\n\t\tconst prev = el.previousElementSibling;\r\n\t\tconst next = el.nextElementSibling;\r\n\t\tif (!prev || !next) {\r\n\t\t\tthis.#mode = this.classList.contains('h') ? \"h\" : \"v\";\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst prevRect = prev.getBoundingClientRect();\r\n\t\tconst nextRect = next.getBoundingClientRect();\r\n\r\n\t\tif (this.classList.contains('h')) {\r\n\t\t\tthis.#mode = \"h\";\r\n\t\t} else if (this.classList.contains('v')) {\r\n\t\t\tthis.#mode = \"v\";\r\n\t\t} else {\r\n\t\t\tthis.#mode = (Math.abs(prevRect.top - nextRect.top) < 5) ? \"h\" : \"v\";\r\n\t\t}\r\n\t};\r\n\r\n\t#startDrag = (e) => {\r\n\t\te.preventDefault();\r\n\t\te.stopPropagation();\r\n\r\n\t\tconst splitterRect = this.getBoundingClientRect();\r\n\t\tconst isHorizontal = this.#mode === \"h\";\r\n\r\n\t\t// 마우스 포인터와 스플리터 시작점 사이의 거리\r\n\t\tconst clickOffset = isHorizontal\r\n\t\t\t? e.clientX - splitterRect.left\r\n\t\t\t: e.clientY - splitterRect.top;\r\n\r\n\t\tconst dragBar = document.createElement(\"div\");\r\n\t\tdragBar.className = `nx-splitter-drag-bar-${this.#mode}`;\r\n\r\n\t\tObject.assign(dragBar.style, {\r\n\t\t\tposition: \"absolute\",\r\n\t\t\tzIndex: \"999\",\r\n\t\t\tbackground: \"#666\",\r\n\t\t\topacity: \"0.6\",\r\n\t\t\tpointerEvents: \"none\"\r\n\t\t});\r\n\r\n\t\tconst root = this.getRootNode({ composed: true });\r\n\t\tconst parent = root instanceof ShadowRoot ? root.host : this.parentElement;\r\n\t\tconst prev = this.previousElementSibling;\r\n\t\tconst next = this.nextElementSibling;\r\n\r\n\t\tif (!parent || !prev || !next) {\r\n\t\t\ttrace.warn(\"Spliter's parent or siblings not found.\");\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t(parent.shadowRoot || parent).appendChild(dragBar);\r\n\t\tconst dragBarOffsetParentRect = dragBar.offsetParent.getBoundingClientRect();\r\n\r\n\t\tconst prevRect = prev.getBoundingClientRect();\r\n\t\tconst nextRect = next.getBoundingClientRect();\r\n\r\n\t\t// 드래그 바의 초기 위치와 크기 설정\r\n\t\tconst initialSplitterPosInParent = (isHorizontal\r\n\t\t\t? splitterRect.left - dragBarOffsetParentRect.left\r\n\t\t\t: splitterRect.top - dragBarOffsetParentRect.top) + clickOffset;\r\n\r\n\t\tif (isHorizontal) {\r\n\t\t\tdragBar.style.top = \"0\";\r\n\t\t\tdragBar.style.left = `${initialSplitterPosInParent}px`;\r\n\t\t\tdragBar.style.width = \"2px\";\r\n\t\t\tdragBar.style.height = \"100%\";\r\n\t\t} else {\r\n\t\t\tdragBar.style.left = \"0\";\r\n\t\t\tdragBar.style.top = `${initialSplitterPosInParent}px`;\r\n\t\t\tdragBar.style.height = \"2px\";\r\n\t\t\tdragBar.style.width = \"100%\";\r\n\t\t}\r\n\r\n\t\tdragBar.style.mixBlendMode = \"difference\";\r\n\t\tdragBar.style.zIndex = \"99999\";\r\n\r\n\t\tconst minLimit = isHorizontal\r\n\t\t\t? prevRect.left - dragBarOffsetParentRect.left\r\n\t\t\t: prevRect.top - dragBarOffsetParentRect.top;\r\n\t\tconst maxLimit = isHorizontal\r\n\t\t\t? nextRect.right - dragBarOffsetParentRect.left - splitterRect.width\r\n\t\t\t: nextRect.bottom - dragBarOffsetParentRect.top - splitterRect.height;\r\n\r\n\t\tconst onMove = moveEvent => {\r\n\t\t\tconst clientPos = isHorizontal ? moveEvent.clientX : moveEvent.clientY;\r\n\t\t\tconst currentPosInParent = isHorizontal\r\n\t\t\t\t? clientPos - dragBarOffsetParentRect.left\r\n\t\t\t\t: clientPos - dragBarOffsetParentRect.top;\r\n\r\n\t\t\tconst clampedPos = Math.max(minLimit, Math.min(currentPosInParent, maxLimit));\r\n\r\n\t\t\tif (isHorizontal) {\r\n\t\t\t\tdragBar.style.left = `${clampedPos}px`;\r\n\t\t\t} else {\r\n\t\t\t\tdragBar.style.top = `${clampedPos}px`;\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\tconst onUp = () => {\r\n\t\t\twindow.removeEventListener(\"mousemove\", onMove);\r\n\t\t\twindow.removeEventListener(\"mouseup\", onUp);\r\n\t\t\tdragBar.remove();\r\n\r\n\t\t\tconst allChildren = Array.from(parent.children);\r\n\t\t\tconst allPanels = allChildren.filter(el => el.tagName.toLowerCase() !== 'nx-splitter');\r\n\r\n\t\t\t// ⭐⭐ gap 크기 계산 ⭐⭐\r\n\t\t\tconst style = window.getComputedStyle(parent);\r\n\t\t\tconst gapValue = isHorizontal ? style.getPropertyValue('column-gap') : style.getPropertyValue('row-gap');\r\n\t\t\tconst gapSize = parseFloat(gapValue) || 0;\r\n\t\t\tconst gapCount = allChildren.length > 1 ? allChildren.length - 1 : 0;\r\n\t\t\tconst totalGapSize = gapCount * gapSize;\r\n\r\n\t\t\tconst finalDragBarPos = isHorizontal ? parseFloat(dragBar.style.left) : parseFloat(dragBar.style.top);\r\n\t\t\tconst dragOffset = finalDragBarPos - initialSplitterPosInParent;\r\n\r\n\t\t\tconst prevSize = isHorizontal ? prev.getBoundingClientRect().width : prev.getBoundingClientRect().height;\r\n\t\t\tconst nextSize = isHorizontal ? next.getBoundingClientRect().width : next.getBoundingClientRect().height;\r\n\r\n\t\t\tlet newPrevSize = prevSize + dragOffset;\r\n\t\t\tlet newNextSize = nextSize - dragOffset;\r\n\r\n\t\t\t// 패널 크기가 음수가 되지 않도록 제한하고, 다른 패널에 차이를 보정\r\n\t\t\tif (newPrevSize < 0) {\r\n\t\t\t\tnewNextSize += newPrevSize;\r\n\t\t\t\tnewPrevSize = 0;\r\n\t\t\t}\r\n\t\t\tif (newNextSize < 0) {\r\n\t\t\t\tnewPrevSize += newNextSize;\r\n\t\t\t\tnewNextSize = 0;\r\n\t\t\t}\r\n\r\n\t\t\tconst initialSizes = allPanels.map(panel => isHorizontal ? panel.getBoundingClientRect().width : panel.getBoundingClientRect().height);\r\n\r\n\t\t\tconst totalSplitterSize = allChildren.reduce((sum, child) => {\r\n\t\t\t\tif (child.tagName.toLowerCase() === 'nx-splitter') {\r\n\t\t\t\t\treturn sum + (isHorizontal ? child.getBoundingClientRect().width : child.getBoundingClientRect().height);\r\n\t\t\t\t}\r\n\t\t\t\treturn sum;\r\n\t\t\t}, 0);\r\n\r\n\t\t\tconst totalContainerSize = (isHorizontal ? parent.getBoundingClientRect().width : parent.getBoundingClientRect().height);\r\n\t\t\tconst totalFlexSpace = totalContainerSize - totalSplitterSize - totalGapSize;\r\n\r\n\t\t\tlet flexSum = 0;\r\n\t\t\tallPanels.forEach((panel, index) => {\r\n\t\t\t\tlet newSize;\r\n\t\t\t\tif (panel === prev) {\r\n\t\t\t\t\tnewSize = newPrevSize;\r\n\t\t\t\t} else if (panel === next) {\r\n\t\t\t\t\tnewSize = newNextSize;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tnewSize = initialSizes[index];\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst newFlexBasis = newSize / totalFlexSpace;\r\n\t\t\t\t//panel.style.flex = `${newFlexBasis} ${newFlexBasis} 0`;\r\n\r\n\t\t\t\ttrace.log(panel);\r\n\r\n\t\t\t\tif (panel.classList.contains('sidebar')) {\r\n\t\t\t\t\t// 드래그가 끝난 시점의 newSize(px)를 그대로 고정값으로 할당\r\n\t\t\t\t\t// 이렇게 하면 비율(%)이 아니라 딱 그 픽셀만큼만 자리를 차지하게 됩니다.\r\n\t\t\t\t\tpanel.style.flex = `0 0 ${newSize}px`;\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// 나머지 메인 보드 같은 유연한 패널은 비율(%)로 처리\r\n\t\t\t\t\t//const newFlexBasis = newSize / totalFlexSpace;\r\n\t\t\t\t\tpanel.style.flex = `${newFlexBasis} ${newFlexBasis} 0`;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tflexSum += newFlexBasis;\r\n\t\t\t});\r\n\r\n\t\t\ttrace.log(`dragOffset: ${dragOffset}`);\r\n\t\t\ttrace.log(`Calculated FlexSum: ${flexSum}`);\r\n\t\t};\r\n\r\n\t\twindow.addEventListener(\"mousemove\", onMove);\r\n\t\twindow.addEventListener(\"mouseup\", onUp);\r\n\t};\r\n\r\n\tget cssPath() {\r\n\t\treturn this.getAttribute(\"css-path\") || NineUtil.cssPath;\r\n\t}\r\n\r\n\t#init = () => {\r\n\t\tthis.#detectMode(this);\r\n\t\tthis.classList.add(this.#mode);\r\n\r\n\t\tconst contents = this.innerHTML.trim();\r\n\t\t//const gripClass = `grip-${this.#mode}`;\r\n\t\tconst gripTmpl = (contents === \"\") ? `<div class=\"grip\"></div>` : `<div class=\"grip\"></div><div class=\"inner-container\">${contents}</div><div class=\"grip\"></div>`;\r\n\r\n\t\tthis.innerHTML = \"\";\r\n\t\tconst htmlTmpl = document.createElement(\"template\");\r\n\t\thtmlTmpl.innerHTML = `\r\n\t\t\t<style>\r\n\t\t\t\t@import \"https://cdn.jsdelivr.net/npm/@nine-lab/nine-util@${__APP_VERSION__}/dist/css/nine-util.css\";\r\n\t\t\t\t${this.cssPath ? `@import \"${this.cssPath}\";` : \"\"}\r\n\t\t\t</style>\r\n\t\t\t${gripTmpl}\r\n `;\r\n\r\n\t\tthis.shadowRoot.appendChild(htmlTmpl.content.cloneNode(true));\r\n\r\n\t\tthis.shadowRoot.querySelectorAll(\".grip\").forEach(el => {\r\n\t\t\tel.addEventListener(\"mousedown\", e => this.#startDrag(e));\r\n\t\t});\r\n\r\n\t\tthis.#prepareLayout();\r\n\r\n\t\twindow.addEventListener(\"resize\", () => this.#prepareLayout());\r\n\t};\r\n\r\n\t#prepareLayout = () => {\r\n\t\tconst isHorizontal = this.#mode === \"h\";\r\n\t\tconst parent = this.parentElement;\r\n\t\tconst allPanels = Array.from(parent.children).filter(el => el.tagName.toLowerCase() !== 'nx-splitter');\r\n\t\tif (allPanels.length < 2) return;\r\n\r\n\t\tconst parentRect = parent.getBoundingClientRect();\r\n\t\tconst totalContentSize = allPanels.reduce((sum, el) => {\r\n\t\t\tconst size = isHorizontal ? el.getBoundingClientRect().width : el.getBoundingClientRect().height;\r\n\t\t\treturn sum + size;\r\n\t\t}, 0);\r\n\t\tconst totalParentSize = isHorizontal ? parentRect.width : parentRect.height;\r\n\r\n\t\tallPanels.forEach(panel => {\r\n\t\t\tconst size = isHorizontal ? panel.getBoundingClientRect().width : panel.getBoundingClientRect().height;\r\n\t\t\tconst newSize = totalParentSize * (size / totalContentSize);\r\n\t\t\tconst flexGrow = newSize / totalParentSize;\r\n\t\t\tpanel.style.flex = `${flexGrow} ${flexGrow} 0`;\r\n\t\t});\r\n\t};\r\n}\r\n\r\nif (!customElements.get('nine-splitter')) {\r\n\tcustomElements.define(\"nine-splitter\", UxSplitter);\r\n}","// 1. 기존 core 모듈\r\nimport { NineUtil } from './ux/dialog/NineUtil.js';\r\nimport { nine, subscribeConfig, config } from './core/Config.js';\r\nimport { Trace, trace } from './core/Trace.js';\r\nimport { TaskDebouncer } from './core/TaskDebouncer.js';\r\n\r\n// 2. 신규 net 및 ux 모듈 추가\r\nimport { api, Fetch } from './net/Fetch.js';\r\nimport { Loading } from './ux/Loading.js';\r\n\r\nimport { nineDialog } from './ux/dialog/nineDialog.js';\r\nimport { nineConfirmPopup, nineAlertPopup } from './ux/dialog/nineConfirm.js';\r\nimport { ninePromptPopup } from './ux/dialog/ninePrompt.js';\r\n\r\n// ux\r\nimport './ux/UxSplitter.js';\r\n\r\nconst utilInstance = new NineUtil();\r\nnine.alert = utilInstance.alert.bind(utilInstance);\r\nnine.confirm = utilInstance.confirm.bind(utilInstance);\r\nnine.prompt = utilInstance.prompt.bind(utilInstance);\r\n\r\n// 기존 nine 객체(Config)와 Util 기능을 합성\r\n//Object.assign(nine, utilInstance);\r\n\r\nnine.api = api;\r\nnine.trace = trace;\r\nnine.subscribeConfig = subscribeConfig;\r\nnine.config = config || {};\r\n\r\nexport {\r\n\tnine,\r\n\tsubscribeConfig,\r\n\tconfig,\r\n\tNineUtil,\r\n\tTrace,\r\n\ttrace,\r\n\tTaskDebouncer,\r\n\tapi, // 🚀 추가: 이제 서비스에서 api.get() 가능\r\n\tFetch, // 🚀 추가: 클래스 자체도 혹시 모르니 노출\r\n\tLoading as loading, // 🚀 추가: loading.show() 로 쓰기 편하게 alias\r\n\tnineDialog,\r\n\tnineAlertPopup, nineConfirmPopup, ninePromptPopup\r\n};\r\n\r\nif (typeof window !== 'undefined') {\r\n\twindow.nine = nine;\r\n}\r\n"],"names":["listeners","Set","_initialConfig","ux","nativeOverride","theme","board","readOnly","cssPath","debug","window","__NINE_GLOBAL_CONFIG__","_config","subscribeConfig","fn","add","delete","config","Proxy","set","target","prop","value","forEach","get","nine","this","setup","options","Object","entries","key","Array","isArray","nineDialog","HTMLElement","constructor","super","__privateAdd","_shift","_dialog","__publicField","__privateGet","showModal","close","remove","_init","querySelector","querySelectorAll","btn","onclick","closeWithAnimation","_onMouseDown","e","closest","button","altKey","ctrlKey","shiftKey","rect","getBoundingClientRect","__privateSet","x","clientX","left","y","clientY","top","onMouseMove","ev","style","position","margin","onMouseUp","document","removeEventListener","addEventListener","_onTouchStart","touch","changedTouches","pageX","pageY","onTouchMove","t","onTouchEnd","connectedCallback","v","innerHTML","titleText","getAttribute","trace","log","call","returnValue","classList","setTimeout","dispatchEvent","CustomEvent","detail","WeakMap","BasePopup","attachShadow","mode","open","PopupClass","message","title","renderFn","tagName","toLowerCase","class","animation","_c","_b","_a","replace","el","createElement","body","appendChild","dialogComp","shadowRoot","setAttribute","Promise","resolve","setupEvents","customElements","define","_nineConfirmPopup","render","m","o","msg","conf","nineConfirmPopup","_nineAlertPopup","nineAlertPopup","_ninePromptPopup","textarea","requestAnimationFrame","focus","ninePromptPopup","NineUtil","_NineUtil_instances","alert","__privateMethod","prepare_fn","confirm","prompt","WeakSet","type","defaultClass","isExecuted","popup","runner","rgb","classic","shake","run","zoom","then","reject","Trace","name","color","_Trace_instances","_name","_color","_enabled","autoConfig_fn","initBAK","init","console","bind","warn","error","enable","disable","location","hostname","startsWith","_timer","_queue","_delay","_TaskDebouncer_instances","flush_fn","length","tasks","splice","seen","task","identifier","func","JSON","stringify","args","has","Loading","show","overlay","getElementById","id","cssText","head","display","hide","_Fetch","_request","__API_BASE_URL__","method","url","data","showLoading","finalUrl","BASE_URL","headers","FormData","targetUrl","URLSearchParams","fetch","async","res","ok","text","Error","status","json","catch","err","finally","rows","fileKey","filePartName","jsonPartName","chunkSize","totalCount","lastResponse","i","formData","chunk","slice","rowDataList","row","fileObj","_fileObj","rest","push","File","append","jsonBlob","Blob","post","success","Fetch","api","UxSplitter","_mode","_detectMode","prev","previousElementSibling","next","nextElementSibling","contains","prevRect","nextRect","Math","abs","_startDrag","preventDefault","stopPropagation","splitterRect","isHorizontal","clickOffset","dragBar","className","assign","zIndex","background","opacity","pointerEvents","root","getRootNode","composed","parent","ShadowRoot","host","parentElement","dragBarOffsetParentRect","offsetParent","initialSplitterPosInParent","width","height","mixBlendMode","minLimit","maxLimit","right","bottom","onMove","moveEvent","clientPos","currentPosInParent","clampedPos","max","min","onUp","allChildren","from","children","allPanels","filter","getComputedStyle","gapValue","getPropertyValue","gapSize","parseFloat","totalGapSize","dragOffset","prevSize","nextSize","newPrevSize","newNextSize","initialSizes","map","panel","totalSplitterSize","reduce","sum","child","totalFlexSpace","flexSum","index","newSize","newFlexBasis","flex","contents","trim","gripTmpl","htmlTmpl","content","cloneNode","_prepareLayout","parentRect","totalContentSize","totalParentSize","size","flexGrow","utilInstance","delay","exec","clearTimeout","execWithKey"],"mappings":"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"}
1
+ {"version":3,"file":"nine-util.umd.js","sources":["../src/ux/dialog/nineDialog.js","../src/ux/dialog/nineConfirm.js","../src/ux/dialog/ninePrompt.js","../src/ux/dialog/NineUtil.js","../src/core/Config.js","../src/core/Trace.js","../src/core/TaskDebouncer.js","../src/external/NoPeer.js","../src/ux/Loading.js","../src/net/Fetch.js","../src/ux/UxSplitter.js","../src/index.js","../src/utils/promise.js"],"sourcesContent":["import { dialogStyles } from './style.dialog.js';\n\nexport class nineDialog extends HTMLElement\n{\n\t#shift;\n\t#dialog;\n\n\n\tconstructor () {\n\t\tsuper();\n\t}\n\n\tconnectedCallback() {\n\n\t\tconst v = this.innerHTML;\n\t\tconst titleText = this.getAttribute(\"title\") || \"Details\";\n\n\t\ttrace.log(\"111111111\")\n\n\t\tthis.innerHTML = `\n\t\t\t<style>${dialogStyles}</style>\n\t\t\n\t\t\t<dialog>\n\t\t\t\t<div class=\"head\">\n\t\t\t\t\t<div class=\"rect1\"></div>\n\t\t\t\t\t<div class=\"rect2\"></div>\n\t\t\t\t\t<div class=\"rect3\"></div>\n\t\t\t\t\t<ng-sphere class=\"icon\" end-fill=\"#666\" size=\"8\"></ng-sphere>\n\t\t\t\t\t<span class=\"title\">${titleText}</span>\n\t\t\t\t\t<span class=\"sub-title\"></span>\n\t\t\t\t\t<div class=\"buttons\">\n\t\t\t\t\t\t<ng-sphere class=\"apply\" start-fill=\"#cc6\" end-fill=\"#660\" size=\"16\" title=\"apply\"></ng-sphere>\n\t\t\t\t\t\t<ng-sphere class=\"reset\" start-fill=\"#99f\" end-fill=\"#00f\" size=\"16\" title=\"reset\"></ng-sphere>\n\t\t\t\t\t\t<ng-sphere class=\"close\" start-fill=\"#f99\" end-fill=\"#f00\" size=\"16\" title=\"close\"></ng-sphere>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"contents\">\n\t\t\t\t\t<div class=\"left\">\n\t\t\t\t\t\t<span>가나다라마바사아자차카타파하가나다라마바사아자차카타파하가나다라마바사아자차카타파하가나다라마바사아자차카타파하가나다라마바사아자차카타파하가나다라마바사아자차카타파하가나다라마바사아자차카타파하가나다라마바사아자차카타파하</span>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"body\">\n\t\t\t\t\t\t${v}\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"close2\">\n\t\t\t\t\t\t<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" viewBox=\"0 0 16 16\">\n\t\t\t\t\t\t\t<path d=\"M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708\"/>\n\t\t\t\t\t\t</svg>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</dialog>\n\t\t`;\n\n\t\t//this.#owner = this.getRootNode().host.closest(\"nine-grid\");\n\n\t\t//$(\".title\", this).html(\"Details\");\n\n\t\tthis.#dialog = this.querySelector('dialog');\n\t\tthis.#init();\n\t};\n\n\tshowModal = () => {\n\t\tthis.#dialog.showModal();\n\t};\n\n\tclose = () => {\n\t\t// 이벤트 리스너 제거 (표준 방식은 핸들러 참조가 필요하지만,\n\t\t// 여기서는 요소가 사라지므로 메모리 관리를 위해 정리)\n\t\tthis.#dialog.close();\n\t\tthis.remove();\n\t};\n\n\t#init = () => {\n\t\tconst head = this.querySelector('.head');\n\n\t\t// 1. 모든 닫기 성격의 버튼 (.close, .close2, .cancel) 공통 처리\n\t\tthis.querySelectorAll('.close, .close2, .cancel').forEach(btn => {\n\t\t\tbtn.onclick = () => this.closeWithAnimation(null); // 취소/닫기는 null 리턴\n\t\t});\n\n\t\t// 2. 확인 버튼 (.ok) 처리\n\t\t// 확인 버튼은 텍스트 입력값 등 데이터가 필요하므로\n\t\t// 실제 데이터 추출은 각 팝업 클래스(prompt 등)에서 하되,\n\t\t// 닫기 애니메이션 실행은 여기서 담당하도록 가이드합니다.\n\t\tthis.querySelectorAll('.ok').forEach(btn => {\n\t\t\t// .ok 버튼의 로직은 각 팝업의 setupEvents에서 덮어쓰거나\n\t\t\t// 델리게이트 이벤트를 통해 처리합니다.\n\t\t});\n\n\t\t// 드래그 로직 생략...\n\t};\n\n\t// --- 드래그 로직 (Vanilla JS) ---\n\t#onMouseDown = e => {\n\t\tif (e.target.closest(\"buttons\")) return;\n\t\tif (e.button !== 0 || e.altKey || e.ctrlKey || e.shiftKey) return;\n\n\t\tconst rect = this.#dialog.getBoundingClientRect();\n\t\tthis.#shift = {\n\t\t\tx: e.clientX - rect.left,\n\t\t\ty: e.clientY - rect.top\n\t\t};\n\n\t\tconst onMouseMove = (ev) => {\n\t\t\tthis.#dialog.style.position = 'fixed';\n\t\t\tthis.#dialog.style.margin = '0';\n\t\t\tthis.#dialog.style.left = `${ev.clientX - this.#shift.x}px`;\n\t\t\tthis.#dialog.style.top = `${ev.clientY - this.#shift.y}px`;\n\t\t};\n\n\t\tconst onMouseUp = () => {\n\t\t\tdocument.removeEventListener('mousemove', onMouseMove);\n\t\t\tdocument.removeEventListener('mouseup', onMouseUp);\n\t\t};\n\n\t\tdocument.addEventListener('mousemove', onMouseMove);\n\t\tdocument.addEventListener('mouseup', onMouseUp);\n\t};\n\n\t#onTouchStart = e => {\n\t\tif (e.target.closest(\"buttons\")) return;\n\n\t\tconst rect = this.#dialog.getBoundingClientRect();\n\t\tconst touch = e.changedTouches[0];\n\t\tthis.#shift = {\n\t\t\tx: touch.pageX - rect.left,\n\t\t\ty: touch.pageY - rect.top\n\t\t};\n\n\t\tconst onTouchMove = (ev) => {\n\t\t\tconst t = ev.changedTouches[0];\n\t\t\tthis.#dialog.style.position = 'fixed';\n\t\t\tthis.#dialog.style.margin = '0';\n\t\t\tthis.#dialog.style.left = `${t.pageX - this.#shift.x}px`;\n\t\t\tthis.#dialog.style.top = `${t.pageY - this.#shift.y}px`;\n\t\t};\n\n\t\tconst onTouchEnd = () => {\n\t\t\tdocument.removeEventListener('touchmove', onTouchMove);\n\t\t\tdocument.removeEventListener('touchend', onTouchEnd);\n\t\t};\n\n\t\tdocument.addEventListener('touchmove', onTouchMove);\n\t\tdocument.addEventListener('touchend', onTouchEnd);\n\t};\n\n\tcloseWithAnimation(returnValue) {\n\t\tthis.#dialog.classList.add(\"out\"); // 퇴장 애니메이션 시작\n\n\t\t// 애니메이션(0.3s)이 끝난 후 제거 및 이벤트 발생\n\t\tsetTimeout(() => {\n\t\t\tthis.#dialog.close();\n\t\t\t// 부모(BasePopup)에게 작업 완료와 결과값을 알림\n\t\t\tthis.dispatchEvent(new CustomEvent('closed', { detail: returnValue }));\n\t\t\tthis.remove();\n\t\t}, 300);\n\t}\n}\n\n// BasePopup.js\nexport class BasePopup extends HTMLElement {\n\n\tconstructor() {\n\t\tsuper();\n\t\tthis.attachShadow({ mode: 'open' });\n\t}\n\n\tstatic async open(PopupClass, message, title, options, renderFn) {\n\t\t// 1. 설정 병합\n\t\tconst tagName = PopupClass.tagName.toLowerCase();\n\t\tconst config = {\n\t\t\t\"true-text\": \"확인\",\n\t\t\t\"false-text\": \"취소\",\n\t\t\tclass: \"classic\",\n\t\t\tanimation: \"fade\",\n\t\t\t...(window.nine?.config?.ux?.[tagName.replace('nine-', '').replace('-popup', '')] || {}),\n\t\t\t...options\n\t\t};\n\n\t\t// 2. 중복 제거 및 엘리먼트 생성\n\t\tdocument.querySelectorAll(tagName).forEach(el => el.remove());\n\t\tconst el = document.createElement(tagName);\n\t\tif (config.class) el.classList.add(config.class);\n\t\tif (config.animation) el.classList.add(config.animation);\n\t\tdocument.body.appendChild(el);\n\n\t\t// 3. 렌더링 (각 팝업의 UI 그리기)\n\t\trenderFn(el, message, config);\n\n\t\tconst dialogComp = el.shadowRoot.querySelector(\"nine-dialog\");\n\t\tif (title) dialogComp.setAttribute(\"title\", title);\n\n\t\treturn new Promise((resolve) => {\n\t\t\t// [중요] nine-dialog의 애니메이션이 끝난 후 던지는 이벤트를 수신\n\t\t\tdialogComp.addEventListener('closed', (e) => resolve(e.detail));\n\n\t\t\t// 각 팝업 클래스에서 버튼 클릭 시 dialogComp.closeWithAnimation(값)을\n\t\t\t// 호출하도록 이벤트를 바인딩해줌\n\t\t\tel.setupEvents(resolve, dialogComp);\n\n\t\t\tdialogComp.showModal();\n\t\t});\n\t}\n}\n\nif (!customElements.get('nine-dialog')) {\n\tcustomElements.define(\"nine-dialog\", nineDialog);\n}\n","import { BasePopup } from \"./nineDialog.js\";\n\nexport class nineConfirmPopup extends BasePopup {\n\tstatic tagName = 'nine-confirm-popup';\n\n\tconstructor() {\n\t\tsuper();\n\t}\n\n\trender(message, config) {\n\t\tthis.shadowRoot.innerHTML = `\n <nine-dialog>\n <div class=\"msg\">${message.replace(/\\n/g, \"<br/>\")}</div>\n <div class=\"buttons-confirm\">\n <button class=\"cancel\">${config[\"false-text\"]}</button>\n <button class=\"ok\">${config[\"true-text\"]}</button>\n </div>\n </nine-dialog>`;\n\t}\n\n\tsetupEvents(resolve, dialogComp) {\n\t\tthis.shadowRoot.querySelector(\".ok\").onclick = () => dialogComp.closeWithAnimation(true);\n\t\t// 취소는 nine-dialog 내부 기본 로직(closeWithAnimation(null))이 처리함\n\t}\n\n\tstatic confirm = (m, t, o) => BasePopup.open(nineConfirmPopup, m, t, o, (el, msg, conf) => el.render(msg, conf));\n}\n\n// --- 3. ALERT (단순 알림) ---\nexport class nineAlertPopup extends BasePopup {\n\tstatic tagName = 'nine-alert-popup';\n\n\tconstructor() {\n\t\tsuper();\n\t}\n\n\trender(message, config) {\n\t\tthis.shadowRoot.innerHTML = `\n <nine-dialog>\n <div class=\"msg\">${message.replace(/\\n/g, \"<br/>\")}</div>\n <div class=\"buttons-confirm\">\n <button class=\"cancel\">확인</button>\n </div>\n </nine-dialog>`;\n\t}\n\n\tsetupEvents(resolve, dialogComp) {\n\t\t// 얼럿은 취소 버튼 하나만 두거나, 확인 버튼이 cancel 역할을 수행하게 함\n\t}\n\n\tstatic alert = (m, t, o) => BasePopup.open(nineAlertPopup, m, t, o, (el, msg, conf) => el.render(msg, conf));\n}\n\n// Custom Element 등록\nif (!customElements.get('nine-confirm-popup')) customElements.define('nine-confirm-popup', nineConfirmPopup);\nif (!customElements.get('nine-alert-popup')) customElements.define(\"nine-alert-popup\", nineAlertPopup);","import { BasePopup } from \"./nineDialog.js\";\n\n/**\n *\n */\nexport class ninePromptPopup extends BasePopup {\n\tstatic tagName = 'nine-prompt-popup';\n\n\tconstructor() {\n\t\tsuper();\n\t}\n\n\trender(message, config) {\n\n\t\ttrace.log(this);\n\t\ttrace.log(this.shadowRoot);\n\n\t\tthis.shadowRoot.innerHTML = `\n\t\t\t<style>\n\t\t\t\tdialog {\n\t\t\t\t\theight: 300px !important;\n\t\t\t\t}\n\t\t\t\t.msg {\n\t\t\t\t\theight: unset !important;\n\t\t\t\t}\n\t\t\t</style>\n\t\t\t\n <nine-dialog>\n <div class=\"msg\">${message.replace(/\\n/g, \"<br/>\")}</div>\n <div class=\"input-area\">\n <textarea placeholder=\"내용을 입력하세요...\"></textarea>\n </div>\n <div class=\"buttons-confirm\">\n <button class=\"cancel\">${config[\"false-text\"]}</button>\n <button class=\"ok\">${config[\"true-text\"]}</button>\n </div>\n </nine-dialog>`;\n\t}\n\n\tsetupEvents(resolve, dialogComp) {\n\t\tconst textarea = this.shadowRoot.querySelector(\"textarea\");\n\t\tconst okBtn = this.shadowRoot.querySelector(\".ok\");\n\n\t\t// 확인 버튼 클릭 시 textarea 값을 가지고 애니메이션 닫기\n\t\tokBtn.onclick = () => dialogComp.closeWithAnimation(textarea.value);\n\n\t\t// 렌더링 후 포커스\n\t\trequestAnimationFrame(() => textarea.focus());\n\t}\n\n\tstatic prompt = (m, t, o) => BasePopup.open(ninePromptPopup, m, t, o, (el, msg, conf) => el.render(msg, conf));\n}\n\nif (!customElements.get('nine-prompt-popup')) {\n\tcustomElements.define('nine-prompt-popup', ninePromptPopup);\n}","// src/core/NineUtil.js\r\nimport { nineAlertPopup, nineConfirmPopup } from './nineConfirm.js';\r\nimport { ninePromptPopup } from \"./ninePrompt.js\";\r\n\r\nexport class NineUtil {\r\n\t// static 필드는 클래스 자체에 저장됨\r\n\tstatic cssPath = \"\";\r\n\r\n\t/**\r\n\t * 팝업 준비 로직 (Private 메서드)\r\n\t */\r\n\t#prepare(type, message, title, defaultClass) {\r\n\r\n\t\tconst options = { class: defaultClass, animation: 'fade' };\r\n\t\t//const popup = type === 'alert' ? nineAlertPopup : (type === 'confirm' ? nineConfirmPopup : ninePromptPopup);\r\n\t\tlet isExecuted = false;\r\n\r\n\t\tconst popupMap = {\r\n\t\t\talert: nineAlertPopup,\r\n\t\t\tconfirm: nineConfirmPopup,\r\n\t\t\tprompt: ninePromptPopup\r\n\t\t};\r\n\r\n\t\tconst popup = popupMap[type];\r\n\r\n\t\tconst runner = {\r\n\t\t\trgb: () => { options.class = 'rgb'; return runner; },\r\n\t\t\tclassic: () => { options.class = 'classic'; return runner; },\r\n\t\t\tshake: () => { options.animation = 'shake'; return runner; },\r\n\t\t\trun: () => { options.animation = 'roadRunner'; return runner; },\r\n\t\t\tzoom: () => { options.animation = 'zoom'; return runner; },\r\n\r\n\t\t\tthen: (resolve, reject) => {\r\n\t\t\t\tisExecuted = true;\r\n\t\t\t\treturn popup[type](message, title, options).then(resolve, reject);\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\t// Microtask: 동기 체이닝이 모두 끝난 후 실행\r\n\t\tPromise.resolve().then(() => {\r\n\t\t\tif (!isExecuted) {\r\n\t\t\t\tisExecuted = true;\r\n\t\t\t\tpopup[type](message, title, options);\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\treturn runner;\r\n\t}\r\n\r\n\talert(message, title = \"Alert\") {\r\n\t\treturn this.#prepare('alert', message, title, 'classic');\r\n\t}\r\n\r\n\tconfirm(message, title = \"Confirm\") {\r\n\t\treturn this.#prepare('confirm', message, title, 'classic');\r\n\t}\r\n\r\n\tprompt(message, title = \"Prompt\") {\r\n\t\treturn this.#prepare('prompt', message, title, 'classic');\r\n\t}\r\n}","const listeners = new Set();\r\n\r\n// 💡 [핵심] 전역 저장소를 단일화합니다.\r\n// window에 이미 있으면 그것을 쓰고, 없으면 초기값을 생성하여 등록합니다.\r\nconst _initialConfig = {\r\n\tux: { nativeOverride: false, theme: 'light' },\r\n\tboard: { readOnly: false },\r\n\tcssPath: \"\",\r\n\tdebug: false\r\n};\r\n\r\nif (typeof window !== 'undefined' && !window.__NINE_GLOBAL_CONFIG__) {\r\n\twindow.__NINE_GLOBAL_CONFIG__ = _initialConfig;\r\n}\r\n\r\n// 이제 모든 모듈의 _config는 동일한 window 객체 메모리를 가리킵니다.\r\nconst _config = typeof window !== 'undefined' ? window.__NINE_GLOBAL_CONFIG__ : _initialConfig;\r\n\r\nexport const subscribeConfig = (fn) => {\r\n\tlisteners.add(fn);\r\n\tfn('all', _config);\r\n\treturn () => listeners.delete(fn);\r\n};\r\n\r\n// Proxy 역시 전역 저장소인 _config를 조작합니다.\r\nexport const config = new Proxy(_config, {\r\n\tset(target, prop, value) {\r\n\t\ttarget[prop] = value;\r\n\t\tlisteners.forEach(fn => fn(prop, target));\r\n\t\treturn true;\r\n\t},\r\n\tget(target, prop) {\r\n\t\treturn target[prop];\r\n\t}\r\n});\r\n\r\nexport const nine = {\r\n\tconfig: config,\r\n\r\n\t// Getter에서 window.nine까지 확인할 필요도 없습니다.\r\n\t// 이미 config 자체가 전역 저장소(__NINE_GLOBAL_CONFIG__)를 바라보고 있기 때문입니다.\r\n\tget cssPath() {\r\n\t\treturn this.config.cssPath || \"\";\r\n\t},\r\n\r\n\tsetup(options = {}) {\r\n\t\tObject.entries(options).forEach(([key, value]) => {\r\n\t\t\t// 깊은 병합 지원\r\n\t\t\tif (typeof value === 'object' && value !== null && !Array.isArray(value)) {\r\n\t\t\t\tthis.config[key] = { ...this.config[key], ...value };\r\n\t\t\t} else {\r\n\t\t\t\tthis.config[key] = value;\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\t// 다른 모듈에서 window.nine으로 접근할 수 있도록 보장\r\n\t\tif (typeof window !== 'undefined') {\r\n\t\t\twindow.nine = window.nine || this;\r\n\t\t}\r\n\t}\r\n};","export class Trace {\r\n\t#name;\r\n\t#color;\r\n\t#enabled = true;\r\n\r\n\tconstructor(name = null, color = \"green\") {\r\n\t\tthis.#name = name;\r\n\t\tthis.#color = color;\r\n\t\tthis.#autoConfig();\r\n\t\t/**\r\n\t\t// 1. 쪼개진 인스턴스들을 하나로 합치는 '본드' 역할 (이게 핵심!)\r\n\t\tif (typeof window !== 'undefined' && window.__NINE_TRACE__) {\r\n\t\t\treturn window.__NINE_TRACE__;\r\n\t\t}\r\n\t\tthis.#autoConfig();\r\n\t\tif (typeof window !== 'undefined') window.__NINE_TRACE__ = this;\r\n\t\t\t*/\r\n\t}\r\n\r\n\t#autoConfig() {\r\n\t\tif (typeof window === 'undefined') return;\r\n\t\tconst isLocal = window.location.hostname === 'localhost' ||\r\n\t\t\twindow.location.hostname === '127.0.0.1' ||\r\n\t\t\twindow.location.hostname.startsWith('192.168.');\r\n\r\n\t\tif (isLocal) {\r\n\t\t\tthis.enable();\r\n\t\t} else {\r\n\t\t\tthis.disable();\r\n\t\t\tconsole.log(\r\n\t\t\t\t`%c[${this.#name || 'Trace'}]%c 운영 모드: 로그 비활성화. %ctrace.enable()%c 로 활성화 가능`,\r\n\t\t\t\t\"color: #4CAF50; font-weight: bold;\", \"\",\r\n\t\t\t\t\"background: #333; color: yellow; padding: 2px 5px;\", \"\"\r\n\t\t\t);\r\n\t\t}\r\n\t}\r\n\r\n\t// 🟢 빼먹었던 init 메서드 다시 추가!\r\n\tinitBAK(name, color = \"green\") {\r\n\t\tthis.#name = name;\r\n\t\tthis.#color = color;\r\n\t}\r\n\r\n\tinit(name, color = \"green\") {\r\n\t\t//const style = `color: ${color}; font-weight: bold;`;\r\n\t\tthis.#name = name;\r\n\t\tthis.#color = color;\r\n\r\n\t\treturn this;\r\n\t\t/**\r\n\t\tconsole.log(name, color);\r\n\t\treturn {\r\n\t\t\tlog: console.log.bind(console, `%c[${name}]`, style),\r\n\t\t\twarn: console.warn.bind(console, `%c[${name}]`, \"color: cyan; font-weight: bold;\"),\r\n\t\t\terror: console.error.bind(console, `%c[${name}]`, \"color: red; font-weight: bold;\")\r\n\t\t}; */\r\n\t}\r\n\r\n\t//get log() { return console.log.bind(console); }\r\n\r\n\t// 🔴 핵심: 소스 위치를 호출부로 찍어주는 Getter 로직\r\n\tget log() {\r\n\t\t//if (!this.#enabled) return () => {};\r\n\t\tconst style = `color: ${this.#color}; font-weight: bold;`;\r\n\t\t// 이름이 있으면 프리픽스를 붙이고, 없으면 그냥 로그를 바인딩합니다.\r\n\t\treturn (this.#name)\r\n\t\t\t? console.log.bind(console, `%c[${this.#name}]`, style)\r\n\t\t\t: console.log.bind(console);\r\n\t}\r\n\r\n\tget warn() {\r\n\t\tif (!this.#enabled) return () => {};\r\n\t\treturn (this.#name)\r\n\t\t\t? console.warn.bind(console, `%c[${this.#name}]`, \"color: cyan; font-weight: bold;\")\r\n\t\t\t: console.warn.bind(console);\r\n\t}\r\n\r\n\tget error() {\r\n\t\t// 에러는 enabled 상태와 상관없이 찍고 싶으시면 if 체크를 주석 처리하세요.\r\n\t\t// if (!this.#enabled) return () => {};\r\n\t\treturn (this.#name)\r\n\t\t\t? console.error.bind(console, `%c[${this.#name}]`, \"color: red; font-weight: bold;\")\r\n\t\t\t: console.error.bind(console);\r\n\t}\r\n\r\n\tenable() { this.#enabled = true; }\r\n\tdisable() { this.#enabled = false; }\r\n}\r\n\r\nexport const trace = new Trace();\r\nif (typeof window !== 'undefined') window.trace = trace;","export class TaskDebouncer {\r\n\t#timer = null;\r\n\t#queue = [];\r\n\t#delay;\r\n\r\n\tconstructor(delay = 50) {\r\n\t\tthis.#delay = delay;\r\n\t}\r\n\r\n\t/**\r\n\t * @param {Function} func - 실행할 함수\r\n\t * @param {...any} args - 함수에 전달할 임의의 파라미터들\r\n\t */\r\n\texec(func, ...args) {\r\n\t\t// 1. 어떤 함수와 어떤 인자들이 들어왔는지 큐에 저장\r\n\t\tthis.#queue.push({ func, args });\r\n\r\n\t\t// 2. 디바운스 타이머 설정\r\n\t\tif (this.#timer) clearTimeout(this.#timer);\r\n\r\n\t\tthis.#timer = setTimeout(() => this.#flush(), this.#delay);\r\n\t}\r\n\r\n\texecWithKey(key, func, ...args) {\r\n\t\t// 1. 같은 키(예: 'resize')가 들어오면 이전 큐에서 해당 키 삭제 (중복 제거)\r\n\t\tthis.#queue = this.#queue.filter(task => task.key !== key);\r\n\r\n\t\t// 2. 새로운 태스크 추가\r\n\t\tthis.#queue.push({ key, func, args });\r\n\r\n\t\tif (this.#timer) clearTimeout(this.#timer);\r\n\t\tthis.#timer = setTimeout(() => this.#flush(), this.#delay);\r\n\t}\r\n\r\n\t#flush() {\r\n\t\tif (this.#queue.length === 0) return;\r\n\r\n\t\t// 3. 현재까지 쌓인 큐를 쏙 빼옴\r\n\t\tconst tasks = this.#queue.splice(0, this.#queue.length);\r\n\t\tconst seen = new Set();\r\n\r\n\t\ttasks.forEach(task => {\r\n\t\t\t// 4. 핵심: 함수 이름과 인자들을 문자열로 합쳐서 유니크 키 생성\r\n\t\t\t// JSON.stringify를 통해 [1, {a:1}] 같은 파라미터도 문자열로 비교 가능\r\n\t\t\tconst identifier = `${task.func.name}_${JSON.stringify(task.args)}`;\r\n\r\n\t\t\tif (!seen.has(identifier)) {\r\n\t\t\t\t// 5. 중복이 아닐 때만 원래 인자들(...args) 그대로 실행\r\n\t\t\t\ttask.func(...task.args);\r\n\t\t\t\tseen.add(identifier);\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tthis.#timer = null;\r\n\t}\r\n}","import { trace as traceOrigin } from '../core/Trace.js';\n\nexport class Trace extends traceOrigin.constructor {\n constructor() {\n super();\n this.init(\"nine-util\", \"green\");\n }\n}\n\nexport const trace = new Trace();","export class Loading {\n\tstatic show() {\n\t\tlet overlay = document.getElementById(\"global-loading-overlay\");\n\t\tif (!overlay) {\n\t\t\toverlay = document.createElement(\"div\");\n\t\t\toverlay.id = \"global-loading-overlay\";\n\t\t\toverlay.style.cssText = `\n position: fixed; inset: 0; z-index: 9999;\n background: rgba(0, 0, 0, 0.4); display: flex; \n justify-content: center; align-items: center;\n backdrop-filter: blur(2px);\n `;\n\t\t\toverlay.innerHTML = `<div class=\"loading-spinner\"></div>`;\n\t\t\tdocument.body.appendChild(overlay);\n\n\t\t\tif (!document.getElementById(\"nine-util-style\")) {\n\t\t\t\tconst style = document.createElement(\"style\");\n\t\t\t\tstyle.id = \"nine-util-style\";\n\t\t\t\tstyle.innerHTML = `\n .loading-spinner {\n width: 48px; height: 48px;\n border: 5px solid rgba(255, 255, 255, 0.3);\n border-top-color: white; border-radius: 50%;\n animation: nine-spin 1s linear infinite;\n }\n @keyframes nine-spin { to { transform: rotate(360deg); } }\n `;\n\t\t\t\tdocument.head.appendChild(style);\n\t\t\t}\n\t\t}\n\t\toverlay.style.display = \"flex\";\n\t}\n\n\tstatic hide() {\n\t\tconst overlay = document.getElementById(\"global-loading-overlay\");\n\t\tif (overlay) overlay.style.display = \"none\";\n\t}\n}","import { trace } from \"@nopeer\";\nimport { Loading } from \"../ux/Loading.js\";\n\nexport class Fetch {\n\tstatic BASE_URL = window.__API_BASE_URL__ || \"\";\n\n\tstatic #request = (method, url, data = {}, showLoading = true) => {\n\t\tconst finalUrl = url.startsWith('http') ? url : `${this.BASE_URL}${url}`;\n\n\t\tif (showLoading) {\n\t\t\tLoading.show();\n\t\t}\n\n\t\t// 1. 기본 헤더 설정\n\t\tconst headers = {};\n\n\t\t// 🔴 핵심: 데이터가 FormData가 아닐 때만 JSON 헤더를 추가합니다.\n\t\tif (!(data instanceof FormData)) {\n\t\t\theaders[\"Content-Type\"] = \"application/json\";\n\t\t}\n\n\t\tconst options = {\n\t\t\tmethod,\n\t\t\theaders\n\t\t};\n\n\t\tlet targetUrl = finalUrl;\n\t\tif (method === \"GET\") {\n\t\t\ttargetUrl += `?${new URLSearchParams(data)}`;\n\t\t} else {\n\t\t\t// 🔴 핵심: FormData는 그대로 body에 넣고, 일반 객체는 JSON.stringify 처리합니다.\n\t\t\toptions.body = data instanceof FormData ? data : JSON.stringify(data);\n\t\t}\n\n\t\treturn fetch(targetUrl, options)\n\t\t\t.then(async res => {\n\t\t\t\tif (!res.ok) {\n\t\t\t\t\tconst text = await res.text();\n\t\t\t\t\tthrow new Error(`API 오류 (${res.status}): ${text}`);\n\t\t\t\t}\n\t\t\t\treturn res.json();\n\t\t\t})\n\t\t\t.catch(err => {\n\t\t\t\ttrace.error(`[IdeFetch.${method.toLowerCase()}] ${finalUrl} 실패:`, err);\n\t\t\t\tthrow err;\n\t\t\t})\n\t\t\t.finally(() => {\n\t\t\t\tif (showLoading) {\n\t\t\t\t\tLoading.hide();\n\t\t\t\t}\n\t\t\t});\n\t};\n\n\t// 기존 post/get 메서드도 인자를 넘겨주도록 수정\n\tstatic get = (url, data = {}, showLoading = true) => this.#request(\"GET\", url, data, showLoading);\n\tstatic post = (url, data = {}, showLoading = true) => this.#request(\"POST\", url, data, showLoading);\n\n\t/**\n\t * 🚀 범용 청크 전송 (파라미터 이름까지 동적 설정)\n\t * @param {string} url - API 주소\n\t * @param {Array} rows - 데이터 배열\n\t * @param {object} options - 상세 옵션\n\t * - fileKey: 객체 내 파일 속성명 (기본: 'fileContents')\n\t * - filePartName: 서버에서 받을 파일 파트명 (기본: 'files')\n\t * - jsonPartName: 서버에서 받을 JSON 파트명 (기본: 'dataList')\n\t * - chunkSize: 분할 단위 (기본: 10)\n\t */\n\tstatic postMultipart = async (url, rows = [], options = {}) => {\n\t\tconst {\n\t\t\tfileKey = 'fileContents',\n\t\t\tfilePartName = 'files',\n\t\t\tjsonPartName = 'dataList',\n\t\t\tchunkSize = 10\n\t\t} = options;\n\n\t\t// 1. 시작 전 로딩바 띄우기\n\t\tLoading.show();\n\n\t\tlet totalCount = 0;\n\t\tlet lastResponse = null;\n\n\t\t// 🔴 2. 전체 루프를 Promise 체인처럼 관리 (내부는 await 유지)\n\t\treturn (async () => {\n\t\t\tfor (let i = 0; i < rows.length; i += chunkSize) {\n\t\t\t\tconst formData = new FormData();\n\t\t\t\tconst chunk = rows.slice(i, i + chunkSize);\n\t\t\t\tconst rowDataList = [];\n\n\t\t\t\tchunk.forEach((row) => {\n\t\t\t\t\tconst { [fileKey]: fileObj, _fileObj, ...rest } = row;\n\t\t\t\t\trowDataList.push(rest);\n\t\t\t\t\tif (fileObj instanceof File) {\n\t\t\t\t\t\tformData.append(filePartName, fileObj);\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tconst jsonBlob = new Blob([JSON.stringify(rowDataList)], { type: 'application/json' });\n\t\t\t\tformData.append(jsonPartName, jsonBlob);\n\n\t\t\t\t// showLoading = false로 내부 호출\n\t\t\t\tlastResponse = await this.post(url, formData, false);\n\n\t\t\t\tif (lastResponse && (lastResponse.success || lastResponse.status === 'OK')) {\n\t\t\t\t\ttotalCount += chunk.length;\n\t\t\t\t} else {\n\t\t\t\t\tthrow new Error(`청크 전송 실패: ${i}번째 섹션`);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn { ...lastResponse, success: true, totalCount };\n\t\t})()\n\t\t\t.catch(err => {\n\t\t\t\ttrace.error(\"[postChunk] Error:\", err);\n\t\t\t\tthrow err;\n\t\t\t})\n\t\t\t.finally(() => {\n\t\t\t\t// 🔴 3. 성공하든 실패하든 여기서 깔끔하게 닫기!\n\t\t\t\tLoading.hide();\n\t\t\t});\n\t};\n}\n\nexport const api = Fetch;","import { trace } from \"@nopeer\";\r\nimport { NineUtil } from \"./dialog/NineUtil.js\";\r\n\r\nclass UxSplitter extends HTMLElement {\r\n\r\n\t#mode;\r\n\r\n\tconstructor() {\r\n\t\tsuper();\r\n\t\tthis.attachShadow({ mode: \"open\" });\r\n\t}\r\n\r\n\tconnectedCallback() {\r\n\r\n\t\tthis.#init();\r\n\t}\r\n\r\n\t#detectMode = (el) => {\r\n\t\tconst prev = el.previousElementSibling;\r\n\t\tconst next = el.nextElementSibling;\r\n\t\tif (!prev || !next) {\r\n\t\t\tthis.#mode = this.classList.contains('h') ? \"h\" : \"v\";\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst prevRect = prev.getBoundingClientRect();\r\n\t\tconst nextRect = next.getBoundingClientRect();\r\n\r\n\t\tif (this.classList.contains('h')) {\r\n\t\t\tthis.#mode = \"h\";\r\n\t\t} else if (this.classList.contains('v')) {\r\n\t\t\tthis.#mode = \"v\";\r\n\t\t} else {\r\n\t\t\tthis.#mode = (Math.abs(prevRect.top - nextRect.top) < 5) ? \"h\" : \"v\";\r\n\t\t}\r\n\t};\r\n\r\n\t#startDrag = (e) => {\r\n\t\te.preventDefault();\r\n\t\te.stopPropagation();\r\n\r\n\t\tconst splitterRect = this.getBoundingClientRect();\r\n\t\tconst isHorizontal = this.#mode === \"h\";\r\n\r\n\t\t// 마우스 포인터와 스플리터 시작점 사이의 거리\r\n\t\tconst clickOffset = isHorizontal\r\n\t\t\t? e.clientX - splitterRect.left\r\n\t\t\t: e.clientY - splitterRect.top;\r\n\r\n\t\tconst dragBar = document.createElement(\"div\");\r\n\t\tdragBar.className = `nx-splitter-drag-bar-${this.#mode}`;\r\n\r\n\t\tObject.assign(dragBar.style, {\r\n\t\t\tposition: \"absolute\",\r\n\t\t\tzIndex: \"999\",\r\n\t\t\tbackground: \"#666\",\r\n\t\t\topacity: \"0.6\",\r\n\t\t\tpointerEvents: \"none\"\r\n\t\t});\r\n\r\n\t\tconst root = this.getRootNode({ composed: true });\r\n\t\tconst parent = root instanceof ShadowRoot ? root.host : this.parentElement;\r\n\t\tconst prev = this.previousElementSibling;\r\n\t\tconst next = this.nextElementSibling;\r\n\r\n\t\tif (!parent || !prev || !next) {\r\n\t\t\ttrace.warn(\"Spliter's parent or siblings not found.\");\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t(parent.shadowRoot || parent).appendChild(dragBar);\r\n\t\tconst dragBarOffsetParentRect = dragBar.offsetParent.getBoundingClientRect();\r\n\r\n\t\tconst prevRect = prev.getBoundingClientRect();\r\n\t\tconst nextRect = next.getBoundingClientRect();\r\n\r\n\t\t// 드래그 바의 초기 위치와 크기 설정\r\n\t\tconst initialSplitterPosInParent = (isHorizontal\r\n\t\t\t? splitterRect.left - dragBarOffsetParentRect.left\r\n\t\t\t: splitterRect.top - dragBarOffsetParentRect.top) + clickOffset;\r\n\r\n\t\tif (isHorizontal) {\r\n\t\t\tdragBar.style.top = \"0\";\r\n\t\t\tdragBar.style.left = `${initialSplitterPosInParent}px`;\r\n\t\t\tdragBar.style.width = \"2px\";\r\n\t\t\tdragBar.style.height = \"100%\";\r\n\t\t} else {\r\n\t\t\tdragBar.style.left = \"0\";\r\n\t\t\tdragBar.style.top = `${initialSplitterPosInParent}px`;\r\n\t\t\tdragBar.style.height = \"2px\";\r\n\t\t\tdragBar.style.width = \"100%\";\r\n\t\t}\r\n\r\n\t\tdragBar.style.mixBlendMode = \"difference\";\r\n\t\tdragBar.style.zIndex = \"99999\";\r\n\r\n\t\tconst minLimit = isHorizontal\r\n\t\t\t? prevRect.left - dragBarOffsetParentRect.left\r\n\t\t\t: prevRect.top - dragBarOffsetParentRect.top;\r\n\t\tconst maxLimit = isHorizontal\r\n\t\t\t? nextRect.right - dragBarOffsetParentRect.left - splitterRect.width\r\n\t\t\t: nextRect.bottom - dragBarOffsetParentRect.top - splitterRect.height;\r\n\r\n\t\tconst onMove = moveEvent => {\r\n\t\t\tconst clientPos = isHorizontal ? moveEvent.clientX : moveEvent.clientY;\r\n\t\t\tconst currentPosInParent = isHorizontal\r\n\t\t\t\t? clientPos - dragBarOffsetParentRect.left\r\n\t\t\t\t: clientPos - dragBarOffsetParentRect.top;\r\n\r\n\t\t\tconst clampedPos = Math.max(minLimit, Math.min(currentPosInParent, maxLimit));\r\n\r\n\t\t\tif (isHorizontal) {\r\n\t\t\t\tdragBar.style.left = `${clampedPos}px`;\r\n\t\t\t} else {\r\n\t\t\t\tdragBar.style.top = `${clampedPos}px`;\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\tconst onUp = () => {\r\n\t\t\twindow.removeEventListener(\"mousemove\", onMove);\r\n\t\t\twindow.removeEventListener(\"mouseup\", onUp);\r\n\t\t\tdragBar.remove();\r\n\r\n\t\t\tconst allChildren = Array.from(parent.children);\r\n\t\t\tconst allPanels = allChildren.filter(el => el.tagName.toLowerCase() !== 'nx-splitter');\r\n\r\n\t\t\t// ⭐⭐ gap 크기 계산 ⭐⭐\r\n\t\t\tconst style = window.getComputedStyle(parent);\r\n\t\t\tconst gapValue = isHorizontal ? style.getPropertyValue('column-gap') : style.getPropertyValue('row-gap');\r\n\t\t\tconst gapSize = parseFloat(gapValue) || 0;\r\n\t\t\tconst gapCount = allChildren.length > 1 ? allChildren.length - 1 : 0;\r\n\t\t\tconst totalGapSize = gapCount * gapSize;\r\n\r\n\t\t\tconst finalDragBarPos = isHorizontal ? parseFloat(dragBar.style.left) : parseFloat(dragBar.style.top);\r\n\t\t\tconst dragOffset = finalDragBarPos - initialSplitterPosInParent;\r\n\r\n\t\t\tconst prevSize = isHorizontal ? prev.getBoundingClientRect().width : prev.getBoundingClientRect().height;\r\n\t\t\tconst nextSize = isHorizontal ? next.getBoundingClientRect().width : next.getBoundingClientRect().height;\r\n\r\n\t\t\tlet newPrevSize = prevSize + dragOffset;\r\n\t\t\tlet newNextSize = nextSize - dragOffset;\r\n\r\n\t\t\t// 패널 크기가 음수가 되지 않도록 제한하고, 다른 패널에 차이를 보정\r\n\t\t\tif (newPrevSize < 0) {\r\n\t\t\t\tnewNextSize += newPrevSize;\r\n\t\t\t\tnewPrevSize = 0;\r\n\t\t\t}\r\n\t\t\tif (newNextSize < 0) {\r\n\t\t\t\tnewPrevSize += newNextSize;\r\n\t\t\t\tnewNextSize = 0;\r\n\t\t\t}\r\n\r\n\t\t\tconst initialSizes = allPanels.map(panel => isHorizontal ? panel.getBoundingClientRect().width : panel.getBoundingClientRect().height);\r\n\r\n\t\t\tconst totalSplitterSize = allChildren.reduce((sum, child) => {\r\n\t\t\t\tif (child.tagName.toLowerCase() === 'nx-splitter') {\r\n\t\t\t\t\treturn sum + (isHorizontal ? child.getBoundingClientRect().width : child.getBoundingClientRect().height);\r\n\t\t\t\t}\r\n\t\t\t\treturn sum;\r\n\t\t\t}, 0);\r\n\r\n\t\t\tconst totalContainerSize = (isHorizontal ? parent.getBoundingClientRect().width : parent.getBoundingClientRect().height);\r\n\t\t\tconst totalFlexSpace = totalContainerSize - totalSplitterSize - totalGapSize;\r\n\r\n\t\t\tlet flexSum = 0;\r\n\t\t\tallPanels.forEach((panel, index) => {\r\n\t\t\t\tlet newSize;\r\n\t\t\t\tif (panel === prev) {\r\n\t\t\t\t\tnewSize = newPrevSize;\r\n\t\t\t\t} else if (panel === next) {\r\n\t\t\t\t\tnewSize = newNextSize;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tnewSize = initialSizes[index];\r\n\t\t\t\t}\r\n\r\n\t\t\t\tconst newFlexBasis = newSize / totalFlexSpace;\r\n\t\t\t\t//panel.style.flex = `${newFlexBasis} ${newFlexBasis} 0`;\r\n\r\n\t\t\t\ttrace.log(panel);\r\n\r\n\t\t\t\tif (panel.classList.contains('sidebar')) {\r\n\t\t\t\t\t// 드래그가 끝난 시점의 newSize(px)를 그대로 고정값으로 할당\r\n\t\t\t\t\t// 이렇게 하면 비율(%)이 아니라 딱 그 픽셀만큼만 자리를 차지하게 됩니다.\r\n\t\t\t\t\tpanel.style.flex = `0 0 ${newSize}px`;\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// 나머지 메인 보드 같은 유연한 패널은 비율(%)로 처리\r\n\t\t\t\t\t//const newFlexBasis = newSize / totalFlexSpace;\r\n\t\t\t\t\tpanel.style.flex = `${newFlexBasis} ${newFlexBasis} 0`;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tflexSum += newFlexBasis;\r\n\t\t\t});\r\n\r\n\t\t\ttrace.log(`dragOffset: ${dragOffset}`);\r\n\t\t\ttrace.log(`Calculated FlexSum: ${flexSum}`);\r\n\t\t};\r\n\r\n\t\twindow.addEventListener(\"mousemove\", onMove);\r\n\t\twindow.addEventListener(\"mouseup\", onUp);\r\n\t};\r\n\r\n\tget cssPath() {\r\n\t\treturn this.getAttribute(\"css-path\") || NineUtil.cssPath;\r\n\t}\r\n\r\n\t#init = () => {\r\n\t\tthis.#detectMode(this);\r\n\t\tthis.classList.add(this.#mode);\r\n\r\n\t\tconst contents = this.innerHTML.trim();\r\n\t\t//const gripClass = `grip-${this.#mode}`;\r\n\t\tconst gripTmpl = (contents === \"\") ? `<div class=\"grip\"></div>` : `<div class=\"grip\"></div><div class=\"inner-container\">${contents}</div><div class=\"grip\"></div>`;\r\n\r\n\t\tthis.innerHTML = \"\";\r\n\t\tconst htmlTmpl = document.createElement(\"template\");\r\n\t\thtmlTmpl.innerHTML = `\r\n\t\t\t<style>\r\n\t\t\t\t@import \"https://cdn.jsdelivr.net/npm/@nine-lab/nine-util@${__APP_VERSION__}/dist/css/nine-util.css\";\r\n\t\t\t\t${this.cssPath ? `@import \"${this.cssPath}\";` : \"\"}\r\n\t\t\t</style>\r\n\t\t\t${gripTmpl}\r\n `;\r\n\r\n\t\tthis.shadowRoot.appendChild(htmlTmpl.content.cloneNode(true));\r\n\r\n\t\tthis.shadowRoot.querySelectorAll(\".grip\").forEach(el => {\r\n\t\t\tel.addEventListener(\"mousedown\", e => this.#startDrag(e));\r\n\t\t});\r\n\r\n\t\tthis.#prepareLayout();\r\n\r\n\t\twindow.addEventListener(\"resize\", () => this.#prepareLayout());\r\n\t};\r\n\r\n\t#prepareLayout = () => {\r\n\t\tconst isHorizontal = this.#mode === \"h\";\r\n\t\tconst parent = this.parentElement;\r\n\t\tconst allPanels = Array.from(parent.children).filter(el => el.tagName.toLowerCase() !== 'nx-splitter');\r\n\t\tif (allPanels.length < 2) return;\r\n\r\n\t\tconst parentRect = parent.getBoundingClientRect();\r\n\t\tconst totalContentSize = allPanels.reduce((sum, el) => {\r\n\t\t\tconst size = isHorizontal ? el.getBoundingClientRect().width : el.getBoundingClientRect().height;\r\n\t\t\treturn sum + size;\r\n\t\t}, 0);\r\n\t\tconst totalParentSize = isHorizontal ? parentRect.width : parentRect.height;\r\n\r\n\t\tallPanels.forEach(panel => {\r\n\t\t\tconst size = isHorizontal ? panel.getBoundingClientRect().width : panel.getBoundingClientRect().height;\r\n\t\t\tconst newSize = totalParentSize * (size / totalContentSize);\r\n\t\t\tconst flexGrow = newSize / totalParentSize;\r\n\t\t\tpanel.style.flex = `${flexGrow} ${flexGrow} 0`;\r\n\t\t});\r\n\t};\r\n}\r\n\r\nif (!customElements.get('nine-splitter')) {\r\n\tcustomElements.define(\"nine-splitter\", UxSplitter);\r\n}","// 1. 기존 core 모듈\r\nimport { NineUtil } from './ux/dialog/NineUtil.js';\r\nimport { nine, subscribeConfig, config } from './core/Config.js';\r\nimport { Trace, trace } from './core/Trace.js';\r\nimport { TaskDebouncer } from './core/TaskDebouncer.js';\r\n\r\n// 2. 신규 net 및 ux 모듈 추가\r\nimport { api, Fetch } from './net/Fetch.js';\r\nimport { Loading } from './ux/Loading.js';\r\n\r\nimport { nineDialog } from './ux/dialog/nineDialog.js';\r\nimport { nineConfirmPopup, nineAlertPopup } from './ux/dialog/nineConfirm.js';\r\nimport { ninePromptPopup } from './ux/dialog/ninePrompt.js';\r\n\r\nimport { safe } from \"./utils/promise.js\"; // 경로에 맞춰 임포트\r\n// ux\r\nimport './ux/UxSplitter.js';\r\n\r\nconst utilInstance = new NineUtil();\r\nnine.alert = utilInstance.alert.bind(utilInstance);\r\nnine.confirm = utilInstance.confirm.bind(utilInstance);\r\nnine.prompt = utilInstance.prompt.bind(utilInstance);\r\n\r\nnine.safe = safe;\r\n\r\n// 기존 nine 객체(Config)와 Util 기능을 합성\r\n//Object.assign(nine, utilInstance);\r\n\r\nnine.api = api;\r\nnine.trace = trace;\r\nnine.subscribeConfig = subscribeConfig;\r\nnine.config = config || {};\r\n\r\nexport {\r\n\tnine,\r\n\tsubscribeConfig,\r\n\tconfig,\r\n\tNineUtil,\r\n\tTrace,\r\n\ttrace,\r\n\tTaskDebouncer,\r\n\tapi, // 🚀 추가: 이제 서비스에서 api.get() 가능\r\n\tFetch, // 🚀 추가: 클래스 자체도 혹시 모르니 노출\r\n\tLoading as loading, // 🚀 추가: loading.show() 로 쓰기 편하게 alias\r\n\tnineDialog,\r\n\tnineAlertPopup, nineConfirmPopup, ninePromptPopup\r\n};\r\n\r\nif (typeof window !== 'undefined') {\r\n\twindow.nine = nine;\r\n}\r\n","/**\r\n * 비동기 함수를 try-catch 없이 안전하게 실행하게 도와주는 유틸리티\r\n * @param {Promise} promise\r\n * @returns {Promise<[any, Error|null]>}\r\n */\r\nexport const safe = async (promise) => {\r\n\ttry {\r\n\t\tconst data = await promise;\r\n\t\treturn [data, null];\r\n\t} catch (err) {\r\n\t\treturn [null, err];\r\n\t}\r\n};"],"names":["nineDialog","HTMLElement","constructor","super","__privateAdd","this","_shift","_dialog","__publicField","__privateGet","showModal","close","remove","_init","querySelector","querySelectorAll","forEach","btn","onclick","closeWithAnimation","_onMouseDown","e","target","closest","button","altKey","ctrlKey","shiftKey","rect","getBoundingClientRect","__privateSet","x","clientX","left","y","clientY","top","onMouseMove","ev","style","position","margin","onMouseUp","document","removeEventListener","addEventListener","_onTouchStart","touch","changedTouches","pageX","pageY","onTouchMove","t","onTouchEnd","connectedCallback","v","innerHTML","titleText","getAttribute","trace","log","call","returnValue","classList","add","setTimeout","dispatchEvent","CustomEvent","detail","WeakMap","BasePopup","attachShadow","mode","open","PopupClass","message","title","options","renderFn","tagName","toLowerCase","config","class","animation","_c","_a","window","nine","_b","ux","replace","el","createElement","body","appendChild","dialogComp","shadowRoot","setAttribute","Promise","resolve","setupEvents","customElements","get","define","_nineConfirmPopup","render","m","o","msg","conf","nineConfirmPopup","_nineAlertPopup","nineAlertPopup","_ninePromptPopup","textarea","value","requestAnimationFrame","focus","ninePromptPopup","NineUtil","_NineUtil_instances","alert","__privateMethod","prepare_fn","confirm","prompt","WeakSet","type","defaultClass","isExecuted","popup","runner","rgb","classic","shake","run","zoom","then","reject","listeners","Set","_initialConfig","nativeOverride","theme","board","readOnly","cssPath","debug","__NINE_GLOBAL_CONFIG__","_config","subscribeConfig","fn","delete","Proxy","set","prop","setup","Object","entries","key","Array","isArray","Trace$1","name","color","_Trace_instances","_name","_color","_enabled","autoConfig_fn","initBAK","init","console","bind","warn","error","enable","disable","location","hostname","startsWith","Trace","_timer","_queue","_delay","_TaskDebouncer_instances","flush_fn","length","tasks","splice","seen","task","identifier","func","JSON","stringify","args","has","traceOrigin","Loading","show","overlay","getElementById","id","cssText","head","display","hide","_Fetch","_request","__API_BASE_URL__","method","url","data","showLoading","finalUrl","BASE_URL","headers","FormData","targetUrl","URLSearchParams","fetch","async","res","ok","text","Error","status","json","catch","err","finally","rows","fileKey","filePartName","jsonPartName","chunkSize","totalCount","lastResponse","i","formData","chunk","slice","rowDataList","row","fileObj","_fileObj","rest","push","File","append","jsonBlob","Blob","post","success","Fetch","api","UxSplitter","_mode","_detectMode","prev","previousElementSibling","next","nextElementSibling","contains","prevRect","nextRect","Math","abs","_startDrag","preventDefault","stopPropagation","splitterRect","isHorizontal","clickOffset","dragBar","className","assign","zIndex","background","opacity","pointerEvents","root","getRootNode","composed","parent","ShadowRoot","host","parentElement","dragBarOffsetParentRect","offsetParent","initialSplitterPosInParent","width","height","mixBlendMode","minLimit","maxLimit","right","bottom","onMove","moveEvent","clientPos","currentPosInParent","clampedPos","max","min","onUp","allChildren","from","children","allPanels","filter","getComputedStyle","gapValue","getPropertyValue","gapSize","parseFloat","totalGapSize","dragOffset","prevSize","nextSize","newPrevSize","newNextSize","initialSizes","map","panel","totalSplitterSize","reduce","sum","child","totalFlexSpace","flexSum","index","newSize","newFlexBasis","flex","contents","trim","gripTmpl","htmlTmpl","content","cloneNode","_prepareLayout","parentRect","totalContentSize","totalParentSize","size","flexGrow","utilInstance","safe","promise","delay","exec","clearTimeout","execWithKey"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nine-lab/nine-util",
3
- "version": "0.9.125",
3
+ "version": "0.9.127",
4
4
  "description": "Custom Element based Util Component for Real-time Collaboration",
5
5
  "type": "module",
6
6
  "main": "./dist/nine-util.umd.cjs",