pubuilder 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,879 @@
1
+ "use client";
2
+ import { jsxs as b, jsx as l, Fragment as F } from "react/jsx-runtime";
3
+ import { memo as W, useRef as L, useState as C, useEffect as k, useMemo as G, useLayoutEffect as U } from "react";
4
+ import { createPortal as X } from "react-dom";
5
+ import { create as q } from "zustand";
6
+ import { Handle as T, Position as N, ReactFlow as Z } from "@xyflow/react";
7
+ function Se(e) {
8
+ return e;
9
+ }
10
+ const K = { width: 1440, height: 900 };
11
+ function A(e, r, o) {
12
+ o != null && e.append(r, String(o));
13
+ }
14
+ function Q(e, r) {
15
+ const o = e.indexOf("#"), t = o >= 0 ? e.slice(o) : "", a = o >= 0 ? e.slice(0, o) : e, c = a.indexOf("?"), s = c >= 0 ? a.slice(0, c) : a, n = new URLSearchParams(c >= 0 ? a.slice(c + 1) : "");
16
+ for (const [d, u] of Object.entries(r.query))
17
+ if (n.delete(d), Array.isArray(u))
18
+ for (const m of u) A(n, d, m);
19
+ else
20
+ A(n, d, u);
21
+ const i = n.toString();
22
+ return `${s}${i ? `?${i}` : ""}${t}`;
23
+ }
24
+ function J(e) {
25
+ const r = [], o = /* @__PURE__ */ new Set(), t = (a, c, s) => {
26
+ for (const n of a) {
27
+ if (!n.path) throw new Error("[pubuilder] page.path는 필수입니다");
28
+ if (!n.title) throw new Error(`[pubuilder] "${n.path}"의 title이 없습니다`);
29
+ if (o.has(n.path)) throw new Error(`[pubuilder] 중복 path: ${n.path}`);
30
+ if (o.add(n.path), r.push({
31
+ id: n.path,
32
+ path: n.path,
33
+ title: n.title,
34
+ external: n.external ?? /^https?:\/\//.test(n.path),
35
+ parentId: c,
36
+ depth: s
37
+ }), n.variants?.length) {
38
+ if (n.external ?? /^https?:\/\//.test(n.path))
39
+ throw new Error(`[pubuilder] 외부 페이지에는 variants를 사용할 수 없습니다: ${n.path}`);
40
+ for (const i of n.variants) {
41
+ if (!i.title) throw new Error(`[pubuilder] "${n.path}" variant의 title이 없습니다`);
42
+ const d = Q(n.path, i);
43
+ if (o.has(d)) throw new Error(`[pubuilder] 중복 path: ${d}`);
44
+ o.add(d), r.push({
45
+ id: d,
46
+ path: d,
47
+ title: i.title,
48
+ external: !1,
49
+ parentId: n.path,
50
+ depth: s + 1
51
+ });
52
+ }
53
+ }
54
+ n.children?.length && t(n.children, n.path, s + 1);
55
+ }
56
+ };
57
+ if (t(e.pages, null, 0), r.length === 0) throw new Error("[pubuilder] pages가 비어 있습니다");
58
+ return { nodes: r, viewport: e.viewport ?? K };
59
+ }
60
+ function ee() {
61
+ return typeof process < "u" && process.env.NODE_ENV === "production";
62
+ }
63
+ const x = q((e) => ({
64
+ isMapOpen: !1,
65
+ viewerPath: null,
66
+ granularity: "section",
67
+ inspectEnabled: !0,
68
+ selection: null,
69
+ openMap: () => e({ isMapOpen: !0 }),
70
+ closeMap: () => e({ isMapOpen: !1, viewerPath: null, selection: null }),
71
+ openViewer: (r) => e({ viewerPath: r, selection: null }),
72
+ closeViewer: () => e({ viewerPath: null, selection: null }),
73
+ setGranularity: (r) => e({ granularity: r }),
74
+ setInspectEnabled: (r) => e({ inspectEnabled: r }),
75
+ setSelection: (r) => e({ selection: r })
76
+ })), oe = ".react-flow{direction:ltr;--xy-edge-stroke-default: #b1b1b7;--xy-edge-stroke-width-default: 1;--xy-edge-stroke-selected-default: #555;--xy-connectionline-stroke-default: #b1b1b7;--xy-connectionline-stroke-width-default: 1;--xy-attribution-background-color-default: rgba(255, 255, 255, .5);--xy-minimap-background-color-default: #fff;--xy-minimap-mask-background-color-default: rgba(240, 240, 240, .6);--xy-minimap-mask-stroke-color-default: transparent;--xy-minimap-mask-stroke-width-default: 1;--xy-minimap-node-background-color-default: #e2e2e2;--xy-minimap-node-stroke-color-default: transparent;--xy-minimap-node-stroke-width-default: 2;--xy-background-color-default: transparent;--xy-background-pattern-dots-color-default: #91919a;--xy-background-pattern-lines-color-default: #eee;--xy-background-pattern-cross-color-default: #e2e2e2;background-color:var(--xy-background-color, var(--xy-background-color-default));--xy-node-color-default: inherit;--xy-node-border-default: 1px solid #1a192b;--xy-node-background-color-default: #fff;--xy-node-group-background-color-default: rgba(240, 240, 240, .25);--xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(0, 0, 0, .08);--xy-node-boxshadow-selected-default: 0 0 0 .5px #1a192b;--xy-node-border-radius-default: 3px;--xy-handle-background-color-default: #1a192b;--xy-handle-border-color-default: #fff;--xy-selection-background-color-default: rgba(0, 89, 220, .08);--xy-selection-border-default: 1px dotted rgba(0, 89, 220, .8);--xy-controls-button-background-color-default: #fefefe;--xy-controls-button-background-color-hover-default: #f4f4f4;--xy-controls-button-color-default: inherit;--xy-controls-button-color-hover-default: inherit;--xy-controls-button-border-color-default: #eee;--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, .08);--xy-edge-label-background-color-default: #ffffff;--xy-edge-label-color-default: inherit;--xy-resize-background-color-default: #3367d9}.react-flow.dark{--xy-edge-stroke-default: #3e3e3e;--xy-edge-stroke-width-default: 1;--xy-edge-stroke-selected-default: #727272;--xy-connectionline-stroke-default: #b1b1b7;--xy-connectionline-stroke-width-default: 1;--xy-attribution-background-color-default: rgba(150, 150, 150, .25);--xy-minimap-background-color-default: #141414;--xy-minimap-mask-background-color-default: rgba(60, 60, 60, .6);--xy-minimap-mask-stroke-color-default: transparent;--xy-minimap-mask-stroke-width-default: 1;--xy-minimap-node-background-color-default: #2b2b2b;--xy-minimap-node-stroke-color-default: transparent;--xy-minimap-node-stroke-width-default: 2;--xy-background-color-default: #141414;--xy-background-pattern-dots-color-default: #555;--xy-background-pattern-lines-color-default: #333;--xy-background-pattern-cross-color-default: #333;--xy-node-color-default: #f8f8f8;--xy-node-border-default: 1px solid #3c3c3c;--xy-node-background-color-default: #1e1e1e;--xy-node-group-background-color-default: rgba(240, 240, 240, .25);--xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(255, 255, 255, .08);--xy-node-boxshadow-selected-default: 0 0 0 .5px #999;--xy-handle-background-color-default: #bebebe;--xy-handle-border-color-default: #1e1e1e;--xy-selection-background-color-default: rgba(200, 200, 220, .08);--xy-selection-border-default: 1px dotted rgba(200, 200, 220, .8);--xy-controls-button-background-color-default: #2b2b2b;--xy-controls-button-background-color-hover-default: #3e3e3e;--xy-controls-button-color-default: #f8f8f8;--xy-controls-button-color-hover-default: #fff;--xy-controls-button-border-color-default: #5b5b5b;--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, .08);--xy-edge-label-background-color-default: #141414;--xy-edge-label-color-default: #f8f8f8}.react-flow__background{background-color:var(--xy-background-color-props, var(--xy-background-color, var(--xy-background-color-default)));pointer-events:none;z-index:-1}.react-flow__container{position:absolute;width:100%;height:100%;top:0;left:0}.react-flow__pane{z-index:1;touch-action:none}.react-flow__pane.draggable{cursor:grab}.react-flow__pane.dragging{cursor:grabbing}.react-flow__pane.selection{cursor:pointer}.react-flow__viewport{transform-origin:0 0;z-index:2;pointer-events:none}.react-flow__renderer{z-index:4}.react-flow__selection{z-index:6}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible{outline:none}.react-flow__edge-path{stroke:var(--xy-edge-stroke, var(--xy-edge-stroke-default));stroke-width:var(--xy-edge-stroke-width, var(--xy-edge-stroke-width-default));fill:none}.react-flow__connection-path{stroke:var(--xy-connectionline-stroke, var(--xy-connectionline-stroke-default));stroke-width:var(--xy-connectionline-stroke-width, var(--xy-connectionline-stroke-width-default));fill:none}.react-flow .react-flow__edges{position:absolute}.react-flow .react-flow__edges svg{overflow:visible;position:absolute;pointer-events:none}.react-flow__edge{pointer-events:visibleStroke}.react-flow__edge.selectable{cursor:pointer}.react-flow__edge.animated path{stroke-dasharray:5;animation:dashdraw .5s linear infinite}.react-flow__edge.animated path.react-flow__edge-interaction{stroke-dasharray:none;animation:none}.react-flow__edge.inactive{pointer-events:none}.react-flow__edge.selected,.react-flow__edge:focus,.react-flow__edge:focus-visible{outline:none}.react-flow__edge.selected .react-flow__edge-path,.react-flow__edge.selectable:focus .react-flow__edge-path,.react-flow__edge.selectable:focus-visible .react-flow__edge-path{stroke:var(--xy-edge-stroke-selected, var(--xy-edge-stroke-selected-default))}.react-flow__edge-textwrapper{pointer-events:all}.react-flow__edge .react-flow__edge-text{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__arrowhead polyline{stroke:var(--xy-edge-stroke, var(--xy-edge-stroke-default))}.react-flow__arrowhead polyline.arrowclosed{fill:var(--xy-edge-stroke, var(--xy-edge-stroke-default))}.react-flow__connection{pointer-events:none}.react-flow__connection .animated{stroke-dasharray:5;animation:dashdraw .5s linear infinite}svg.react-flow__connectionline{z-index:1001;overflow:visible;position:absolute}.react-flow__nodes{pointer-events:none;transform-origin:0 0}.react-flow__node{position:absolute;-webkit-user-select:none;-moz-user-select:none;user-select:none;pointer-events:all;transform-origin:0 0;box-sizing:border-box;cursor:default}.react-flow__node.selectable{cursor:pointer}.react-flow__node.draggable{cursor:grab;pointer-events:all}.react-flow__node.draggable.dragging{cursor:grabbing}.react-flow__nodesselection{z-index:3;transform-origin:left top;pointer-events:none}.react-flow__nodesselection-rect{position:absolute;pointer-events:all;cursor:grab}.react-flow__handle{position:absolute;pointer-events:none;min-width:5px;min-height:5px;width:6px;height:6px;background-color:var(--xy-handle-background-color, var(--xy-handle-background-color-default));border:1px solid var(--xy-handle-border-color, var(--xy-handle-border-color-default));border-radius:100%}.react-flow__handle.connectingfrom{pointer-events:all}.react-flow__handle.connectionindicator{pointer-events:all;cursor:crosshair}.react-flow__handle-bottom{top:auto;left:50%;bottom:0;transform:translate(-50%,50%)}.react-flow__handle-top{top:0;left:50%;transform:translate(-50%,-50%)}.react-flow__handle-left{top:50%;left:0;transform:translate(-50%,-50%)}.react-flow__handle-right{top:50%;right:0;transform:translate(50%,-50%)}.react-flow__edgeupdater{cursor:move;pointer-events:all}.react-flow__pane.selection .react-flow__panel{pointer-events:none}.react-flow__panel{position:absolute;z-index:5;margin:15px}.react-flow__panel.top{top:0}.react-flow__panel.bottom{bottom:0}.react-flow__panel.top.center,.react-flow__panel.bottom.center{left:50%;transform:translate(-15px) translate(-50%)}.react-flow__panel.left{left:0}.react-flow__panel.right{right:0}.react-flow__panel.left.center,.react-flow__panel.right.center{top:50%;transform:translateY(-15px) translateY(-50%)}.react-flow__attribution{font-size:10px;background:var(--xy-attribution-background-color, var(--xy-attribution-background-color-default));padding:2px 3px;margin:0}.react-flow__attribution a{text-decoration:none;color:#999}@keyframes dashdraw{0%{stroke-dashoffset:10}}.react-flow__edgelabel-renderer{position:absolute;width:100%;height:100%;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;left:0;top:0}.react-flow__viewport-portal{position:absolute;width:100%;height:100%;left:0;top:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__minimap{background:var( --xy-minimap-background-color-props, var(--xy-minimap-background-color, var(--xy-minimap-background-color-default)) )}.react-flow__minimap-svg{display:block}.react-flow__minimap-mask{fill:var( --xy-minimap-mask-background-color-props, var(--xy-minimap-mask-background-color, var(--xy-minimap-mask-background-color-default)) );stroke:var( --xy-minimap-mask-stroke-color-props, var(--xy-minimap-mask-stroke-color, var(--xy-minimap-mask-stroke-color-default)) );stroke-width:var( --xy-minimap-mask-stroke-width-props, var(--xy-minimap-mask-stroke-width, var(--xy-minimap-mask-stroke-width-default)) )}.react-flow__minimap-node{fill:var( --xy-minimap-node-background-color-props, var(--xy-minimap-node-background-color, var(--xy-minimap-node-background-color-default)) );stroke:var( --xy-minimap-node-stroke-color-props, var(--xy-minimap-node-stroke-color, var(--xy-minimap-node-stroke-color-default)) );stroke-width:var( --xy-minimap-node-stroke-width-props, var(--xy-minimap-node-stroke-width, var(--xy-minimap-node-stroke-width-default)) )}.react-flow__background-pattern.dots{fill:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-dots-color-default)) )}.react-flow__background-pattern.lines{stroke:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-lines-color-default)) )}.react-flow__background-pattern.cross{stroke:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-cross-color-default)) )}.react-flow__controls{display:flex;flex-direction:column;box-shadow:var(--xy-controls-box-shadow, var(--xy-controls-box-shadow-default))}.react-flow__controls.horizontal{flex-direction:row}.react-flow__controls-button{display:flex;justify-content:center;align-items:center;height:26px;width:26px;padding:4px;border:none;background:var(--xy-controls-button-background-color, var(--xy-controls-button-background-color-default));border-bottom:1px solid var( --xy-controls-button-border-color-props, var(--xy-controls-button-border-color, var(--xy-controls-button-border-color-default)) );color:var( --xy-controls-button-color-props, var(--xy-controls-button-color, var(--xy-controls-button-color-default)) );cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__controls-button svg{width:100%;max-width:12px;max-height:12px;fill:currentColor}.react-flow__edge.updating .react-flow__edge-path{stroke:#777}.react-flow__edge-text{font-size:10px}.react-flow__node.selectable:focus,.react-flow__node.selectable:focus-visible{outline:none}.react-flow__node-input,.react-flow__node-default,.react-flow__node-output,.react-flow__node-group{padding:10px;border-radius:var(--xy-node-border-radius, var(--xy-node-border-radius-default));width:150px;font-size:12px;color:var(--xy-node-color, var(--xy-node-color-default));text-align:center;border:var(--xy-node-border, var(--xy-node-border-default));background-color:var(--xy-node-background-color, var(--xy-node-background-color-default))}.react-flow__node-input.selectable:hover,.react-flow__node-default.selectable:hover,.react-flow__node-output.selectable:hover,.react-flow__node-group.selectable:hover{box-shadow:var(--xy-node-boxshadow-hover, var(--xy-node-boxshadow-hover-default))}.react-flow__node-input.selectable.selected,.react-flow__node-input.selectable:focus,.react-flow__node-input.selectable:focus-visible,.react-flow__node-default.selectable.selected,.react-flow__node-default.selectable:focus,.react-flow__node-default.selectable:focus-visible,.react-flow__node-output.selectable.selected,.react-flow__node-output.selectable:focus,.react-flow__node-output.selectable:focus-visible,.react-flow__node-group.selectable.selected,.react-flow__node-group.selectable:focus,.react-flow__node-group.selectable:focus-visible{box-shadow:var(--xy-node-boxshadow-selected, var(--xy-node-boxshadow-selected-default))}.react-flow__node-group{background-color:var(--xy-node-group-background-color, var(--xy-node-group-background-color-default))}.react-flow__nodesselection-rect,.react-flow__selection{background:var(--xy-selection-background-color, var(--xy-selection-background-color-default));border:var(--xy-selection-border, var(--xy-selection-border-default))}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible,.react-flow__selection:focus,.react-flow__selection:focus-visible{outline:none}.react-flow__controls-button:hover{background:var( --xy-controls-button-background-color-hover-props, var(--xy-controls-button-background-color-hover, var(--xy-controls-button-background-color-hover-default)) );color:var( --xy-controls-button-color-hover-props, var(--xy-controls-button-color-hover, var(--xy-controls-button-color-hover-default)) )}.react-flow__controls-button:disabled{pointer-events:none}.react-flow__controls-button:disabled svg{fill-opacity:.4}.react-flow__controls-button:last-child{border-bottom:none}.react-flow__controls.horizontal .react-flow__controls-button{border-bottom:none;border-right:1px solid var( --xy-controls-button-border-color-props, var(--xy-controls-button-border-color, var(--xy-controls-button-border-color-default)) )}.react-flow__controls.horizontal .react-flow__controls-button:last-child{border-right:none}.react-flow__resize-control{position:absolute}.react-flow__resize-control.left,.react-flow__resize-control.right{cursor:ew-resize}.react-flow__resize-control.top,.react-flow__resize-control.bottom{cursor:ns-resize}.react-flow__resize-control.top.left,.react-flow__resize-control.bottom.right{cursor:nwse-resize}.react-flow__resize-control.bottom.left,.react-flow__resize-control.top.right{cursor:nesw-resize}.react-flow__resize-control.handle{width:5px;height:5px;border:1px solid #fff;border-radius:1px;background-color:var(--xy-resize-background-color, var(--xy-resize-background-color-default));translate:-50% -50%}.react-flow__resize-control.handle.left{left:0;top:50%}.react-flow__resize-control.handle.right{left:100%;top:50%}.react-flow__resize-control.handle.top{left:50%;top:0}.react-flow__resize-control.handle.bottom{left:50%;top:100%}.react-flow__resize-control.handle.top.left,.react-flow__resize-control.handle.bottom.left{left:0}.react-flow__resize-control.handle.top.right,.react-flow__resize-control.handle.bottom.right{left:100%}.react-flow__resize-control.line{border-color:var(--xy-resize-background-color, var(--xy-resize-background-color-default));border-width:0;border-style:solid}.react-flow__resize-control.line.left,.react-flow__resize-control.line.right{width:1px;transform:translate(-50%);top:0;height:100%}.react-flow__resize-control.line.left{left:0;border-left-width:1px}.react-flow__resize-control.line.right{left:100%;border-right-width:1px}.react-flow__resize-control.line.top,.react-flow__resize-control.line.bottom{height:1px;transform:translateY(-50%);left:0;width:100%}.react-flow__resize-control.line.top{top:0;border-top-width:1px}.react-flow__resize-control.line.bottom{border-bottom-width:1px;top:100%}.react-flow__edge-textbg{fill:var(--xy-edge-label-background-color, var(--xy-edge-label-background-color-default))}.react-flow__edge-text{fill:var(--xy-edge-label-color, var(--xy-edge-label-color-default))}", te = "pubuilder-styles", re = "pubuilder-xyflow-styles", ne = (
77
+ /* css */
78
+ `
79
+ .pbu-fab {
80
+ position: fixed;
81
+ right: 16px;
82
+ bottom: 16px;
83
+ z-index: 2147483000;
84
+ width: 40px;
85
+ height: 40px;
86
+ border-radius: 2px;
87
+ border: 1px solid #3c3c3c;
88
+ cursor: pointer;
89
+ background: #252526;
90
+ color: #cccccc;
91
+ display: flex;
92
+ align-items: center;
93
+ justify-content: center;
94
+ }
95
+ .pbu-fab:hover { background: #2d2d2d; color: #ffffff; }
96
+
97
+ .pbu-overlay,
98
+ .pbu-viewer {
99
+ position: fixed;
100
+ inset: 0;
101
+ display: flex;
102
+ flex-direction: column;
103
+ font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
104
+ font-size: 12px;
105
+ color: #cccccc;
106
+ }
107
+ .pbu-overlay { z-index: 2147483100; background: #1e1e1e; }
108
+ .pbu-viewer { z-index: 2147483200; background: #1e1e1e; }
109
+
110
+ .pbu-bar {
111
+ display: flex;
112
+ align-items: center;
113
+ gap: 10px;
114
+ height: 38px;
115
+ padding: 0 12px;
116
+ background: #252526;
117
+ border-bottom: 1px solid #3c3c3c;
118
+ flex-shrink: 0;
119
+ }
120
+ .pbu-logo {
121
+ font-weight: 600;
122
+ font-size: 11px;
123
+ letter-spacing: 0.08em;
124
+ text-transform: uppercase;
125
+ color: #cccccc;
126
+ }
127
+ .pbu-hint { font-size: 11px; color: #8c8c8c; }
128
+ .pbu-spacer { flex: 1; }
129
+
130
+ .pbu-btn {
131
+ border: 1px solid #3c3c3c;
132
+ background: #2d2d2d;
133
+ color: #cccccc;
134
+ font-size: 11px;
135
+ padding: 4px 10px;
136
+ border-radius: 2px;
137
+ cursor: pointer;
138
+ }
139
+ .pbu-btn:hover { background: #37373d; }
140
+ .pbu-btn:disabled { opacity: 0.4; cursor: not-allowed; }
141
+ .pbu-btn-primary { background: #0e639c; border-color: #0e639c; color: #fff; }
142
+ .pbu-btn-primary:hover:not(:disabled) { background: #1177bb; }
143
+
144
+ .pbu-icon-btn {
145
+ border: none;
146
+ background: transparent;
147
+ color: #8c8c8c;
148
+ font-size: 14px;
149
+ cursor: pointer;
150
+ padding: 4px 8px;
151
+ border-radius: 2px;
152
+ }
153
+ .pbu-icon-btn:hover { background: #2d2d2d; color: #ffffff; }
154
+
155
+ .pbu-seg {
156
+ display: flex;
157
+ border: 1px solid #3c3c3c;
158
+ border-radius: 2px;
159
+ overflow: hidden;
160
+ }
161
+ .pbu-seg button {
162
+ border: none;
163
+ background: #2d2d2d;
164
+ color: #8c8c8c;
165
+ font-size: 11px;
166
+ padding: 4px 12px;
167
+ cursor: pointer;
168
+ }
169
+ .pbu-seg button + button { border-left: 1px solid #3c3c3c; }
170
+ .pbu-seg button.pbu-on { background: #0e639c; color: #fff; }
171
+
172
+ .pbu-toggle {
173
+ display: flex;
174
+ align-items: center;
175
+ gap: 5px;
176
+ font-size: 11px;
177
+ color: #8c8c8c;
178
+ cursor: pointer;
179
+ user-select: none;
180
+ }
181
+
182
+ .pbu-canvas { flex: 1; min-height: 0; }
183
+ .pbu-canvas .react-flow { background: #1e1e1e; }
184
+ /* draggable/selectable 꺼도 노드 클릭은 받아야 함 (RF는 비인터랙티브 노드에 pointer-events:none을 줌) */
185
+ .pbu-canvas .react-flow__node { pointer-events: all !important; cursor: pointer; }
186
+ .pbu-canvas .react-flow__edge-path { stroke: #555555; stroke-width: 1; }
187
+ .pbu-canvas .react-flow__controls button {
188
+ background: #252526;
189
+ border-bottom: 1px solid #3c3c3c;
190
+ border-radius: 0;
191
+ color: #cccccc;
192
+ fill: #cccccc;
193
+ }
194
+ .pbu-canvas .react-flow__controls button:hover { background: #2d2d2d; }
195
+
196
+ .pbu-node {
197
+ background: #252526;
198
+ border: 1px solid #3c3c3c;
199
+ border-radius: 0;
200
+ overflow: hidden;
201
+ cursor: pointer;
202
+ }
203
+ .pbu-node:hover { border-color: #0e639c; }
204
+ .pbu-node-header {
205
+ display: flex;
206
+ align-items: center;
207
+ justify-content: space-between;
208
+ gap: 8px;
209
+ height: 28px;
210
+ padding: 0 8px;
211
+ background: #2d2d2d;
212
+ border-bottom: 1px solid #3c3c3c;
213
+ }
214
+ .pbu-node-title {
215
+ font-size: 11px;
216
+ font-weight: 600;
217
+ color: #cccccc;
218
+ white-space: nowrap;
219
+ overflow: hidden;
220
+ text-overflow: ellipsis;
221
+ }
222
+ .pbu-node-path {
223
+ font-size: 10px;
224
+ color: #8c8c8c;
225
+ font-family: ui-monospace, Menlo, monospace;
226
+ white-space: nowrap;
227
+ flex-shrink: 0;
228
+ }
229
+ .pbu-node-body { position: relative; background: #fff; overflow: hidden; }
230
+ .pbu-node-iframe {
231
+ border: 0;
232
+ transform-origin: 0 0;
233
+ pointer-events: none;
234
+ display: block;
235
+ }
236
+ .pbu-node-shield { position: absolute; inset: 0; }
237
+ .pbu-node-placeholder {
238
+ position: absolute;
239
+ inset: 0;
240
+ display: flex;
241
+ align-items: center;
242
+ justify-content: center;
243
+ font-size: 11px;
244
+ color: #8c8c8c;
245
+ background: #1e1e1e;
246
+ }
247
+ .pbu-handle { opacity: 0; pointer-events: none; }
248
+
249
+ .pbu-viewer-title { font-size: 12px; font-weight: 600; }
250
+ .pbu-viewer-title code {
251
+ margin-left: 8px;
252
+ font-size: 11px;
253
+ font-weight: 400;
254
+ color: #8c8c8c;
255
+ font-family: ui-monospace, Menlo, monospace;
256
+ }
257
+ .pbu-viewer-body { flex: 1; min-height: 0; display: flex; }
258
+ .pbu-viewer-frame-wrap { flex: 1; min-width: 0; background: #fff; }
259
+ .pbu-viewer-iframe { width: 100%; height: 100%; border: 0; display: block; }
260
+
261
+ .pbu-panel {
262
+ width: 300px;
263
+ flex-shrink: 0;
264
+ background: #252526;
265
+ border-left: 1px solid #3c3c3c;
266
+ padding: 12px;
267
+ overflow-y: auto;
268
+ display: flex;
269
+ flex-direction: column;
270
+ gap: 12px;
271
+ }
272
+ .pbu-panel-title {
273
+ font-size: 11px;
274
+ font-weight: 600;
275
+ letter-spacing: 0.08em;
276
+ text-transform: uppercase;
277
+ color: #cccccc;
278
+ padding-bottom: 8px;
279
+ border-bottom: 1px solid #3c3c3c;
280
+ }
281
+ .pbu-panel-empty { font-size: 11px; color: #8c8c8c; line-height: 1.7; }
282
+ .pbu-field { display: flex; flex-direction: column; gap: 4px; }
283
+ .pbu-field > label {
284
+ font-size: 10px;
285
+ font-weight: 600;
286
+ text-transform: uppercase;
287
+ letter-spacing: 0.06em;
288
+ color: #8c8c8c;
289
+ }
290
+ .pbu-field code {
291
+ font-size: 11px;
292
+ color: #cccccc;
293
+ font-family: ui-monospace, Menlo, monospace;
294
+ word-break: break-all;
295
+ }
296
+ .pbu-field span { font-size: 12px; color: #cccccc; }
297
+ .pbu-selector {
298
+ background: #1e1e1e;
299
+ border: 1px solid #3c3c3c;
300
+ border-radius: 2px;
301
+ padding: 6px 8px;
302
+ display: block;
303
+ }
304
+ .pbu-chip {
305
+ display: inline-block;
306
+ background: #37373d;
307
+ color: #cccccc;
308
+ font-size: 11px;
309
+ font-weight: 600;
310
+ font-family: ui-monospace, Menlo, monospace;
311
+ padding: 1px 6px;
312
+ border-radius: 2px;
313
+ margin-right: 6px;
314
+ }
315
+ .pbu-phase3 {
316
+ margin-top: 4px;
317
+ padding: 10px;
318
+ border: 1px dashed #3c3c3c;
319
+ border-radius: 2px;
320
+ display: flex;
321
+ flex-direction: column;
322
+ gap: 8px;
323
+ }
324
+ .pbu-phase3 > label { font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em; color: #8c8c8c; }
325
+ .pbu-phase3 input {
326
+ background: #1e1e1e;
327
+ border: 1px solid #3c3c3c;
328
+ border-radius: 2px;
329
+ color: #8c8c8c;
330
+ font-size: 11px;
331
+ padding: 5px 8px;
332
+ }
333
+ .pbu-badge {
334
+ background: #37373d;
335
+ color: #d7ba7d;
336
+ font-size: 9px;
337
+ font-weight: 700;
338
+ padding: 1px 5px;
339
+ border-radius: 2px;
340
+ margin-left: 4px;
341
+ }
342
+ `
343
+ );
344
+ function j(e, r) {
345
+ if (document.getElementById(e)) return;
346
+ const o = document.createElement("style");
347
+ o.id = e, o.textContent = r, document.head.appendChild(o);
348
+ }
349
+ function ae() {
350
+ typeof document > "u" || (j(re, oe), j(te, ne));
351
+ }
352
+ function le(e, r, o, t = 140, a = 48) {
353
+ const c = /* @__PURE__ */ new Map();
354
+ for (const d of e) {
355
+ const u = c.get(d.parentId) ?? [];
356
+ u.push(d), c.set(d.parentId, u);
357
+ }
358
+ const s = /* @__PURE__ */ new Map();
359
+ let n = 0;
360
+ const i = (d) => {
361
+ const u = c.get(d.id) ?? [], m = d.depth * (r + t);
362
+ let w;
363
+ if (u.length === 0)
364
+ w = n, n += o + a;
365
+ else {
366
+ const p = u.map(i);
367
+ w = (Math.min(...p) + Math.max(...p)) / 2;
368
+ }
369
+ return s.set(d.id, { x: m, y: w }), w;
370
+ };
371
+ for (const d of c.get(null) ?? []) i(d);
372
+ return e.map((d) => ({ ...d, ...s.get(d.id) }));
373
+ }
374
+ const ce = W(function(r) {
375
+ const { page: o, viewport: t, thumbWidth: a, bodyHeight: c } = r.data, s = x((w) => w.openViewer), n = L(null), [i, d] = C(!1);
376
+ k(() => {
377
+ const w = n.current;
378
+ if (!w || o.external) return;
379
+ const p = new IntersectionObserver(([v]) => {
380
+ v.isIntersecting && (d(!0), p.disconnect());
381
+ });
382
+ return p.observe(w), () => p.disconnect();
383
+ }, [o.external]);
384
+ const u = a / t.width;
385
+ return /* @__PURE__ */ b("div", { ref: n, className: "pbu-node", style: { width: a }, onClick: () => {
386
+ o.external ? window.open(o.path, "_blank", "noopener") : s(o.path);
387
+ }, children: [
388
+ /* @__PURE__ */ l(T, { type: "target", position: N.Left, className: "pbu-handle", isConnectable: !1 }),
389
+ /* @__PURE__ */ b("div", { className: "pbu-node-header", children: [
390
+ /* @__PURE__ */ l("span", { className: "pbu-node-title", children: o.title }),
391
+ /* @__PURE__ */ l("span", { className: "pbu-node-path", children: o.external ? "외부 ↗" : o.path })
392
+ ] }),
393
+ /* @__PURE__ */ b("div", { className: "pbu-node-body", style: { height: c }, children: [
394
+ o.external ? /* @__PURE__ */ l("div", { className: "pbu-node-placeholder", children: "↗ 외부 링크" }) : i ? /* @__PURE__ */ l(
395
+ "iframe",
396
+ {
397
+ className: "pbu-node-iframe",
398
+ src: o.path,
399
+ title: `${o.title} 미리보기`,
400
+ loading: "lazy",
401
+ tabIndex: -1,
402
+ style: {
403
+ width: t.width,
404
+ height: t.height,
405
+ transform: `scale(${u})`
406
+ }
407
+ }
408
+ ) : /* @__PURE__ */ l("div", { className: "pbu-node-placeholder", children: "…" }),
409
+ /* @__PURE__ */ l("div", { className: "pbu-node-shield" })
410
+ ] }),
411
+ /* @__PURE__ */ l(T, { type: "source", position: N.Right, className: "pbu-handle", isConnectable: !1 })
412
+ ] });
413
+ }), ie = { page: ce }, S = 260, se = 30;
414
+ function de({ ia: e }) {
415
+ const r = x((a) => a.closeMap), { nodes: o, edges: t } = G(() => {
416
+ const a = S / e.viewport.width, c = Math.round(e.viewport.height * a), s = c + se, n = le(e.nodes, S, s), i = n.map((u) => ({
417
+ id: u.id,
418
+ type: "page",
419
+ position: { x: u.x, y: u.y },
420
+ data: {
421
+ page: u,
422
+ viewport: e.viewport,
423
+ thumbWidth: S,
424
+ bodyHeight: c
425
+ },
426
+ sourcePosition: N.Right,
427
+ targetPosition: N.Left
428
+ })), d = n.filter((u) => u.parentId).map((u) => ({
429
+ id: `${u.parentId}->${u.id}`,
430
+ source: u.parentId,
431
+ target: u.id,
432
+ type: "smoothstep"
433
+ }));
434
+ return { nodes: i, edges: d };
435
+ }, [e]);
436
+ return k(() => {
437
+ const a = (c) => {
438
+ c.key === "Escape" && (x.getState().viewerPath || r());
439
+ };
440
+ return window.addEventListener("keydown", a), () => window.removeEventListener("keydown", a);
441
+ }, [r]), /* @__PURE__ */ b("div", { className: "pbu-overlay", children: [
442
+ /* @__PURE__ */ b("div", { className: "pbu-bar", children: [
443
+ /* @__PURE__ */ l("span", { className: "pbu-logo", children: "pubuilder" }),
444
+ /* @__PURE__ */ l("span", { className: "pbu-hint", children: "노드 클릭 → 페이지 확대 · 스크롤 줌 · 드래그 팬 · Esc 닫기" }),
445
+ /* @__PURE__ */ l("span", { className: "pbu-spacer" }),
446
+ /* @__PURE__ */ l("button", { type: "button", className: "pbu-icon-btn", onClick: r, "aria-label": "닫기", children: "✕" })
447
+ ] }),
448
+ /* @__PURE__ */ l("div", { className: "pbu-canvas", children: /* @__PURE__ */ l(
449
+ Z,
450
+ {
451
+ nodes: o,
452
+ edges: t,
453
+ nodeTypes: ie,
454
+ fitView: !0,
455
+ fitViewOptions: { padding: 0.15, maxZoom: 1 },
456
+ minZoom: 0.05,
457
+ maxZoom: 2,
458
+ nodesDraggable: !1,
459
+ nodesConnectable: !1,
460
+ elementsSelectable: !1
461
+ }
462
+ ) })
463
+ ] });
464
+ }
465
+ function ue() {
466
+ const e = x((t) => t.isMapOpen), r = x((t) => t.openMap), o = x((t) => t.closeMap);
467
+ return /* @__PURE__ */ l(
468
+ "button",
469
+ {
470
+ type: "button",
471
+ className: "pbu-fab",
472
+ title: "Page Map (pubuilder)",
473
+ "aria-label": "페이지 맵 열기",
474
+ onClick: () => e ? o() : r(),
475
+ children: /* @__PURE__ */ b("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
476
+ /* @__PURE__ */ l("polygon", { points: "3 6 9 3 15 6 21 3 21 18 15 21 9 18 3 21" }),
477
+ /* @__PURE__ */ l("line", { x1: "9", y1: "3", x2: "9", y2: "18" }),
478
+ /* @__PURE__ */ l("line", { x1: "15", y1: "6", x2: "15", y2: "21" })
479
+ ] })
480
+ }
481
+ );
482
+ }
483
+ const pe = /* @__PURE__ */ new Set([
484
+ "section",
485
+ "header",
486
+ "footer",
487
+ "nav",
488
+ "main",
489
+ "article",
490
+ "aside",
491
+ "form"
492
+ ]), fe = /* @__PURE__ */ new Set([
493
+ "a",
494
+ "button",
495
+ "input",
496
+ "select",
497
+ "textarea",
498
+ "img",
499
+ "video",
500
+ "table",
501
+ "ul",
502
+ "ol",
503
+ "li",
504
+ "figure",
505
+ "h1",
506
+ "h2",
507
+ "h3",
508
+ "h4",
509
+ "p",
510
+ "label"
511
+ ]);
512
+ function Y(e, r) {
513
+ const o = [];
514
+ let t = e;
515
+ for (; t && t !== r.body && t !== r.documentElement; )
516
+ o.push(t), t = t.parentElement;
517
+ return o;
518
+ }
519
+ function be(e, r) {
520
+ const o = Y(e, r);
521
+ if (o.length === 0) return null;
522
+ const t = o.find((s) => {
523
+ const n = s.tagName.toLowerCase();
524
+ return pe.has(n) && n !== "main";
525
+ });
526
+ if (t) return t;
527
+ const a = o.find((s) => s.tagName.toLowerCase() === "main");
528
+ if (a) return a;
529
+ const c = r.body.scrollHeight || 1;
530
+ for (let s = o.length - 1; s >= 0; s--) {
531
+ const n = o[s].getBoundingClientRect();
532
+ if (n.height > 0 && n.height < c * 0.8) return o[s];
533
+ }
534
+ return o[o.length - 1];
535
+ }
536
+ function he(e, r) {
537
+ const o = Y(e, r);
538
+ for (const t of o) {
539
+ if (fe.has(t.tagName.toLowerCase())) return t;
540
+ const a = t.getBoundingClientRect(), c = t.children.length > 0 || (t.textContent ?? "").trim().length > 0;
541
+ if (a.width >= 40 && a.height >= 24 && c) return t;
542
+ }
543
+ return o[0] ?? null;
544
+ }
545
+ function ge(e, r, o) {
546
+ return o === "all" ? r.body : o === "section" ? be(e, r) : he(e, r);
547
+ }
548
+ function xe(e) {
549
+ const o = e.querySelector("h1, h2, h3, h4, h5, h6")?.textContent?.trim();
550
+ if (o) return E(o);
551
+ const t = e.getAttribute("aria-label");
552
+ if (t) return E(t);
553
+ const a = e.getAttribute("alt");
554
+ if (a) return E(a);
555
+ const c = (e.textContent ?? "").trim().replace(/\s+/g, " ");
556
+ return c ? E(c) : `<${e.tagName.toLowerCase()}>`;
557
+ }
558
+ function E(e, r = 30) {
559
+ return e.length > r ? `${e.slice(0, r)}…` : e;
560
+ }
561
+ function we(e, r) {
562
+ if (e.id) return `#${CSS.escape(e.id)}`;
563
+ const o = [];
564
+ let t = e;
565
+ for (; t && t !== r.body && o.length < 8; ) {
566
+ if (t.id)
567
+ return o.unshift(`#${CSS.escape(t.id)}`), o.join(" > ");
568
+ const a = t.tagName.toLowerCase(), c = t.parentElement;
569
+ let s = a;
570
+ if (c) {
571
+ const n = Array.from(c.children).filter(
572
+ (i) => i.tagName === t.tagName
573
+ );
574
+ n.length > 1 && (s += `:nth-of-type(${n.indexOf(t) + 1})`);
575
+ }
576
+ o.unshift(s), t = c;
577
+ }
578
+ return o.join(" > ");
579
+ }
580
+ function H(e, r, o) {
581
+ const t = e.createElement("div");
582
+ t.setAttribute("data-pubuilder", "highlight"), Object.assign(t.style, {
583
+ position: "fixed",
584
+ top: "0",
585
+ left: "0",
586
+ display: "none",
587
+ border: `1px solid ${r}`,
588
+ background: o,
589
+ borderRadius: "0",
590
+ pointerEvents: "none",
591
+ zIndex: "2147483647",
592
+ boxSizing: "border-box"
593
+ });
594
+ const a = e.createElement("div");
595
+ return Object.assign(a.style, {
596
+ position: "absolute",
597
+ left: "-1px",
598
+ top: "-22px",
599
+ padding: "2px 7px",
600
+ background: r,
601
+ color: "#fff",
602
+ font: "600 10px/16px system-ui, sans-serif",
603
+ borderRadius: "0",
604
+ whiteSpace: "nowrap",
605
+ pointerEvents: "none"
606
+ }), t.appendChild(a), { root: t, label: a };
607
+ }
608
+ function V(e, r, o, t) {
609
+ const a = r.getBoundingClientRect(), c = t ?? -1 / 0, s = Math.max(a.top, c), n = a.bottom - s;
610
+ if (n <= 2) {
611
+ M(e);
612
+ return;
613
+ }
614
+ e.root.style.display = "block", e.root.style.transform = `translate(${a.x}px, ${s}px)`, e.root.style.width = `${a.width}px`, e.root.style.height = `${n}px`, e.label.textContent = o, e.label.style.top = s < 30 || s - 24 < c ? "2px" : "-24px";
615
+ }
616
+ function M(e) {
617
+ e.root.style.display = "none";
618
+ }
619
+ function D(e) {
620
+ const r = e.getBoundingClientRect();
621
+ return `${e.tagName.toLowerCase()} · ${Math.round(r.width)}×${Math.round(r.height)}`;
622
+ }
623
+ function me(e, r) {
624
+ let o = null;
625
+ try {
626
+ o = e.contentDocument;
627
+ } catch {
628
+ return null;
629
+ }
630
+ const t = e.contentWindow;
631
+ if (!o || !o.body || !t) return null;
632
+ const a = o;
633
+ let c = r.granularity, s = r.enabled, n = null, i = null;
634
+ const d = H(a, "rgba(14,99,156,0.95)", "rgba(14,99,156,0.10)"), u = H(a, "rgba(35,134,54,0.95)", "rgba(35,134,54,0.07)");
635
+ a.body.appendChild(d.root), a.body.appendChild(u.root);
636
+ let m = [], w = 0;
637
+ const p = () => {
638
+ m = [];
639
+ for (const f of Array.from(a.body.querySelectorAll("*"))) {
640
+ if (f === d.root || f === u.root || d.root.contains(f) || u.root.contains(f)) continue;
641
+ const g = t.getComputedStyle(f).position;
642
+ if (g !== "fixed" && g !== "sticky") continue;
643
+ const h = f.getBoundingClientRect();
644
+ h.width === 0 || h.height === 0 || h.top <= 1 && h.height < t.innerHeight * 0.5 && m.push({ el: f, rect: h });
645
+ }
646
+ }, v = () => {
647
+ const f = Date.now();
648
+ f - w < 500 || (w = f, p());
649
+ }, z = (f) => {
650
+ const g = f.getBoundingClientRect();
651
+ let h = null;
652
+ for (const y of m)
653
+ y.el === f || y.el.contains(f) || f.contains(y.el) || !(g.left < y.rect.right && g.right > y.rect.left) || (h === null || y.rect.bottom > h) && (h = y.rect.bottom);
654
+ return h;
655
+ }, _ = () => {
656
+ n && s && n.isConnected ? V(d, n, D(n), z(n)) : M(d), i && i.isConnected ? V(u, i, `선택됨 · ${D(i)}`, z(i)) : M(u);
657
+ }, P = (f) => {
658
+ if (c === "all") return a.body;
659
+ if (i && i.isConnected && i.contains(f)) {
660
+ if (i === f) return i;
661
+ let g = f;
662
+ for (; g.parentElement && g.parentElement !== i; )
663
+ g = g.parentElement;
664
+ return g;
665
+ }
666
+ return ge(f, a, c);
667
+ }, I = (f) => {
668
+ if (!s) return;
669
+ v();
670
+ const g = f.target;
671
+ if (!g || !a.body.contains(g)) return;
672
+ const h = P(g);
673
+ h !== n && (n = h, _());
674
+ }, $ = (f) => {
675
+ if (!s) return;
676
+ f.preventDefault(), f.stopPropagation(), p(), w = Date.now();
677
+ const g = f.target;
678
+ if (!g) return;
679
+ const h = P(g);
680
+ if (!h) return;
681
+ i = h, _();
682
+ const y = h.getBoundingClientRect();
683
+ r.onSelect({
684
+ pagePath: r.pagePath,
685
+ selector: we(h, a),
686
+ tag: h.tagName.toLowerCase(),
687
+ label: xe(h),
688
+ rect: {
689
+ x: y.x + t.scrollX,
690
+ y: y.y + t.scrollY,
691
+ width: y.width,
692
+ height: y.height
693
+ },
694
+ granularity: c
695
+ });
696
+ }, B = () => {
697
+ n = null, _();
698
+ }, O = () => _(), R = () => {
699
+ p(), _();
700
+ };
701
+ return p(), a.addEventListener("mousemove", I, !0), a.addEventListener("click", $, !0), a.documentElement.addEventListener("mouseleave", B), t.addEventListener("scroll", O, !0), t.addEventListener("resize", R), {
702
+ destroy() {
703
+ try {
704
+ a.removeEventListener("mousemove", I, !0), a.removeEventListener("click", $, !0), a.documentElement.removeEventListener("mouseleave", B), t.removeEventListener("scroll", O, !0), t.removeEventListener("resize", R), d.root.remove(), u.root.remove();
705
+ } catch {
706
+ }
707
+ },
708
+ setGranularity(f) {
709
+ c = f, n = null, _();
710
+ },
711
+ setEnabled(f) {
712
+ s = f, f || (n = null), _();
713
+ }
714
+ };
715
+ }
716
+ function ye() {
717
+ const e = x((a) => a.selection), [r, o] = C(!1), t = async () => {
718
+ e && (await navigator.clipboard.writeText(e.selector), o(!0), setTimeout(() => o(!1), 1200));
719
+ };
720
+ return /* @__PURE__ */ b("aside", { className: "pbu-panel", children: [
721
+ /* @__PURE__ */ l("div", { className: "pbu-panel-title", children: "선택된 블록" }),
722
+ e ? /* @__PURE__ */ b(F, { children: [
723
+ /* @__PURE__ */ b("div", { className: "pbu-field", children: [
724
+ /* @__PURE__ */ l("label", { children: "페이지" }),
725
+ /* @__PURE__ */ l("code", { children: e.pagePath })
726
+ ] }),
727
+ /* @__PURE__ */ b("div", { className: "pbu-field", children: [
728
+ /* @__PURE__ */ l("label", { children: "블록" }),
729
+ /* @__PURE__ */ b("div", { children: [
730
+ /* @__PURE__ */ l("span", { className: "pbu-chip", children: e.tag }),
731
+ /* @__PURE__ */ l("span", { children: e.label })
732
+ ] })
733
+ ] }),
734
+ /* @__PURE__ */ b("div", { className: "pbu-field", children: [
735
+ /* @__PURE__ */ l("label", { children: "Selector" }),
736
+ /* @__PURE__ */ l("code", { className: "pbu-selector", children: e.selector }),
737
+ /* @__PURE__ */ l("button", { type: "button", className: "pbu-btn", onClick: t, children: r ? "복사됨 ✓" : "Selector 복사" })
738
+ ] }),
739
+ /* @__PURE__ */ b("div", { className: "pbu-field", children: [
740
+ /* @__PURE__ */ l("label", { children: "크기" }),
741
+ /* @__PURE__ */ b("span", { children: [
742
+ Math.round(e.rect.width),
743
+ " × ",
744
+ Math.round(e.rect.height),
745
+ "px"
746
+ ] })
747
+ ] }),
748
+ /* @__PURE__ */ b("div", { className: "pbu-field", children: [
749
+ /* @__PURE__ */ l("label", { children: "단위" }),
750
+ /* @__PURE__ */ l("span", { children: e.granularity === "all" ? "전체" : e.granularity === "section" ? "섹션" : "유닛" })
751
+ ] }),
752
+ /* @__PURE__ */ b("div", { className: "pbu-phase3", children: [
753
+ /* @__PURE__ */ b("label", { children: [
754
+ "Figma 노드 링크",
755
+ /* @__PURE__ */ l("span", { className: "pbu-badge", children: "PHASE 3" })
756
+ ] }),
757
+ /* @__PURE__ */ l("input", { disabled: !0, placeholder: "https://figma.com/design/..." }),
758
+ /* @__PURE__ */ l("button", { type: "button", disabled: !0, className: "pbu-btn pbu-btn-primary", children: "이 블록 퍼블리싱 (준비 중)" })
759
+ ] })
760
+ ] }) : /* @__PURE__ */ b("div", { className: "pbu-panel-empty", children: [
761
+ "화면에서 블록에 마우스를 올리고 클릭해 선택하세요.",
762
+ /* @__PURE__ */ l("br", {}),
763
+ "상단 토글로 ",
764
+ /* @__PURE__ */ l("b", { children: "전체 / 섹션 / 유닛" }),
765
+ " 단위를 바꿀 수 있어요."
766
+ ] })
767
+ ] });
768
+ }
769
+ function _e({ ia: e }) {
770
+ const r = x((p) => p.viewerPath), o = x((p) => p.closeViewer), t = x((p) => p.granularity), a = x((p) => p.setGranularity), c = x((p) => p.inspectEnabled), s = x((p) => p.setInspectEnabled), n = L(null), i = L(null), [d, u] = C(!1), m = e.nodes.find((p) => p.path === r), w = () => {
771
+ i.current?.destroy(), i.current = null;
772
+ const p = n.current;
773
+ if (!p || !r) return;
774
+ const v = x.getState(), z = me(p, {
775
+ pagePath: r,
776
+ granularity: v.granularity,
777
+ enabled: v.inspectEnabled,
778
+ onSelect: (_) => x.getState().setSelection(_)
779
+ });
780
+ if (!z) {
781
+ u(!0);
782
+ return;
783
+ }
784
+ u(!1), i.current = z;
785
+ };
786
+ return k(() => () => i.current?.destroy(), []), k(() => {
787
+ i.current?.setGranularity(t);
788
+ }, [t]), k(() => {
789
+ i.current?.setEnabled(c);
790
+ }, [c]), k(() => {
791
+ const p = (v) => {
792
+ v.key === "Escape" && o();
793
+ };
794
+ return window.addEventListener("keydown", p), () => window.removeEventListener("keydown", p);
795
+ }, [o]), m ? /* @__PURE__ */ b("div", { className: "pbu-viewer", children: [
796
+ /* @__PURE__ */ b("div", { className: "pbu-bar", children: [
797
+ /* @__PURE__ */ l("button", { type: "button", className: "pbu-btn", onClick: o, children: "← 맵으로" }),
798
+ /* @__PURE__ */ b("span", { className: "pbu-viewer-title", children: [
799
+ m.title,
800
+ /* @__PURE__ */ l("code", { children: m.path })
801
+ ] }),
802
+ /* @__PURE__ */ l("span", { className: "pbu-spacer" }),
803
+ d && /* @__PURE__ */ l("span", { className: "pbu-hint", children: "⚠ 이 페이지는 검사할 수 없어요" }),
804
+ /* @__PURE__ */ b("div", { className: "pbu-seg", role: "group", "aria-label": "블록 단위", children: [
805
+ /* @__PURE__ */ l(
806
+ "button",
807
+ {
808
+ type: "button",
809
+ className: t === "all" ? "pbu-on" : "",
810
+ onClick: () => a("all"),
811
+ children: "전체"
812
+ }
813
+ ),
814
+ /* @__PURE__ */ l(
815
+ "button",
816
+ {
817
+ type: "button",
818
+ className: t === "section" ? "pbu-on" : "",
819
+ onClick: () => a("section"),
820
+ children: "섹션"
821
+ }
822
+ ),
823
+ /* @__PURE__ */ l(
824
+ "button",
825
+ {
826
+ type: "button",
827
+ className: t === "unit" ? "pbu-on" : "",
828
+ onClick: () => a("unit"),
829
+ children: "유닛"
830
+ }
831
+ )
832
+ ] }),
833
+ /* @__PURE__ */ b("label", { className: "pbu-toggle", children: [
834
+ /* @__PURE__ */ l(
835
+ "input",
836
+ {
837
+ type: "checkbox",
838
+ checked: c,
839
+ onChange: (p) => s(p.target.checked)
840
+ }
841
+ ),
842
+ "검사 모드"
843
+ ] }),
844
+ /* @__PURE__ */ l("button", { type: "button", className: "pbu-icon-btn", onClick: o, "aria-label": "닫기", children: "✕" })
845
+ ] }),
846
+ /* @__PURE__ */ b("div", { className: "pbu-viewer-body", children: [
847
+ /* @__PURE__ */ l("div", { className: "pbu-viewer-frame-wrap", children: /* @__PURE__ */ l(
848
+ "iframe",
849
+ {
850
+ ref: n,
851
+ className: "pbu-viewer-iframe",
852
+ src: m.path,
853
+ title: m.title,
854
+ onLoad: w
855
+ }
856
+ ) }),
857
+ /* @__PURE__ */ l(ye, {})
858
+ ] })
859
+ ] }) : null;
860
+ }
861
+ function Le({ config: e, enabled: r = !0 }) {
862
+ const o = r && !ee(), [t, a] = C(!1), c = x((i) => i.isMapOpen), s = x((i) => i.viewerPath), n = G(() => J(e), [e]);
863
+ return U(() => {
864
+ o && window.self === window.top && (ae(), a(!0));
865
+ }, [o]), !t || !o ? null : X(
866
+ /* @__PURE__ */ b(F, { children: [
867
+ /* @__PURE__ */ l(ue, {}),
868
+ c && /* @__PURE__ */ l(de, { ia: n }),
869
+ s && /* @__PURE__ */ l(_e, { ia: n })
870
+ ] }),
871
+ document.body
872
+ );
873
+ }
874
+ export {
875
+ Le as PageMap,
876
+ Se as defineIA,
877
+ J as normalizeIA
878
+ };
879
+ //# sourceMappingURL=index.js.map