@eyeon/map 2.0.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.
Files changed (58) hide show
  1. package/README.md +27 -0
  2. package/dist/assets/MapViewer.css +1 -0
  3. package/dist/assets/index.css +1 -0
  4. package/dist/chunks/MapViewer.js +530 -0
  5. package/dist/chunks/MapViewer.js.map +1 -0
  6. package/dist/chunks/graph-tools.js +153 -0
  7. package/dist/chunks/graph-tools.js.map +1 -0
  8. package/dist/chunks/pathfinding.js +343 -0
  9. package/dist/chunks/pathfinding.js.map +1 -0
  10. package/dist/core/geometry/index.d.ts +42 -0
  11. package/dist/core/geometry/index.d.ts.map +1 -0
  12. package/dist/core/import/index.d.ts +51 -0
  13. package/dist/core/import/index.d.ts.map +1 -0
  14. package/dist/core/index.d.ts +7 -0
  15. package/dist/core/index.d.ts.map +1 -0
  16. package/dist/core/index.js +282 -0
  17. package/dist/core/index.js.map +1 -0
  18. package/dist/core/publish/index.d.ts +28 -0
  19. package/dist/core/publish/index.d.ts.map +1 -0
  20. package/dist/core/routing/graph-tools.d.ts +47 -0
  21. package/dist/core/routing/graph-tools.d.ts.map +1 -0
  22. package/dist/core/routing/pathfinding.d.ts +22 -0
  23. package/dist/core/routing/pathfinding.d.ts.map +1 -0
  24. package/dist/core/types.d.ts +406 -0
  25. package/dist/core/types.d.ts.map +1 -0
  26. package/dist/editor/MapEditor.d.ts +31 -0
  27. package/dist/editor/MapEditor.d.ts.map +1 -0
  28. package/dist/editor/canvas/EditorCanvas.d.ts +22 -0
  29. package/dist/editor/canvas/EditorCanvas.d.ts.map +1 -0
  30. package/dist/editor/index.css +248 -0
  31. package/dist/editor/index.d.ts +5 -0
  32. package/dist/editor/index.d.ts.map +1 -0
  33. package/dist/editor/index.js +734 -0
  34. package/dist/editor/index.js.map +1 -0
  35. package/dist/editor/panels/Inspector.d.ts +14 -0
  36. package/dist/editor/panels/Inspector.d.ts.map +1 -0
  37. package/dist/editor/panels/LeftRail.d.ts +36 -0
  38. package/dist/editor/panels/LeftRail.d.ts.map +1 -0
  39. package/dist/editor/panels/PreviewOverlay.d.ts +6 -0
  40. package/dist/editor/panels/PreviewOverlay.d.ts.map +1 -0
  41. package/dist/index.d.ts +3 -0
  42. package/dist/index.d.ts.map +1 -0
  43. package/dist/viewer/MapViewer.d.ts +26 -0
  44. package/dist/viewer/MapViewer.d.ts.map +1 -0
  45. package/dist/viewer/components/LevelMeshes.d.ts +11 -0
  46. package/dist/viewer/components/LevelMeshes.d.ts.map +1 -0
  47. package/dist/viewer/components/MapScene.d.ts +12 -0
  48. package/dist/viewer/components/MapScene.d.ts.map +1 -0
  49. package/dist/viewer/components/RouteLine.d.ts +8 -0
  50. package/dist/viewer/components/RouteLine.d.ts.map +1 -0
  51. package/dist/viewer/index.css +210 -0
  52. package/dist/viewer/index.d.ts +4 -0
  53. package/dist/viewer/index.d.ts.map +1 -0
  54. package/dist/viewer/index.js +7 -0
  55. package/dist/viewer/index.js.map +1 -0
  56. package/dist/viewer/ui/RuntimeChrome.d.ts +19 -0
  57. package/dist/viewer/ui/RuntimeChrome.d.ts.map +1 -0
  58. package/package.json +81 -0
@@ -0,0 +1,734 @@
1
+ import { jsxs as r, jsx as n, Fragment as q } from "react/jsx-runtime";
2
+ import { useRef as z, useState as h, useMemo as V, useEffect as J, Suspense as Q, useCallback as ee } from "react";
3
+ import { v as Z, e as le } from "../chunks/pathfinding.js";
4
+ import { w as ne } from "../chunks/graph-tools.js";
5
+ import { a as ie } from "../chunks/MapViewer.js";
6
+ function F(i) {
7
+ return i.map((l) => {
8
+ if (l.length === 0) return "";
9
+ let p = `M ${l[0].x} ${l[0].y}`;
10
+ for (let d = 1; d < l.length; d++) p += ` L ${l[d].x} ${l[d].y}`;
11
+ return p += " Z", p;
12
+ }).join(" ");
13
+ }
14
+ function ae({
15
+ level: i,
16
+ shapes: l,
17
+ anchors: p,
18
+ edges: d,
19
+ theme: f,
20
+ tool: y,
21
+ baseAngle: K,
22
+ selectedShapeId: D,
23
+ selectedAnchorIds: _,
24
+ baseSvgUrl: I,
25
+ onSelectShape: C,
26
+ onSelectAnchors: t,
27
+ onCreateRoutePoint: u,
28
+ onMoveAnchor: S,
29
+ onCreateShape: O
30
+ }) {
31
+ const M = z(null), [b, E] = h({ x: 0, y: 0 }), [m, B] = h(1), [k, R] = h([]), [A, U] = h(null), [$, o] = h(null), g = z(null), v = (i == null ? void 0 : i.sourceViewbox) ?? { x: 0, y: 0, width: 1e3, height: 800 }, w = (e, c) => {
32
+ const s = M.current;
33
+ if (!s) return { x: 0, y: 0 };
34
+ const L = s.getBoundingClientRect(), T = (e - L.left - b.x) / m, a = (c - L.top - b.y) / m;
35
+ return { x: T + v.x, y: a + v.y };
36
+ }, Y = V(
37
+ () => new Map(p.map((e) => [e.id, e])),
38
+ [p]
39
+ ), X = (e) => {
40
+ if (y === "pan" || e.button === 1) {
41
+ g.current = { x: e.clientX, y: e.clientY, panX: b.x, panY: b.y };
42
+ return;
43
+ }
44
+ const c = w(e.clientX, e.clientY);
45
+ if (y === "draw-route") {
46
+ const s = $ ? Z(Y.get($) ?? c, c, K) : c;
47
+ u(s, $);
48
+ return;
49
+ }
50
+ y === "draw-unit" && R([c]);
51
+ }, j = (e) => {
52
+ if (g.current) {
53
+ E({
54
+ x: g.current.panX + (e.clientX - g.current.x),
55
+ y: g.current.panY + (e.clientY - g.current.y)
56
+ });
57
+ return;
58
+ }
59
+ if (A != null) {
60
+ const c = w(e.clientX, e.clientY);
61
+ S(A, c.x, c.y);
62
+ return;
63
+ }
64
+ if (y === "draw-unit" && k.length > 0) {
65
+ const c = w(e.clientX, e.clientY);
66
+ R((s) => [...s.slice(0, -1), s[s.length - 1], c].slice(0, -0) || [...s.slice(0, -1), c]), R((s) => s.length === 0 ? s : [...s.slice(0, -1), c]);
67
+ }
68
+ }, x = () => {
69
+ if (g.current = null, A != null) {
70
+ const e = p.find((c) => c.id === A);
71
+ if (e) {
72
+ const c = p.filter((s) => s.id !== e.id).filter((s) => Math.hypot(s.x - e.x, s.y - e.y) <= 2.5).map((s) => s.id);
73
+ c.length && t([e.id, ...c]);
74
+ }
75
+ U(null);
76
+ }
77
+ }, G = () => {
78
+ if (k.length < 3) {
79
+ R([]);
80
+ return;
81
+ }
82
+ const e = {
83
+ paths: [
84
+ {
85
+ d: F([k]),
86
+ closed: !0
87
+ }
88
+ ],
89
+ polygons: [k]
90
+ };
91
+ O("unit", e), R([]);
92
+ };
93
+ return /* @__PURE__ */ r(
94
+ "div",
95
+ {
96
+ className: "eyeon-map-canvas",
97
+ onWheel: (e) => {
98
+ e.preventDefault(), B((c) => Math.min(8, Math.max(0.2, c * (e.deltaY > 0 ? 0.9 : 1.1))));
99
+ },
100
+ children: [
101
+ /* @__PURE__ */ n(
102
+ "svg",
103
+ {
104
+ ref: M,
105
+ className: "eyeon-map-canvas__svg",
106
+ viewBox: `${v.x} ${v.y} ${v.width} ${v.height}`,
107
+ onPointerDown: X,
108
+ onPointerMove: j,
109
+ onPointerUp: x,
110
+ onDoubleClick: () => {
111
+ y === "draw-unit" && G();
112
+ },
113
+ children: /* @__PURE__ */ r("g", { transform: `translate(${b.x / m}, ${b.y / m}) scale(${m})`, children: [
114
+ I && /* @__PURE__ */ n(
115
+ "image",
116
+ {
117
+ href: I,
118
+ x: v.x,
119
+ y: v.y,
120
+ width: v.width,
121
+ height: v.height,
122
+ opacity: 0.85
123
+ }
124
+ ),
125
+ l.map((e) => /* @__PURE__ */ n(
126
+ "path",
127
+ {
128
+ d: e.geometry.paths.map((c) => c.d).join(" ") || F(e.geometry.polygons),
129
+ fill: e.style.fill ?? (e.kind === "walkable" ? f.WALKABLE_COLOR : e.kind === "unit" ? f.STORE_DEFAULT_COLOR : "#cbd5e1"),
130
+ fillOpacity: e.kind === "amenity" ? 0.15 : 0.85,
131
+ stroke: D === e.id ? f.ACCENT_COLOR : "#64748b",
132
+ strokeWidth: D === e.id ? 2.5 / m : 1 / m,
133
+ onClick: (c) => {
134
+ c.stopPropagation(), y === "select" && C(e.id);
135
+ },
136
+ style: { cursor: y === "select" ? "pointer" : "default" }
137
+ },
138
+ e.id
139
+ )),
140
+ d.map((e) => {
141
+ const c = Y.get(e.fromAnchorId), s = Y.get(e.toAnchorId);
142
+ return !c || !s ? null : /* @__PURE__ */ n(
143
+ "line",
144
+ {
145
+ x1: c.x,
146
+ y1: c.y,
147
+ x2: s.x,
148
+ y2: s.y,
149
+ stroke: f.ACCENT_COLOR,
150
+ strokeWidth: 2 / m,
151
+ strokeLinecap: "round"
152
+ },
153
+ e.id
154
+ );
155
+ }),
156
+ p.map((e) => {
157
+ const c = _.includes(e.id), s = c && _.some((L) => {
158
+ if (L === e.id) return !1;
159
+ const T = Y.get(L);
160
+ return T && Math.hypot(T.x - e.x, T.y - e.y) <= 2.5;
161
+ });
162
+ return /* @__PURE__ */ n(
163
+ "circle",
164
+ {
165
+ cx: e.x,
166
+ cy: e.y,
167
+ r: (c ? 5 : 3.5) / m,
168
+ fill: s ? "#22c55e" : c ? f.ACCENT_COLOR : "#0f172a",
169
+ stroke: "#fff",
170
+ strokeWidth: 1 / m,
171
+ onPointerDown: (L) => {
172
+ if (L.stopPropagation(), y === "draw-route") {
173
+ o(e.id), u(e, $);
174
+ return;
175
+ }
176
+ y === "select" && (t(
177
+ L.shiftKey ? _.includes(e.id) ? _.filter((T) => T !== e.id) : [..._, e.id] : [e.id]
178
+ ), U(e.id));
179
+ },
180
+ style: { cursor: "grab" }
181
+ },
182
+ e.id
183
+ );
184
+ }),
185
+ k.length > 1 && /* @__PURE__ */ n(
186
+ "polyline",
187
+ {
188
+ points: k.map((e) => `${e.x},${e.y}`).join(" "),
189
+ fill: "none",
190
+ stroke: f.ACCENT_COLOR,
191
+ strokeWidth: 2 / m,
192
+ strokeDasharray: `${6 / m} ${4 / m}`
193
+ }
194
+ )
195
+ ] })
196
+ }
197
+ ),
198
+ !i && /* @__PURE__ */ n("div", { className: "eyeon-map-canvas__empty", children: "Select or create a level to begin" })
199
+ ]
200
+ }
201
+ );
202
+ }
203
+ const te = [
204
+ { id: "levels", label: "Levels" },
205
+ { id: "shapes", label: "Shapes" },
206
+ { id: "routes", label: "Routes" },
207
+ { id: "amenities", label: "Amenities" },
208
+ { id: "kiosks", label: "Kiosks" },
209
+ { id: "theme", label: "Theme" }
210
+ ];
211
+ function re({
212
+ tab: i,
213
+ onTabChange: l,
214
+ draft: p,
215
+ activeLevelId: d,
216
+ onSelectLevel: f,
217
+ canFloors: y,
218
+ canSettings: K,
219
+ onImportSvg: D,
220
+ onAutoroute: _,
221
+ theme: I,
222
+ onThemeChange: C
223
+ }) {
224
+ return /* @__PURE__ */ r("aside", { className: "eyeon-map-rail", children: [
225
+ /* @__PURE__ */ n("nav", { className: "eyeon-map-rail__tabs", children: te.map((t) => /* @__PURE__ */ n(
226
+ "button",
227
+ {
228
+ type: "button",
229
+ className: i === t.id ? "is-active" : "",
230
+ onClick: () => l(t.id),
231
+ children: t.label
232
+ },
233
+ t.id
234
+ )) }),
235
+ /* @__PURE__ */ r("div", { className: "eyeon-map-rail__body", children: [
236
+ i === "levels" && /* @__PURE__ */ r("div", { className: "eyeon-map-rail__section", children: [
237
+ /* @__PURE__ */ n("div", { className: "eyeon-map-rail__heading", children: "Buildings" }),
238
+ p.buildings.map((t) => /* @__PURE__ */ r("div", { className: "eyeon-map-rail__group", children: [
239
+ /* @__PURE__ */ n("div", { className: "eyeon-map-rail__group-title", children: t.name }),
240
+ p.levels.filter((u) => u.buildingId === t.id).map((u) => /* @__PURE__ */ n(
241
+ "button",
242
+ {
243
+ type: "button",
244
+ className: u.id === d ? "eyeon-map-rail__row is-active" : "eyeon-map-rail__row",
245
+ onClick: () => f(u.id),
246
+ children: u.name
247
+ },
248
+ u.id
249
+ ))
250
+ ] }, t.id)),
251
+ /* @__PURE__ */ n("div", { className: "eyeon-map-rail__heading", children: "Outdoor" }),
252
+ p.levels.filter((t) => t.kind === "outdoor").map((t) => /* @__PURE__ */ n(
253
+ "button",
254
+ {
255
+ type: "button",
256
+ className: t.id === d ? "eyeon-map-rail__row is-active" : "eyeon-map-rail__row",
257
+ onClick: () => f(t.id),
258
+ children: t.name
259
+ },
260
+ t.id
261
+ )),
262
+ y && d != null && /* @__PURE__ */ r("div", { className: "eyeon-map-rail__actions", children: [
263
+ /* @__PURE__ */ r("label", { className: "eyeon-map-rail__file", children: [
264
+ "Import SVG",
265
+ /* @__PURE__ */ n(
266
+ "input",
267
+ {
268
+ type: "file",
269
+ accept: ".svg,image/svg+xml",
270
+ onChange: (t) => {
271
+ var S;
272
+ const u = (S = t.target.files) == null ? void 0 : S[0];
273
+ u && D && D(d, u);
274
+ }
275
+ }
276
+ )
277
+ ] }),
278
+ /* @__PURE__ */ n("button", { type: "button", onClick: () => _ == null ? void 0 : _(d), children: "Auto-route" })
279
+ ] })
280
+ ] }),
281
+ i === "shapes" && /* @__PURE__ */ r("div", { className: "eyeon-map-rail__section", children: [
282
+ /* @__PURE__ */ r("div", { className: "eyeon-map-rail__heading", children: [
283
+ "Shapes (",
284
+ p.shapes.filter((t) => t.levelId === d).length,
285
+ ")"
286
+ ] }),
287
+ p.shapes.filter((t) => t.levelId === d).map((t) => /* @__PURE__ */ r("div", { className: "eyeon-map-rail__row", children: [
288
+ /* @__PURE__ */ n("span", { className: "eyeon-map-rail__muted", children: t.kind }),
289
+ " ",
290
+ t.key
291
+ ] }, t.id))
292
+ ] }),
293
+ i === "routes" && /* @__PURE__ */ r("div", { className: "eyeon-map-rail__section", children: [
294
+ /* @__PURE__ */ n("div", { className: "eyeon-map-rail__heading", children: "Anchors / Edges" }),
295
+ /* @__PURE__ */ n("p", { className: "eyeon-map-rail__hint", children: "Draw routes on the canvas. Drag anchors onto each other to weld. Green highlight means a weld is available." }),
296
+ /* @__PURE__ */ r("div", { className: "eyeon-map-rail__stat", children: [
297
+ p.anchors.filter((t) => t.levelId === d).length,
298
+ " anchors ·",
299
+ " ",
300
+ p.edges.length,
301
+ " edges"
302
+ ] })
303
+ ] }),
304
+ i === "amenities" && /* @__PURE__ */ r("div", { className: "eyeon-map-rail__section", children: [
305
+ /* @__PURE__ */ n("div", { className: "eyeon-map-rail__heading", children: "Amenity catalog" }),
306
+ p.amenities.map((t) => /* @__PURE__ */ r("div", { className: "eyeon-map-rail__row", children: [
307
+ t.name,
308
+ /* @__PURE__ */ n("span", { className: "eyeon-map-rail__muted", children: t.code })
309
+ ] }, t.id))
310
+ ] }),
311
+ i === "kiosks" && /* @__PURE__ */ n("div", { className: "eyeon-map-rail__section", children: /* @__PURE__ */ n("p", { className: "eyeon-map-rail__hint", children: "Assign a kiosk_screen shape to a display_kiosks device in the inspector." }) }),
312
+ i === "theme" && K && /* @__PURE__ */ r("div", { className: "eyeon-map-rail__section", children: [
313
+ /* @__PURE__ */ n("div", { className: "eyeon-map-rail__heading", children: "Theme" }),
314
+ /* @__PURE__ */ r("label", { className: "eyeon-map-rail__field", children: [
315
+ "Style",
316
+ /* @__PURE__ */ r(
317
+ "select",
318
+ {
319
+ value: I.MAP_STYLE,
320
+ onChange: (t) => C({ MAP_STYLE: t.target.value }),
321
+ children: [
322
+ /* @__PURE__ */ n("option", { value: "2D", children: "2D" }),
323
+ /* @__PURE__ */ n("option", { value: "3D", children: "3D" })
324
+ ]
325
+ }
326
+ )
327
+ ] }),
328
+ [
329
+ ["ACCENT_COLOR", "Accent"],
330
+ ["STORE_DEFAULT_COLOR", "Store fill"],
331
+ ["MAP_BACKGROUND_COLOR", "Background"],
332
+ ["WALL_COLOR", "Walls"],
333
+ ["PARKING_ZONE_COLOR", "Parking"],
334
+ ["GREEN_AREA_COLOR", "Green"],
335
+ ["WATER_COLOR", "Water"]
336
+ ].map(([t, u]) => /* @__PURE__ */ r("label", { className: "eyeon-map-rail__field", children: [
337
+ u,
338
+ /* @__PURE__ */ n(
339
+ "input",
340
+ {
341
+ type: "color",
342
+ value: I[t],
343
+ onChange: (S) => C({ [t]: S.target.value })
344
+ }
345
+ )
346
+ ] }, t))
347
+ ] })
348
+ ] })
349
+ ] });
350
+ }
351
+ const oe = [
352
+ "unit",
353
+ "amenity",
354
+ "kiosk_screen",
355
+ "connector",
356
+ "entrance",
357
+ "walkable",
358
+ "void",
359
+ "wall",
360
+ "boundary",
361
+ "floorplate",
362
+ "decor",
363
+ "label",
364
+ "zone",
365
+ "parking_zone",
366
+ "green_area",
367
+ "water",
368
+ "parking_icon"
369
+ ], ce = [
370
+ "occupied",
371
+ "vacant",
372
+ "coming_soon",
373
+ "under_renovation"
374
+ ];
375
+ function de({
376
+ shape: i,
377
+ assignment: l,
378
+ amenities: p,
379
+ canEdit: d,
380
+ onRename: f,
381
+ onChangeKind: y,
382
+ onSaveAssignment: K,
383
+ undoCount: D
384
+ }) {
385
+ var A, U, $;
386
+ const [_, I] = h((i == null ? void 0 : i.key) ?? ""), [C, t] = h(
387
+ ((A = l == null ? void 0 : l.retailerId) == null ? void 0 : A.toString()) ?? ""
388
+ ), [u, S] = h(
389
+ ((U = l == null ? void 0 : l.amenityId) == null ? void 0 : U.toString()) ?? ""
390
+ ), [O, M] = h(
391
+ (($ = l == null ? void 0 : l.kioskId) == null ? void 0 : $.toString()) ?? ""
392
+ ), [b, E] = h(
393
+ (l == null ? void 0 : l.unitStatus) ?? "vacant"
394
+ ), [m, B] = h((l == null ? void 0 : l.unitNumber) ?? ""), [k, R] = h((l == null ? void 0 : l.customLabel) ?? "");
395
+ return J(() => {
396
+ var o, g, v;
397
+ I((i == null ? void 0 : i.key) ?? ""), t(((o = l == null ? void 0 : l.retailerId) == null ? void 0 : o.toString()) ?? ""), S(((g = l == null ? void 0 : l.amenityId) == null ? void 0 : g.toString()) ?? ""), M(((v = l == null ? void 0 : l.kioskId) == null ? void 0 : v.toString()) ?? ""), E((l == null ? void 0 : l.unitStatus) ?? "vacant"), B((l == null ? void 0 : l.unitNumber) ?? ""), R((l == null ? void 0 : l.customLabel) ?? "");
398
+ }, [i, l]), i ? /* @__PURE__ */ r("aside", { className: "eyeon-map-inspector", children: [
399
+ /* @__PURE__ */ n("div", { className: "eyeon-map-inspector__heading", children: "Shape" }),
400
+ /* @__PURE__ */ r("label", { className: "eyeon-map-rail__field", children: [
401
+ "Key / ID",
402
+ /* @__PURE__ */ n(
403
+ "input",
404
+ {
405
+ value: _,
406
+ disabled: !d,
407
+ onChange: (o) => I(o.target.value),
408
+ onBlur: () => {
409
+ _ && _ !== i.key && f(_);
410
+ }
411
+ }
412
+ )
413
+ ] }),
414
+ /* @__PURE__ */ r("label", { className: "eyeon-map-rail__field", children: [
415
+ "Kind",
416
+ /* @__PURE__ */ n(
417
+ "select",
418
+ {
419
+ value: i.kind,
420
+ disabled: !d,
421
+ onChange: (o) => y(o.target.value),
422
+ children: oe.map((o) => /* @__PURE__ */ n("option", { value: o, children: o }, o))
423
+ }
424
+ )
425
+ ] }),
426
+ /* @__PURE__ */ n("div", { className: "eyeon-map-inspector__heading", children: "Assignment" }),
427
+ (i.kind === "unit" || i.kind === "parking_zone") && /* @__PURE__ */ r(q, { children: [
428
+ /* @__PURE__ */ r("label", { className: "eyeon-map-rail__field", children: [
429
+ "Retailer ID",
430
+ /* @__PURE__ */ n(
431
+ "input",
432
+ {
433
+ value: C,
434
+ disabled: !d,
435
+ onChange: (o) => t(o.target.value)
436
+ }
437
+ )
438
+ ] }),
439
+ /* @__PURE__ */ r("label", { className: "eyeon-map-rail__field", children: [
440
+ "Status",
441
+ /* @__PURE__ */ n(
442
+ "select",
443
+ {
444
+ value: b,
445
+ disabled: !d,
446
+ onChange: (o) => E(o.target.value),
447
+ children: ce.map((o) => /* @__PURE__ */ n("option", { value: o, children: o }, o))
448
+ }
449
+ )
450
+ ] }),
451
+ /* @__PURE__ */ r("label", { className: "eyeon-map-rail__field", children: [
452
+ "Unit number",
453
+ /* @__PURE__ */ n(
454
+ "input",
455
+ {
456
+ value: m,
457
+ disabled: !d,
458
+ onChange: (o) => B(o.target.value)
459
+ }
460
+ )
461
+ ] })
462
+ ] }),
463
+ i.kind === "amenity" && /* @__PURE__ */ r("label", { className: "eyeon-map-rail__field", children: [
464
+ "Amenity",
465
+ /* @__PURE__ */ r(
466
+ "select",
467
+ {
468
+ value: u,
469
+ disabled: !d,
470
+ onChange: (o) => S(o.target.value),
471
+ children: [
472
+ /* @__PURE__ */ n("option", { value: "", children: "—" }),
473
+ p.map((o) => /* @__PURE__ */ n("option", { value: o.id, children: o.name }, o.id))
474
+ ]
475
+ }
476
+ )
477
+ ] }),
478
+ i.kind === "kiosk_screen" && /* @__PURE__ */ r("label", { className: "eyeon-map-rail__field", children: [
479
+ "Kiosk device ID",
480
+ /* @__PURE__ */ n(
481
+ "input",
482
+ {
483
+ value: O,
484
+ disabled: !d,
485
+ onChange: (o) => M(o.target.value)
486
+ }
487
+ )
488
+ ] }),
489
+ /* @__PURE__ */ r("label", { className: "eyeon-map-rail__field", children: [
490
+ "Custom label",
491
+ /* @__PURE__ */ n(
492
+ "input",
493
+ {
494
+ value: k,
495
+ disabled: !d,
496
+ onChange: (o) => R(o.target.value)
497
+ }
498
+ )
499
+ ] }),
500
+ d && /* @__PURE__ */ n(
501
+ "button",
502
+ {
503
+ type: "button",
504
+ className: "eyeon-map-inspector__save",
505
+ onClick: () => K({
506
+ shapeId: i.id,
507
+ targetType: C ? "retailer" : u ? "amenity" : O ? "kiosk" : "none",
508
+ retailerId: C ? Number(C) : null,
509
+ amenityId: u ? Number(u) : null,
510
+ kioskId: O ? Number(O) : null,
511
+ unitStatus: b,
512
+ unitNumber: m || null,
513
+ customLabel: k || null,
514
+ customImageKey: (l == null ? void 0 : l.customImageKey) ?? null
515
+ }),
516
+ children: "Save assignment"
517
+ }
518
+ )
519
+ ] }) : /* @__PURE__ */ n("aside", { className: "eyeon-map-inspector", children: /* @__PURE__ */ r("div", { className: "eyeon-map-inspector__empty", children: [
520
+ "Select a shape or anchor",
521
+ /* @__PURE__ */ r("div", { className: "eyeon-map-rail__muted", children: [
522
+ "Undo stack: ",
523
+ D
524
+ ] })
525
+ ] }) });
526
+ }
527
+ function se({ document: i }) {
528
+ return /* @__PURE__ */ n("div", { className: "eyeon-map-preview", children: /* @__PURE__ */ n(Q, { fallback: /* @__PURE__ */ n("div", { className: "eyeon-map-preview__loading", children: "Loading preview…" }), children: /* @__PURE__ */ n(ie, { document: i, role: "PORTAL_PREVIEW" }) }) });
529
+ }
530
+ function _e({
531
+ draft: i,
532
+ canEdit: l = !0,
533
+ canFloors: p = !0,
534
+ canSettings: d = !0,
535
+ onBatch: f,
536
+ onPublish: y,
537
+ onImportSvg: K,
538
+ onAutoroute: D,
539
+ previewDocument: _,
540
+ className: I
541
+ }) {
542
+ var T;
543
+ const [C, t] = h("levels"), [u, S] = h(
544
+ ((T = i.levels[0]) == null ? void 0 : T.id) ?? null
545
+ ), [O, M] = h(null), [b, E] = h([]), [m, B] = h("select"), [k, R] = h(!1), [A, U] = h(0), [$, o] = h([]), g = z([]), v = V(
546
+ () => ({ ...le, ...i.theme }),
547
+ [i.theme]
548
+ ), w = i.levels.find((a) => a.id === u) ?? null, Y = i.shapes.filter((a) => a.levelId === u), X = i.anchors.filter((a) => a.levelId === u), j = i.edges.filter((a) => {
549
+ const N = i.anchors.find((P) => P.id === a.fromAnchorId);
550
+ return (N == null ? void 0 : N.levelId) === u;
551
+ }), x = Y.find((a) => a.id === O) ?? null, G = i.assignments.find((a) => a.shapeId === O) ?? null, e = ee(
552
+ async (a) => {
553
+ !a.length || !f || (o((N) => [...N, a]), await f(a), g.current = []);
554
+ },
555
+ [f]
556
+ ), c = async () => {
557
+ if (b.length < 2) return;
558
+ const a = X.map((W) => ({ ...W })), N = i.edges.map((W) => ({ ...W })), P = ne(a, N, b);
559
+ P && (await e([
560
+ {
561
+ op: "weld_anchors",
562
+ anchorIds: b
563
+ }
564
+ ]), E([P.survivingAnchorId]));
565
+ }, s = async (a) => {
566
+ !x || !l || await e([
567
+ {
568
+ op: "upsert_shape",
569
+ shape: {
570
+ id: x.id,
571
+ levelId: x.levelId,
572
+ key: a,
573
+ kind: x.kind
574
+ }
575
+ }
576
+ ]);
577
+ }, L = async (a) => {
578
+ !x || !l || await e([
579
+ {
580
+ op: "upsert_shape",
581
+ shape: {
582
+ id: x.id,
583
+ levelId: x.levelId,
584
+ key: x.key,
585
+ kind: a
586
+ }
587
+ }
588
+ ]);
589
+ };
590
+ return /* @__PURE__ */ r("div", { className: `eyeon-map-editor ${I ?? ""}`, children: [
591
+ /* @__PURE__ */ n(
592
+ re,
593
+ {
594
+ tab: C,
595
+ onTabChange: t,
596
+ draft: i,
597
+ activeLevelId: u,
598
+ onSelectLevel: S,
599
+ canFloors: p,
600
+ canSettings: d,
601
+ onImportSvg: K,
602
+ onAutoroute: D,
603
+ theme: v,
604
+ onThemeChange: async (a) => {
605
+ d && await e([{ op: "update_theme", theme: a }]);
606
+ }
607
+ }
608
+ ),
609
+ /* @__PURE__ */ r("div", { className: "eyeon-map-editor__center", children: [
610
+ /* @__PURE__ */ r("div", { className: "eyeon-map-editor__toolbar", children: [
611
+ /* @__PURE__ */ r("div", { className: "eyeon-map-editor__tools", children: [
612
+ ["select", "pan", "draw-unit", "draw-route"].map((a) => /* @__PURE__ */ n(
613
+ "button",
614
+ {
615
+ type: "button",
616
+ className: m === a ? "is-active" : "",
617
+ onClick: () => B(a),
618
+ disabled: !l && a.startsWith("draw"),
619
+ children: a
620
+ },
621
+ a
622
+ )),
623
+ /* @__PURE__ */ n("button", { type: "button", onClick: c, disabled: b.length < 2, children: "Weld anchors" }),
624
+ /* @__PURE__ */ r("label", { className: "eyeon-map-editor__angle", children: [
625
+ "Base °",
626
+ /* @__PURE__ */ n(
627
+ "input",
628
+ {
629
+ type: "number",
630
+ value: A,
631
+ onChange: (a) => U(Number(a.target.value) || 0)
632
+ }
633
+ )
634
+ ] })
635
+ ] }),
636
+ /* @__PURE__ */ r("div", { className: "eyeon-map-editor__actions", children: [
637
+ /* @__PURE__ */ n("button", { type: "button", onClick: () => R((a) => !a), children: k ? "Edit" : "Preview" }),
638
+ /* @__PURE__ */ n(
639
+ "button",
640
+ {
641
+ type: "button",
642
+ className: "eyeon-map-editor__publish",
643
+ onClick: () => y == null ? void 0 : y(),
644
+ disabled: !l,
645
+ children: "Publish"
646
+ }
647
+ )
648
+ ] })
649
+ ] }),
650
+ /* @__PURE__ */ n("div", { className: "eyeon-map-editor__canvas-wrap", children: k && _ ? /* @__PURE__ */ n(se, { document: _ }) : /* @__PURE__ */ n(
651
+ ae,
652
+ {
653
+ level: w,
654
+ shapes: Y,
655
+ anchors: X,
656
+ edges: j,
657
+ assignments: i.assignments,
658
+ theme: v,
659
+ tool: m,
660
+ baseAngle: A,
661
+ selectedShapeId: O,
662
+ selectedAnchorIds: b,
663
+ baseSvgUrl: (w == null ? void 0 : w.kind) === "outdoor" ? i.baseSvgUrl ?? null : null,
664
+ onSelectShape: M,
665
+ onSelectAnchors: E,
666
+ onCreateRoutePoint: async (a, N) => {
667
+ if (!w || !l) return;
668
+ const P = N ? Z(
669
+ X.find((W) => W.id === N) ?? a,
670
+ a,
671
+ A
672
+ ) : a;
673
+ await e([
674
+ {
675
+ op: "upsert_anchor",
676
+ anchor: {
677
+ levelId: w.id,
678
+ x: P.x,
679
+ y: P.y,
680
+ kind: "junction"
681
+ }
682
+ }
683
+ ]);
684
+ },
685
+ onMoveAnchor: async (a, N, P) => {
686
+ if (!l) return;
687
+ const W = X.find((H) => H.id === a);
688
+ W && await e([
689
+ {
690
+ op: "upsert_anchor",
691
+ anchor: { ...W, x: N, y: P }
692
+ }
693
+ ]);
694
+ },
695
+ onCreateShape: async (a, N) => {
696
+ !w || !l || await e([
697
+ {
698
+ op: "upsert_shape",
699
+ shape: {
700
+ levelId: w.id,
701
+ key: `${a}-${Date.now()}`,
702
+ kind: a,
703
+ geometry: N
704
+ }
705
+ }
706
+ ]);
707
+ }
708
+ }
709
+ ) })
710
+ ] }),
711
+ /* @__PURE__ */ n(
712
+ de,
713
+ {
714
+ shape: x,
715
+ assignment: G,
716
+ amenities: i.amenities,
717
+ canEdit: l,
718
+ onRename: s,
719
+ onChangeKind: L,
720
+ onSaveAssignment: async (a) => {
721
+ l && await e([{ op: "upsert_assignment", assignment: a }]);
722
+ },
723
+ undoCount: $.length
724
+ }
725
+ )
726
+ ] });
727
+ }
728
+ export {
729
+ ae as EditorCanvas,
730
+ de as Inspector,
731
+ re as LeftRail,
732
+ _e as MapEditor
733
+ };
734
+ //# sourceMappingURL=index.js.map