@eventcatalog/visualiser 5.1.2 → 5.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/studio.mjs CHANGED
@@ -1,22 +1,52 @@
1
1
  import {
2
+ CATALOG_COLLECTIONS,
3
+ CATALOG_GROUPS,
4
+ COMPONENT_TYPES,
2
5
  CanvasPortal,
6
+ DEFAULT_NODE_SIZE,
3
7
  DIAGRAM_FIT_VIEW_OPTIONS,
4
8
  DomainCard_default,
5
9
  ENTITY_TARGET_HANDLE_ID,
6
10
  EdgeLabelPortal,
11
+ EditStatus,
12
+ EditableText,
7
13
  Entity_default,
14
+ Field,
15
+ GROUP_TYPES,
16
+ NODE_CATEGORIES,
17
+ NODE_ICONS,
18
+ NodeCard,
8
19
  SystemGroupNode_default,
9
20
  Toolbar,
10
21
  ToolbarButton,
11
22
  ToolbarDivider,
12
23
  ZoomLevel,
13
24
  addExportBranding,
25
+ canGoInContainer,
26
+ canHold,
27
+ componentKey,
14
28
  diagramNodeComponents,
15
29
  eventcatalog_logo_default,
16
30
  getExportImageDimensions,
31
+ getNodeDefinition,
32
+ getNodeLabel,
33
+ getNodeName,
34
+ getNodeSize as getNodeSize2,
35
+ getNoteLevel,
36
+ getResource,
17
37
  injectExportStyles,
18
- memoNode
19
- } from "./chunk-RHE5IMXC.mjs";
38
+ isCatalogCollection,
39
+ isGroupType,
40
+ isOnLevel,
41
+ isShownOnLevel,
42
+ isVersioned,
43
+ isWrittenOnCanvas,
44
+ memoNode,
45
+ nodeDefinitions,
46
+ updateResource,
47
+ useNodeAnchor,
48
+ useSavedFlash
49
+ } from "./chunk-QQUJTD6O.mjs";
20
50
  import "./chunk-STJQWGKW.mjs";
21
51
  import {
22
52
  getMessagesLabel,
@@ -105,317 +135,6 @@ var createEdge = (connection, sourceType, targetType) => {
105
135
  };
106
136
  };
107
137
 
108
- // src/studio/node-types.ts
109
- var NODE_CATEGORIES = [
110
- { id: "boundaries", label: "Boundaries" },
111
- // What's deployed (services, UIs, agents) and what's outside it: drawn first, then what flows between them
112
- { id: "architecture", label: "Services" },
113
- { id: "messages", label: "Messages" },
114
- // Where data lives: all data nodes, of EventCatalog's kinds (container_type)
115
- { id: "data", label: "Data" },
116
- // Who's involved: who uses the architecture (actors) and who owns it (teams)
117
- { id: "people", label: "People" },
118
- { id: "other", label: "Other" }
119
- ];
120
- var CATALOG_COLLECTIONS = [
121
- "domains",
122
- "systems",
123
- "services",
124
- "events",
125
- "commands",
126
- "queries",
127
- "channels",
128
- "containers"
129
- ];
130
- var isCatalogCollection = (collection) => CATALOG_COLLECTIONS.includes(collection);
131
- var GROUP_TYPES = {
132
- domain: "domain-group",
133
- system: "system-group"
134
- };
135
- var isGroupType = (type) => type === GROUP_TYPES.domain || type === GROUP_TYPES.system;
136
- var resource = (name, summary) => ({
137
- name,
138
- version: "0.0.1",
139
- summary,
140
- owners: []
141
- });
142
- var DATA_KINDS = [
143
- {
144
- containerType: "database",
145
- label: "Database",
146
- name: "New Database",
147
- summary: "Tables, e.g. PostgreSQL"
148
- },
149
- {
150
- containerType: "cache",
151
- label: "Cache",
152
- name: "New Cache",
153
- summary: "Fast data, e.g. Redis"
154
- },
155
- {
156
- containerType: "searchIndex",
157
- label: "Search index",
158
- name: "New Search Index",
159
- summary: "Search, e.g. Elasticsearch"
160
- },
161
- {
162
- containerType: "objectStore",
163
- label: "Object store",
164
- name: "New Object Store",
165
- summary: "Files and blobs, e.g. S3"
166
- }
167
- ];
168
- var nodeDefinitions = [
169
- {
170
- type: GROUP_TYPES.domain,
171
- firstLevel: 1,
172
- label: "Domain",
173
- summary: "A business area, e.g. Sales",
174
- category: "boundaries",
175
- resourceKey: "domain",
176
- defaultSize: { width: 720, height: 460 },
177
- createData: () => ({ domain: { name: "New Domain", version: "0.0.1" } })
178
- },
179
- {
180
- type: GROUP_TYPES.system,
181
- firstLevel: 1,
182
- label: "System",
183
- summary: "Services doing one job",
184
- category: "boundaries",
185
- resourceKey: "system",
186
- defaultSize: { width: 560, height: 360 },
187
- createData: () => ({ system: { name: "New System", version: "0.0.1" } })
188
- },
189
- {
190
- type: "service",
191
- firstLevel: 2,
192
- category: "architecture",
193
- label: "Service",
194
- summary: "An API, worker or function",
195
- resourceKey: "service",
196
- createData: () => ({
197
- mode: "full",
198
- service: {
199
- ...resource("New Service", "Describe what this service does."),
200
- sends: [],
201
- receives: []
202
- }
203
- })
204
- },
205
- {
206
- type: "event",
207
- firstLevel: 3,
208
- category: "messages",
209
- label: "Event",
210
- summary: "Something that happened",
211
- resourceKey: "message",
212
- createData: () => ({
213
- mode: "full",
214
- message: resource("NewEvent", "Something happened.")
215
- })
216
- },
217
- {
218
- type: "command",
219
- firstLevel: 3,
220
- category: "messages",
221
- label: "Command",
222
- summary: "A request to do something",
223
- resourceKey: "message",
224
- createData: () => ({
225
- mode: "full",
226
- message: resource("NewCommand", "Asks a service to do something.")
227
- })
228
- },
229
- {
230
- type: "query",
231
- firstLevel: 3,
232
- category: "messages",
233
- label: "Query",
234
- summary: "A request for data",
235
- resourceKey: "message",
236
- createData: () => ({
237
- mode: "full",
238
- message: resource("NewQuery", "Asks for some information.")
239
- })
240
- },
241
- {
242
- type: "channel",
243
- firstLevel: 3,
244
- // With the messages it carries
245
- category: "messages",
246
- label: "Channel",
247
- summary: "A topic, queue or bus",
248
- resourceKey: "channel",
249
- createData: () => ({
250
- mode: "full",
251
- channel: {
252
- ...resource("new.channel", "Where messages are routed."),
253
- protocols: []
254
- }
255
- })
256
- },
257
- {
258
- type: "view",
259
- firstLevel: 2,
260
- category: "architecture",
261
- label: "View",
262
- summary: "A screen or app people use",
263
- resourceKey: "view",
264
- createData: () => ({
265
- mode: "full",
266
- view: resource("New View", "What the user sees.")
267
- })
268
- },
269
- {
270
- type: "externalSystem",
271
- firstLevel: 1,
272
- category: "architecture",
273
- label: "External System",
274
- summary: "A third party you use",
275
- resourceKey: "externalSystem",
276
- createData: () => ({
277
- mode: "full",
278
- externalSystem: resource("External System", "A third party system.")
279
- })
280
- },
281
- {
282
- type: "agent",
283
- // The detail of how things work, like messages: shown on L3 (L1 and L2 draw past it)
284
- firstLevel: 3,
285
- category: "architecture",
286
- label: "Agent",
287
- summary: "An AI agent at work",
288
- resourceKey: "agent",
289
- createData: () => ({
290
- mode: "full",
291
- agent: {
292
- ...resource("New Agent", "What this agent does."),
293
- sends: [],
294
- receives: []
295
- }
296
- })
297
- },
298
- {
299
- type: "actor",
300
- firstLevel: 1,
301
- // Who uses the architecture: customers, operators, partners (Studio's actors)
302
- category: "people",
303
- label: "Actor",
304
- summary: "Someone who uses it",
305
- // Drawn like the visualiser's actors (by name only); the summary is for agents and the properties panel
306
- createData: () => ({ mode: "full", name: "Customer", summary: "" })
307
- },
308
- {
309
- type: "team",
310
- firstLevel: 1,
311
- // Who owns what: connected to a domain, system or service, it's its owner (EventCatalog's owners)
312
- category: "people",
313
- label: "Team",
314
- summary: "Who owns what",
315
- resourceKey: "team",
316
- createData: () => ({
317
- mode: "full",
318
- team: resource("New Team", "What this team looks after.")
319
- })
320
- },
321
- {
322
- type: "text",
323
- // On the bar at the top (T, N), not in the palette
324
- unlisted: true,
325
- firstLevel: 2,
326
- category: "other",
327
- label: "Text",
328
- defaultSize: { width: 240, height: 40 },
329
- autoSize: true,
330
- createData: () => ({ text: "Add some text" })
331
- },
332
- {
333
- type: "note",
334
- // On the bar at the top (T, N), not in the palette
335
- unlisted: true,
336
- firstLevel: 1,
337
- category: "other",
338
- label: "Sticky Note",
339
- // About square, like a post-it (taller if more is written on it)
340
- defaultSize: { width: 200, height: 176 },
341
- autoHeight: true,
342
- createData: () => ({ text: "", color: "yellow" })
343
- },
344
- // The kinds of data store: all data nodes (EventCatalog's containers), told apart by their container_type
345
- ...DATA_KINDS.map(
346
- ({ containerType, label, name, summary }) => ({
347
- type: "data",
348
- ...containerType !== "database" && { id: `data:${containerType}` },
349
- firstLevel: 2,
350
- category: "data",
351
- label,
352
- summary,
353
- resourceKey: "data",
354
- createData: () => ({
355
- mode: "full",
356
- data: {
357
- ...resource(name, "Stores data."),
358
- container_type: containerType
359
- }
360
- })
361
- })
362
- ),
363
- {
364
- type: "entity",
365
- // The domain model: detail, like messages (L3)
366
- firstLevel: 3,
367
- // The domain's data model, with the stores it's kept in
368
- category: "data",
369
- label: "Entity",
370
- summary: "Part of the domain model",
371
- resourceKey: "entity",
372
- createData: () => ({
373
- mode: "full",
374
- entity: {
375
- ...resource("NewEntity", "Something the domain keeps track of."),
376
- properties: [
377
- { name: "id", type: "string", required: true },
378
- { name: "createdAt", type: "string" }
379
- ]
380
- }
381
- })
382
- }
383
- ];
384
- var componentKey = (definition) => definition.id ?? definition.type;
385
- var COMPONENT_TYPES = [
386
- ...new Set(
387
- nodeDefinitions.filter((definition) => !definition.unlisted).map((definition) => definition.type)
388
- )
389
- ];
390
- var definitionsByType = new Map(
391
- nodeDefinitions.map((definition) => [componentKey(definition), definition])
392
- );
393
- var catalogNodeTypes = {
394
- system: { label: "System", resourceKey: "system", firstLevel: 1 },
395
- "context-domain": { label: "Domain", resourceKey: "domain", firstLevel: 1 }
396
- };
397
- var getNodeDefinition = (type) => type ? definitionsByType.get(type) : void 0;
398
- var getNodeLabel = (type) => getNodeDefinition(type)?.label ?? catalogNodeTypes[type ?? ""]?.label ?? "Node";
399
- var DEFAULT_NODE_SIZE = { width: 240, height: 112 };
400
- var getNodeSize2 = (type) => getNodeDefinition(type)?.defaultSize ?? DEFAULT_NODE_SIZE;
401
- var getResourceKey = (type) => getNodeDefinition(type)?.resourceKey ?? catalogNodeTypes[type ?? ""]?.resourceKey;
402
- var getResource = (type, data) => {
403
- const key = getResourceKey(type);
404
- return key ? data[key] ?? {} : data;
405
- };
406
- var canGoInContainer = (type) => !isWrittenOnCanvas(type);
407
- var canHold = (containerType, type) => canGoInContainer(type) && (containerType === GROUP_TYPES.domain || containerType === GROUP_TYPES.system && type !== GROUP_TYPES.domain && type !== "context-domain");
408
- var getNoteLevel = (node) => isWrittenOnCanvas(node.type) ? node.data.level ?? 3 : void 0;
409
- var isOnLevel = (node, level) => !isWrittenOnCanvas(node.type) || getNoteLevel(node) === level;
410
- var isShownOnLevel = (type, level) => level >= (getNodeDefinition(type)?.firstLevel ?? catalogNodeTypes[type ?? ""]?.firstLevel ?? 3);
411
- var isVersioned = (type) => !!getResourceKey(type);
412
- var isWrittenOnCanvas = (type) => type === "note" || type === "text";
413
- var updateResource = (type, data, fields) => {
414
- const key = getResourceKey(type);
415
- return key ? { ...data, [key]: { ...getResource(type, data), ...fields } } : { ...data, ...fields };
416
- };
417
- var getNodeName = (type, data, fallback = "node") => String(getResource(type, data).name ?? data.text ?? fallback);
418
-
419
138
  // src/studio/grouping.ts
420
139
  var GROUP_PADDING = { top: 80, right: 40, bottom: 40, left: 40 };
421
140
  var byId = (nodes) => new Map(nodes.map((node) => [node.id, node]));
@@ -1350,6 +1069,228 @@ var offsetToCentre = (roots, at) => {
1350
1069
  return { x: at.x - (left + right) / 2, y: at.y - (top + bottom) / 2 };
1351
1070
  };
1352
1071
 
1072
+ // src/studio/connect-new.ts
1073
+ var CONNECT_PLACEHOLDER = "connect-placeholder";
1074
+ var CONNECT_PLACEHOLDER_EDGE = "connect-placeholder-edge";
1075
+ var CONNECT_PLACEHOLDER_SIZE = { width: 200, height: 66 };
1076
+ var notPlaceholder = (change) => change.type === "add" || change.id !== CONNECT_PLACEHOLDER;
1077
+ var linkConnection = (newId, link) => link.newIs === "target" ? {
1078
+ source: link.nodeId,
1079
+ sourceHandle: link.handleId,
1080
+ target: newId,
1081
+ targetHandle: null
1082
+ } : {
1083
+ source: newId,
1084
+ sourceHandle: null,
1085
+ target: link.nodeId,
1086
+ targetHandle: link.handleId
1087
+ };
1088
+ var DOMAIN_CARD = "context-domain";
1089
+ var SYSTEM_CARD = "system";
1090
+ var connectedType = (type) => type === GROUP_TYPES.domain ? DOMAIN_CARD : type === GROUP_TYPES.system ? SYSTEM_CARD : type;
1091
+ var isCardType = (type) => type === DOMAIN_CARD || type === SYSTEM_CARD;
1092
+ var newCardData = (type) => ({
1093
+ mode: "full",
1094
+ navigable: false,
1095
+ ...getNodeDefinition(
1096
+ type === DOMAIN_CARD ? GROUP_TYPES.domain : GROUP_TYPES.system
1097
+ ).createData()
1098
+ });
1099
+ var categoryOrder = new Map(
1100
+ NODE_CATEGORIES.map((category, index) => [category.id, index])
1101
+ );
1102
+ var getConnectOptions = (fromType, newIs, level) => nodeDefinitions.filter(
1103
+ (definition) => !definition.unlisted && !isWrittenOnCanvas(definition.type) && isShownOnLevel(definition.type, level)
1104
+ ).map((definition) => {
1105
+ const type = connectedType(definition.type);
1106
+ const says = newIs === "target" ? getEdgeLabel(fromType, type) : getEdgeLabel(type, fromType);
1107
+ return {
1108
+ key: componentKey(definition),
1109
+ type,
1110
+ label: definition.label,
1111
+ summary: definition.summary,
1112
+ category: definition.category,
1113
+ says: says.replace(/\s+/g, " ").trim()
1114
+ };
1115
+ }).sort(
1116
+ (a, b) => Number(!a.says) - Number(!b.says) || (categoryOrder.get(a.category) ?? 0) - (categoryOrder.get(b.category) ?? 0)
1117
+ );
1118
+ var filterConnectOptions = (options, query) => {
1119
+ const words = query.toLowerCase().split(/\s+/).filter(Boolean);
1120
+ if (!words.length) return options;
1121
+ return options.filter((option) => {
1122
+ const text = `${option.label} ${option.summary ?? ""} ${option.says}`.toLowerCase();
1123
+ return words.every((word) => text.includes(word));
1124
+ });
1125
+ };
1126
+ var CONNECT_MIN_DISTANCE = 40;
1127
+ var isAwayFrom = (from, to) => Math.hypot(to.x - from.x, to.y - from.y) >= CONNECT_MIN_DISTANCE;
1128
+ var isEmptyCanvasAt = (point, canvas) => {
1129
+ const under = document.elementFromPoint(point.x, point.y);
1130
+ return !!under?.closest(".react-flow__pane") && !under.closest(".react-flow__node") && !!canvas?.contains(under);
1131
+ };
1132
+ var centreBeyond = (from, to, size) => {
1133
+ const dx = to.x - from.x;
1134
+ const dy = to.y - from.y;
1135
+ if (Math.abs(dx) >= Math.abs(dy))
1136
+ return { x: to.x + Math.sign(dx || 1) * (size.width / 2), y: to.y };
1137
+ return { x: to.x, y: to.y + Math.sign(dy) * (size.height / 2) };
1138
+ };
1139
+
1140
+ // src/studio/use-connect-new.ts
1141
+ import {
1142
+ useCallback,
1143
+ useEffect,
1144
+ useMemo,
1145
+ useRef,
1146
+ useState
1147
+ } from "react";
1148
+ import {
1149
+ useReactFlow
1150
+ } from "@xyflow/react";
1151
+ var PLACEHOLDER_EDGE_STYLE = {
1152
+ stroke: "rgb(var(--ec-accent))",
1153
+ strokeWidth: 1.5,
1154
+ strokeDasharray: "6 4"
1155
+ };
1156
+ var placeholderPosition = ({ from, to }) => {
1157
+ const center = centreBeyond(from, to, CONNECT_PLACEHOLDER_SIZE);
1158
+ return {
1159
+ x: center.x - CONNECT_PLACEHOLDER_SIZE.width / 2,
1160
+ y: center.y - CONNECT_PLACEHOLDER_SIZE.height / 2
1161
+ };
1162
+ };
1163
+ function useConnectNew({
1164
+ canvasRef,
1165
+ getNode,
1166
+ getLevel,
1167
+ locked,
1168
+ onMake
1169
+ }) {
1170
+ const { screenToFlowPosition, flowToScreenPosition } = useReactFlow();
1171
+ const [connecting, setConnecting] = useState(null);
1172
+ const latest = useRef({ getNode, getLevel, locked, onMake, connecting });
1173
+ latest.current = { getNode, getLevel, locked, onMake, connecting };
1174
+ const reconnecting = useRef(false);
1175
+ const onReconnectStart = useCallback(() => {
1176
+ reconnecting.current = true;
1177
+ }, []);
1178
+ const onReconnectEnd = useCallback(() => {
1179
+ reconnecting.current = false;
1180
+ }, []);
1181
+ const onConnectEnd = useCallback(
1182
+ (event, state) => {
1183
+ const { fromNode, fromHandle } = state;
1184
+ if (latest.current.locked || reconnecting.current || state.isValid || state.toNode || !fromNode || !fromHandle)
1185
+ return;
1186
+ const from = latest.current.getNode(fromNode.id);
1187
+ if (!from) return;
1188
+ const { clientX, clientY } = "changedTouches" in event ? event.changedTouches[0] : event;
1189
+ const to = screenToFlowPosition({ x: clientX, y: clientY });
1190
+ if (!isAwayFrom(state.from, to) || !isEmptyCanvasAt({ x: clientX, y: clientY }, canvasRef.current))
1191
+ return;
1192
+ const newIs = fromHandle.type === "source" ? "target" : "source";
1193
+ const options = getConnectOptions(
1194
+ from.type,
1195
+ newIs,
1196
+ latest.current.getLevel()
1197
+ );
1198
+ if (!options.length) return;
1199
+ setConnecting({
1200
+ link: { nodeId: from.id, handleId: fromHandle.id ?? null, newIs },
1201
+ fromName: getNodeName(from.type, from.data),
1202
+ options,
1203
+ from: state.from,
1204
+ to
1205
+ });
1206
+ },
1207
+ [screenToFlowPosition, canvasRef]
1208
+ );
1209
+ const placeholder = useMemo(() => {
1210
+ if (!connecting) return null;
1211
+ const { choice } = connecting;
1212
+ const data = {
1213
+ choice: choice && {
1214
+ key: choice.key,
1215
+ label: choice.label,
1216
+ summary: choice.summary
1217
+ }
1218
+ };
1219
+ const node = {
1220
+ id: CONNECT_PLACEHOLDER,
1221
+ type: CONNECT_PLACEHOLDER,
1222
+ position: placeholderPosition(connecting),
1223
+ data,
1224
+ draggable: false,
1225
+ selectable: false,
1226
+ connectable: false,
1227
+ focusable: false,
1228
+ deletable: false,
1229
+ zIndex: 1e3
1230
+ };
1231
+ const edge = {
1232
+ id: CONNECT_PLACEHOLDER_EDGE,
1233
+ ...linkConnection(CONNECT_PLACEHOLDER, connecting.link),
1234
+ type: "smoothstep",
1235
+ style: PLACEHOLDER_EDGE_STYLE,
1236
+ selectable: false,
1237
+ focusable: false,
1238
+ deletable: false
1239
+ };
1240
+ return { node, edge };
1241
+ }, [connecting]);
1242
+ const highlight = useCallback(
1243
+ (choice) => setConnecting(
1244
+ (current) => current && current.choice?.key !== choice?.key ? { ...current, choice } : current
1245
+ ),
1246
+ []
1247
+ );
1248
+ const cancel = useCallback(() => setConnecting(null), []);
1249
+ const choose = useCallback((option) => {
1250
+ const { connecting: at, locked: isLocked, onMake: make } = latest.current;
1251
+ setConnecting(null);
1252
+ if (!at || isLocked) return;
1253
+ make(
1254
+ option,
1255
+ centreBeyond(at.from, at.to, getNodeSize2(option.type)),
1256
+ at.link
1257
+ );
1258
+ }, []);
1259
+ useEffect(() => {
1260
+ if (locked) setConnecting(null);
1261
+ }, [locked]);
1262
+ let chooser = null;
1263
+ if (connecting && placeholder) {
1264
+ const { x, y } = placeholder.node.position;
1265
+ const start = flowToScreenPosition({ x, y });
1266
+ const end = flowToScreenPosition({
1267
+ x: x + CONNECT_PLACEHOLDER_SIZE.width,
1268
+ y: y + CONNECT_PLACEHOLDER_SIZE.height
1269
+ });
1270
+ chooser = {
1271
+ options: connecting.options,
1272
+ fromName: connecting.fromName,
1273
+ anchor: {
1274
+ x: start.x,
1275
+ y: start.y,
1276
+ width: end.x - start.x,
1277
+ height: end.y - start.y
1278
+ },
1279
+ onHighlight: highlight,
1280
+ onChoose: choose,
1281
+ onCancel: cancel
1282
+ };
1283
+ }
1284
+ return {
1285
+ placeholder,
1286
+ chooser,
1287
+ onConnectEnd,
1288
+ onReconnectStart,
1289
+ onReconnectEnd,
1290
+ cancel
1291
+ };
1292
+ }
1293
+
1353
1294
  // src/studio/entity-handles.ts
1354
1295
  var ENTITY_SOURCE_HANDLE = "__entity-source";
1355
1296
 
@@ -2081,7 +2022,7 @@ var getLevelUnavailableReason = (nodes, level) => {
2081
2022
  };
2082
2023
 
2083
2024
  // src/studio/live-moves.ts
2084
- import { useEffect, useState } from "react";
2025
+ import { useEffect as useEffect2, useState as useState2 } from "react";
2085
2026
 
2086
2027
  // src/studio/smooth.ts
2087
2028
  var EASE_MS = 45;
@@ -2157,10 +2098,10 @@ var sendMove = (live, kind, id, at) => live?.send(
2157
2098
  );
2158
2099
  var NONE = /* @__PURE__ */ new Map();
2159
2100
  function useRemoteMoves(live, kind) {
2160
- const [moves, setMoves] = useState(NONE);
2101
+ const [moves, setMoves] = useState2(NONE);
2161
2102
  const source = live?.source;
2162
2103
  const level = live?.level;
2163
- useEffect(() => {
2104
+ useEffect2(() => {
2164
2105
  if (!source) return;
2165
2106
  let shown = "";
2166
2107
  const glide = createSmoother((at) => setMoves(at.size ? at : NONE));
@@ -2222,9 +2163,9 @@ var NODE_TYPE = {
2222
2163
  };
2223
2164
  var RESOURCE_TYPE = {
2224
2165
  ...Object.fromEntries(
2225
- Object.entries(NODE_TYPE).map(([resource2, node]) => [
2166
+ Object.entries(NODE_TYPE).map(([resource, node]) => [
2226
2167
  node,
2227
- resource2
2168
+ resource
2228
2169
  ])
2229
2170
  ),
2230
2171
  // Catalog domains and systems as cards (Studio's catalog adds them; kept if a canvas has them)
@@ -2247,42 +2188,42 @@ var toCanvasHotspots = (hotspots) => hotspots.map((hotspot) => ({
2247
2188
  author: hotspot.author ?? AGENT_AUTHOR,
2248
2189
  createdAt: hotspot.createdAt ?? Date.now()
2249
2190
  }));
2250
- function resourceNodeData(resource2) {
2251
- const type = NODE_TYPE[resource2.type];
2191
+ function resourceNodeData(resource) {
2192
+ const type = NODE_TYPE[resource.type];
2252
2193
  const fields = {
2253
- name: resource2.name,
2254
- version: resource2.version ?? "0.0.1",
2255
- summary: resource2.summary ?? "",
2256
- owners: resource2.owners ?? []
2194
+ name: resource.name,
2195
+ version: resource.version ?? "0.0.1",
2196
+ summary: resource.summary ?? "",
2197
+ owners: resource.owners ?? []
2257
2198
  };
2258
2199
  const defaults = getNodeDefinition(type)?.createData() ?? {};
2259
- const shared = { resource: resource2 };
2260
- switch (resource2.type) {
2200
+ const shared = { resource };
2201
+ switch (resource.type) {
2261
2202
  case "domain":
2262
- return resource2.card ? {
2203
+ return resource.card ? {
2263
2204
  ...shared,
2264
2205
  mode: "full",
2265
2206
  navigable: false,
2266
- domain: { id: resource2.id, ...fields }
2207
+ domain: { id: resource.id, ...fields }
2267
2208
  } : {
2268
2209
  ...shared,
2269
2210
  domain: {
2270
- id: resource2.id,
2271
- name: resource2.name,
2211
+ id: resource.id,
2212
+ name: resource.name,
2272
2213
  version: fields.version
2273
2214
  }
2274
2215
  };
2275
2216
  case "system":
2276
- return resource2.card ? {
2217
+ return resource.card ? {
2277
2218
  ...shared,
2278
2219
  mode: "full",
2279
2220
  navigable: false,
2280
- system: { id: resource2.id, ...fields }
2221
+ system: { id: resource.id, ...fields }
2281
2222
  } : {
2282
2223
  ...shared,
2283
2224
  system: {
2284
- id: resource2.id,
2285
- name: resource2.name,
2225
+ id: resource.id,
2226
+ name: resource.name,
2286
2227
  version: fields.version
2287
2228
  }
2288
2229
  };
@@ -2290,8 +2231,8 @@ function resourceNodeData(resource2) {
2290
2231
  return {
2291
2232
  ...defaults,
2292
2233
  ...shared,
2293
- name: resource2.name,
2294
- summary: resource2.summary ?? ""
2234
+ name: resource.name,
2235
+ summary: resource.summary ?? ""
2295
2236
  };
2296
2237
  case "channel":
2297
2238
  return {
@@ -2299,7 +2240,7 @@ function resourceNodeData(resource2) {
2299
2240
  ...shared,
2300
2241
  channel: {
2301
2242
  ...fields,
2302
- protocols: resource2.technology ? [resource2.technology] : []
2243
+ protocols: resource.technology ? [resource.technology] : []
2303
2244
  }
2304
2245
  };
2305
2246
  case "container":
@@ -2308,15 +2249,15 @@ function resourceNodeData(resource2) {
2308
2249
  ...shared,
2309
2250
  data: {
2310
2251
  ...fields,
2311
- container_type: resource2.containerType ?? "database",
2312
- technology: resource2.technology
2252
+ container_type: resource.containerType ?? "database",
2253
+ technology: resource.technology
2313
2254
  }
2314
2255
  };
2315
2256
  case "entity":
2316
2257
  return {
2317
2258
  ...defaults,
2318
2259
  ...shared,
2319
- entity: { ...fields, properties: resource2.properties ?? [] }
2260
+ entity: { ...fields, properties: resource.properties ?? [] }
2320
2261
  };
2321
2262
  default: {
2322
2263
  const key = getNodeDefinition(type)?.resourceKey ?? type;
@@ -2400,22 +2341,22 @@ var placeOf2 = (place) => ({
2400
2341
  x: place.x,
2401
2342
  y: place.y
2402
2343
  });
2403
- var nodeTypeOf = (resource2) => resource2.card && resource2.type === "domain" ? "context-domain" : resource2.card && resource2.type === "system" ? "system" : NODE_TYPE[resource2.type];
2404
- var isCardType = (type) => type === "context-domain" || type === "system";
2344
+ var nodeTypeOf = (resource) => resource.card && resource.type === "domain" ? "context-domain" : resource.card && resource.type === "system" ? "system" : NODE_TYPE[resource.type];
2345
+ var isCardType2 = (type) => type === "context-domain" || type === "system";
2405
2346
  async function modelToCanvas(model, seed) {
2406
2347
  const byId2 = new Map(model.resources.map((r) => [r.id, r]));
2407
2348
  const saved = model.layout?.messages ?? {};
2408
2349
  let nodes = sortByHierarchy(
2409
- model.resources.map((resource2) => {
2410
- const parent = resource2.parent ? byId2.get(resource2.parent) : void 0;
2411
- const place = saved[resource2.id];
2412
- const group = !resource2.card && (resource2.type === "domain" || resource2.type === "system");
2413
- const size = group ? place?.width && place.height ? { width: place.width, height: place.height } : getNodeDefinition(NODE_TYPE[resource2.type])?.defaultSize : void 0;
2350
+ model.resources.map((resource) => {
2351
+ const parent = resource.parent ? byId2.get(resource.parent) : void 0;
2352
+ const place = saved[resource.id];
2353
+ const group = !resource.card && (resource.type === "domain" || resource.type === "system");
2354
+ const size = group ? place?.width && place.height ? { width: place.width, height: place.height } : getNodeDefinition(NODE_TYPE[resource.type])?.defaultSize : void 0;
2414
2355
  return {
2415
- id: resource2.id,
2416
- type: nodeTypeOf(resource2),
2356
+ id: resource.id,
2357
+ type: nodeTypeOf(resource),
2417
2358
  position: place ? placeOf2(place) : { x: 0, y: 0 },
2418
- data: resourceNodeData(resource2),
2359
+ data: resourceNodeData(resource),
2419
2360
  ...size && { width: size.width, height: size.height },
2420
2361
  ...parent && !parent.card && (parent.type === "domain" || parent.type === "system") && {
2421
2362
  parentId: parent.id
@@ -2641,7 +2582,7 @@ function canvasToModel(nodes, edges, levelLayouts, base, threads = [], hotspots
2641
2582
  ...type === "container" && {
2642
2583
  containerType: fields.container_type && fields.container_type !== "database" ? fields.container_type : void 0
2643
2584
  },
2644
- ...isCardType(node.type) && { card: true },
2585
+ ...isCardType2(node.type) && { card: true },
2645
2586
  ...parent && resourceTypeOf(parent.type) && { parent: parent.id }
2646
2587
  };
2647
2588
  });
@@ -2692,12 +2633,12 @@ function canvasToModel(nodes, edges, levelLayouts, base, threads = [], hotspots
2692
2633
  const notes = nodes.filter((node) => isWrittenOnCanvas(node.type)).map((node) => {
2693
2634
  const at = getAbsolutePosition(node, lookup);
2694
2635
  const level = node.data.level ?? void 0;
2695
- const resource2 = typeof node.data.resource === "string" && byId2.has(node.data.resource) ? node.data.resource : void 0;
2636
+ const resource = typeof node.data.resource === "string" && byId2.has(node.data.resource) ? node.data.resource : void 0;
2696
2637
  return {
2697
2638
  text: String(node.data.text ?? "").slice(0, 1e3),
2698
2639
  ...node.type === "text" && { kind: "text" },
2699
2640
  ...node.type === "note" && node.data.color ? { color: node.data.color } : {},
2700
- ...resource2 && { resource: resource2 },
2641
+ ...resource && { resource },
2701
2642
  ...typeof node.data.author === "string" && {
2702
2643
  author: node.data.author
2703
2644
  },
@@ -2728,16 +2669,16 @@ function canvasToModel(nodes, edges, levelLayouts, base, threads = [], hotspots
2728
2669
  team.name
2729
2670
  ]);
2730
2671
  }
2731
- for (const resource2 of resources) {
2732
- if (resource2.type === "team") continue;
2672
+ for (const resource of resources) {
2673
+ if (resource.type === "team") continue;
2733
2674
  const owners = [
2734
2675
  .../* @__PURE__ */ new Set([
2735
- ...(resource2.owners ?? []).filter((owner) => !teamNames.has(owner)),
2736
- ...ownedBy.get(resource2.id) ?? []
2676
+ ...(resource.owners ?? []).filter((owner) => !teamNames.has(owner)),
2677
+ ...ownedBy.get(resource.id) ?? []
2737
2678
  ])
2738
2679
  ];
2739
- if (owners.length) resource2.owners = owners;
2740
- else delete resource2.owners;
2680
+ if (owners.length) resource.owners = owners;
2681
+ else delete resource.owners;
2741
2682
  }
2742
2683
  }
2743
2684
  const ids = new Set(resources.map((r) => r.id));
@@ -2937,21 +2878,21 @@ async function canvasImage(container) {
2937
2878
  // src/studio/components/canvas-nodes.tsx
2938
2879
  import {
2939
2880
  createContext,
2940
- memo as memo2,
2941
- useCallback,
2881
+ memo as memo3,
2882
+ useCallback as useCallback2,
2942
2883
  useContext,
2943
- useEffect as useEffect2,
2944
- useMemo,
2945
- useRef,
2946
- useState as useState2
2884
+ useEffect as useEffect4,
2885
+ useMemo as useMemo3,
2886
+ useRef as useRef3,
2887
+ useState as useState4
2947
2888
  } from "react";
2948
2889
  import {
2949
- Handle as Handle2,
2890
+ Handle as Handle3,
2950
2891
  NodeResizeControl,
2951
2892
  NodeResizer,
2952
- Position as Position2,
2893
+ Position as Position3,
2953
2894
  ResizeControlVariant,
2954
- useReactFlow,
2895
+ useReactFlow as useReactFlow2,
2955
2896
  useStoreApi as useStoreApi2,
2956
2897
  useUpdateNodeInternals
2957
2898
  } from "@xyflow/react";
@@ -3006,8 +2947,232 @@ var TeamNode = memo(function TeamNode2({ data, selected }) {
3006
2947
  });
3007
2948
  var TeamNode_default = TeamNode;
3008
2949
 
2950
+ // src/studio/components/ConnectChooser.tsx
2951
+ import {
2952
+ Fragment,
2953
+ memo as memo2,
2954
+ useEffect as useEffect3,
2955
+ useMemo as useMemo2,
2956
+ useRef as useRef2,
2957
+ useState as useState3
2958
+ } from "react";
2959
+ import { Handle as Handle2, Position as Position2 } from "@xyflow/react";
2960
+ import { Plus, X } from "lucide-react";
2961
+ import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
2962
+ var HIDDEN_HANDLE = {
2963
+ opacity: 0,
2964
+ pointerEvents: "none"
2965
+ };
2966
+ var PLACEHOLDER_CLASS = "relative rounded-xl border-2 border-dashed border-current bg-[rgb(var(--ec-card-bg))] px-3 pt-3.5 pb-2.5 opacity-50";
2967
+ var DEFAULT_COLOUR = "text-[rgb(var(--ec-accent))]";
2968
+ function PlaceholderContent({ choice }) {
2969
+ const icon = choice ? NODE_ICONS[choice.key] : void 0;
2970
+ const Icon = icon?.icon ?? Plus;
2971
+ return /* @__PURE__ */ jsxs2(Fragment2, { children: [
2972
+ /* @__PURE__ */ jsx2("span", { className: "absolute -top-2.5 left-2.5 rounded bg-current px-1.5 py-0.5 shadow-sm", children: /* @__PURE__ */ jsxs2("span", { className: "flex items-center gap-1 text-[7px] font-bold uppercase tracking-widest text-white", children: [
2973
+ /* @__PURE__ */ jsx2(Icon, { className: "h-2.5 w-2.5", strokeWidth: 2.5 }),
2974
+ choice?.label ?? "New"
2975
+ ] }) }),
2976
+ /* @__PURE__ */ jsx2("div", { className: "truncate text-[13px] font-semibold leading-snug text-[rgb(var(--ec-page-text))]", children: choice ? `New ${choice.label}` : "New node" }),
2977
+ /* @__PURE__ */ jsx2("div", { className: "mt-1.5 truncate text-[9px] leading-relaxed text-[rgb(var(--ec-page-text-muted))]", children: choice ? choice.summary : "Choose what it is from the list" })
2978
+ ] });
2979
+ }
2980
+ var ConnectPlaceholderNode = memo2(function ConnectPlaceholderNode2({
2981
+ data
2982
+ }) {
2983
+ const { choice } = data;
2984
+ const colour = choice && NODE_ICONS[choice.key]?.className || DEFAULT_COLOUR;
2985
+ return /* @__PURE__ */ jsxs2(
2986
+ "div",
2987
+ {
2988
+ className: `${PLACEHOLDER_CLASS} ${colour}`,
2989
+ style: CONNECT_PLACEHOLDER_SIZE,
2990
+ children: [
2991
+ /* @__PURE__ */ jsx2(
2992
+ Handle2,
2993
+ {
2994
+ type: "target",
2995
+ position: Position2.Left,
2996
+ isConnectable: false,
2997
+ style: HIDDEN_HANDLE
2998
+ }
2999
+ ),
3000
+ /* @__PURE__ */ jsx2(PlaceholderContent, { choice }),
3001
+ /* @__PURE__ */ jsx2(
3002
+ Handle2,
3003
+ {
3004
+ type: "source",
3005
+ position: Position2.Right,
3006
+ isConnectable: false,
3007
+ style: HIDDEN_HANDLE
3008
+ }
3009
+ )
3010
+ ]
3011
+ }
3012
+ );
3013
+ });
3014
+ var LIST_WIDTH = 288;
3015
+ var LIST_HEIGHT = 360;
3016
+ function ConnectChooser({
3017
+ options,
3018
+ fromName,
3019
+ anchor,
3020
+ onHighlight,
3021
+ onChoose,
3022
+ onCancel
3023
+ }) {
3024
+ const [query, setQuery] = useState3("");
3025
+ const [index, setIndex] = useState3(0);
3026
+ const [picking, setPicking] = useState3(false);
3027
+ const shown = useMemo2(
3028
+ () => filterConnectOptions(options, query),
3029
+ [options, query]
3030
+ );
3031
+ const highlighted = shown[Math.min(index, shown.length - 1)];
3032
+ const listRef = useRef2(null);
3033
+ useEffect3(() => setIndex(0), [query]);
3034
+ useEffect3(
3035
+ () => onHighlight(picking ? highlighted : void 0),
3036
+ [picking, highlighted?.key]
3037
+ );
3038
+ useEffect3(() => {
3039
+ if (!highlighted) return;
3040
+ listRef.current?.querySelector(`[data-key="${CSS.escape(highlighted.key)}"]`)?.scrollIntoView({ block: "nearest" });
3041
+ }, [highlighted?.key]);
3042
+ const onKeyDown = (event) => {
3043
+ if (event.key === "Escape") {
3044
+ event.preventDefault();
3045
+ event.stopPropagation();
3046
+ return onCancel();
3047
+ }
3048
+ if (event.key === "ArrowDown" || event.key === "ArrowUp") {
3049
+ event.preventDefault();
3050
+ setPicking(true);
3051
+ if (!shown.length) return;
3052
+ const step = event.key === "ArrowDown" ? 1 : -1;
3053
+ setIndex(
3054
+ (current) => (Math.min(current, shown.length - 1) + step + shown.length) % shown.length
3055
+ );
3056
+ }
3057
+ if (event.key === "Enter" && highlighted) {
3058
+ event.preventDefault();
3059
+ onChoose(highlighted);
3060
+ }
3061
+ };
3062
+ const left = Math.min(
3063
+ Math.max(anchor.x, 12),
3064
+ window.innerWidth - LIST_WIDTH - 12
3065
+ );
3066
+ const below2 = anchor.y + anchor.height + 8;
3067
+ const top = below2 + LIST_HEIGHT > window.innerHeight - 12 ? Math.max(anchor.y - LIST_HEIGHT - 8, 12) : below2;
3068
+ const suggested = shown.filter((option) => option.says);
3069
+ const others = shown.filter((option) => !option.says);
3070
+ const row = (option) => {
3071
+ const { icon: Icon, className } = NODE_ICONS[option.key] ?? NODE_ICONS[option.type] ?? { icon: Plus, className: "" };
3072
+ const active = option.key === highlighted?.key;
3073
+ return /* @__PURE__ */ jsxs2(
3074
+ "button",
3075
+ {
3076
+ type: "button",
3077
+ role: "option",
3078
+ tabIndex: -1,
3079
+ onMouseDown: (event) => event.preventDefault(),
3080
+ "aria-selected": active,
3081
+ "data-key": option.key,
3082
+ onPointerMove: () => {
3083
+ setPicking(true);
3084
+ if (!active) setIndex(shown.indexOf(option));
3085
+ },
3086
+ onClick: () => onChoose(option),
3087
+ className: `flex w-full items-center gap-2.5 rounded-md px-2 py-1.5 text-left ${active ? "bg-[rgb(var(--ec-accent)/0.1)]" : ""}`,
3088
+ children: [
3089
+ /* @__PURE__ */ jsx2("span", { className: "flex h-7 w-7 flex-none items-center justify-center rounded-md bg-[rgb(var(--ec-content-hover))]", children: /* @__PURE__ */ jsx2(Icon, { size: 15, className }) }),
3090
+ /* @__PURE__ */ jsxs2("span", { className: "min-w-0 flex-1", children: [
3091
+ /* @__PURE__ */ jsx2("span", { className: "block truncate text-[13px] font-medium leading-tight", children: option.label }),
3092
+ /* @__PURE__ */ jsx2("span", { className: "block truncate text-[11px] leading-snug text-[rgb(var(--ec-page-text-muted))]", children: option.says || option.summary })
3093
+ ] })
3094
+ ]
3095
+ },
3096
+ option.key
3097
+ );
3098
+ };
3099
+ const section = (title, list) => list.length > 0 && /* @__PURE__ */ jsxs2(Fragment, { children: [
3100
+ /* @__PURE__ */ jsx2(
3101
+ "p",
3102
+ {
3103
+ role: "presentation",
3104
+ className: "px-2 pb-1 pt-2 text-[10px] font-semibold uppercase tracking-wider text-[rgb(var(--ec-page-text-muted))]",
3105
+ children: title
3106
+ }
3107
+ ),
3108
+ list.map(row)
3109
+ ] }, title);
3110
+ return /* @__PURE__ */ jsx2("div", { className: "fixed inset-0 z-50", onPointerDown: onCancel, children: /* @__PURE__ */ jsxs2(
3111
+ "div",
3112
+ {
3113
+ role: "dialog",
3114
+ "aria-label": "Connect to something new",
3115
+ onPointerDown: (event) => event.stopPropagation(),
3116
+ className: "absolute flex flex-col rounded-lg border shadow-xl bg-[rgb(var(--ec-card-bg))] border-[rgb(var(--ec-page-border))] text-[rgb(var(--ec-page-text))]",
3117
+ style: { left, top, width: LIST_WIDTH, maxHeight: LIST_HEIGHT },
3118
+ children: [
3119
+ /* @__PURE__ */ jsxs2("div", { className: "flex flex-none items-center gap-1 border-b border-[rgb(var(--ec-page-border))] p-1.5", children: [
3120
+ /* @__PURE__ */ jsx2(
3121
+ "input",
3122
+ {
3123
+ autoFocus: true,
3124
+ value: query,
3125
+ onChange: (event) => {
3126
+ setPicking(true);
3127
+ setQuery(event.target.value);
3128
+ },
3129
+ onKeyDown,
3130
+ placeholder: fromName ? `Connect ${fromName} to\u2026` : "Connect to\u2026",
3131
+ "aria-label": "What to connect to",
3132
+ role: "combobox",
3133
+ "aria-expanded": true,
3134
+ "aria-controls": "studio-connect-options",
3135
+ className: "min-w-0 flex-1 rounded-md bg-transparent px-2 py-1 text-[13px] outline-none placeholder:text-[rgb(var(--ec-page-text-muted))]"
3136
+ }
3137
+ ),
3138
+ /* @__PURE__ */ jsx2(
3139
+ "button",
3140
+ {
3141
+ type: "button",
3142
+ onClick: onCancel,
3143
+ "aria-label": "Cancel",
3144
+ className: "rounded p-1 text-[rgb(var(--ec-icon-color))] hover:bg-[rgb(var(--ec-page-border)/0.5)]",
3145
+ children: /* @__PURE__ */ jsx2(X, { size: 14 })
3146
+ }
3147
+ )
3148
+ ] }),
3149
+ /* @__PURE__ */ jsx2(
3150
+ "div",
3151
+ {
3152
+ ref: listRef,
3153
+ id: "studio-connect-options",
3154
+ role: "listbox",
3155
+ className: "min-h-0 flex-1 overflow-y-auto p-1",
3156
+ children: shown.length ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
3157
+ section("Suggested", suggested),
3158
+ section(
3159
+ suggested.length ? "Everything else" : "Components",
3160
+ others
3161
+ )
3162
+ ] }) : /* @__PURE__ */ jsxs2("p", { className: "px-2 py-3 text-center text-xs text-[rgb(var(--ec-page-text-muted))]", children: [
3163
+ "Nothing called \u201C",
3164
+ query,
3165
+ "\u201D"
3166
+ ] })
3167
+ }
3168
+ )
3169
+ ]
3170
+ }
3171
+ ) });
3172
+ }
3173
+
3009
3174
  // src/studio/components/canvas-nodes.tsx
3010
- import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
3175
+ import { Fragment as Fragment3, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
3011
3176
  var UpdateNodeDataContext = createContext(() => {
3012
3177
  });
3013
3178
  var EditingContext = createContext(
@@ -3019,8 +3184,8 @@ var StartWritingContext = createContext(null);
3019
3184
  var LockedContext = createContext(false);
3020
3185
  var SystemGroupComponent = SystemGroupNode_default;
3021
3186
  function WidthHandles() {
3022
- return /* @__PURE__ */ jsxs2(Fragment, { children: [
3023
- /* @__PURE__ */ jsx2(
3187
+ return /* @__PURE__ */ jsxs3(Fragment3, { children: [
3188
+ /* @__PURE__ */ jsx3(
3024
3189
  NodeResizeControl,
3025
3190
  {
3026
3191
  position: "left",
@@ -3030,7 +3195,7 @@ function WidthHandles() {
3030
3195
  className: "studio-width-handle"
3031
3196
  }
3032
3197
  ),
3033
- /* @__PURE__ */ jsx2(
3198
+ /* @__PURE__ */ jsx3(
3034
3199
  NodeResizeControl,
3035
3200
  {
3036
3201
  position: "right",
@@ -3054,8 +3219,8 @@ function Writing({
3054
3219
  }) {
3055
3220
  const updateNodeData2 = useContext(UpdateNodeDataContext);
3056
3221
  const liveEdit = useContext(EditingContext);
3057
- const areaRef = useRef(null);
3058
- useEffect2(() => {
3222
+ const areaRef = useRef3(null);
3223
+ useEffect4(() => {
3059
3224
  if (!editing) return;
3060
3225
  let frame = 0;
3061
3226
  let tries = 0;
@@ -3078,8 +3243,8 @@ function Writing({
3078
3243
  area.style.height = `${area.scrollHeight}px`;
3079
3244
  };
3080
3245
  if (!editing)
3081
- return /* @__PURE__ */ jsx2("p", { className, style, children: text || placeholder && /* @__PURE__ */ jsx2("span", { className: "opacity-50", children: placeholder }) });
3082
- return /* @__PURE__ */ jsx2(
3246
+ return /* @__PURE__ */ jsx3("p", { className, style, children: text || placeholder && /* @__PURE__ */ jsx3("span", { className: "opacity-50", children: placeholder }) });
3247
+ return /* @__PURE__ */ jsx3(
3083
3248
  "textarea",
3084
3249
  {
3085
3250
  ref: (area) => {
@@ -3118,30 +3283,30 @@ var NOTE_COLORS = {
3118
3283
  purple: { fill: "#ede9fe", border: "#c4b5fd" },
3119
3284
  gray: { fill: "#f3f4f6", border: "#d1d5db" }
3120
3285
  };
3121
- var StickyNote = memo2(function StickyNote2({ id, data, selected }) {
3286
+ var StickyNote = memo3(function StickyNote2({ id, data, selected }) {
3122
3287
  const updateNodeData2 = useContext(UpdateNodeDataContext);
3123
- const [editing, setEditing] = useState2(
3288
+ const [editing, setEditing] = useState4(
3124
3289
  useContext(StartWritingContext) === id
3125
3290
  );
3126
3291
  const locked = useContext(LockedContext);
3127
3292
  const colorName = typeof data.color === "string" && NOTE_COLORS[data.color] ? data.color : "yellow";
3128
3293
  const color = NOTE_COLORS[colorName];
3129
- return /* @__PURE__ */ jsxs2(
3294
+ return /* @__PURE__ */ jsxs3(
3130
3295
  "div",
3131
3296
  {
3132
3297
  className: "studio-note",
3133
3298
  style: { background: color.fill, borderColor: color.border },
3134
3299
  onDoubleClick: () => !locked && setEditing(true),
3135
3300
  children: [
3136
- selected && !editing && !locked && /* @__PURE__ */ jsxs2(Fragment, { children: [
3137
- /* @__PURE__ */ jsx2(WidthHandles, {}),
3138
- /* @__PURE__ */ jsx2(
3301
+ selected && !editing && !locked && /* @__PURE__ */ jsxs3(Fragment3, { children: [
3302
+ /* @__PURE__ */ jsx3(WidthHandles, {}),
3303
+ /* @__PURE__ */ jsx3(
3139
3304
  "div",
3140
3305
  {
3141
3306
  className: "nodrag nopan studio-note-colors",
3142
3307
  role: "radiogroup",
3143
3308
  "aria-label": "Note colour",
3144
- children: Object.entries(NOTE_COLORS).map(([name, { fill, border }]) => /* @__PURE__ */ jsx2(
3309
+ children: Object.entries(NOTE_COLORS).map(([name, { fill, border }]) => /* @__PURE__ */ jsx3(
3145
3310
  "button",
3146
3311
  {
3147
3312
  role: "radio",
@@ -3159,7 +3324,7 @@ var StickyNote = memo2(function StickyNote2({ id, data, selected }) {
3159
3324
  }
3160
3325
  )
3161
3326
  ] }),
3162
- /* @__PURE__ */ jsx2(
3327
+ /* @__PURE__ */ jsx3(
3163
3328
  Writing,
3164
3329
  {
3165
3330
  id,
@@ -3170,12 +3335,12 @@ var StickyNote = memo2(function StickyNote2({ id, data, selected }) {
3170
3335
  className: "studio-note-body"
3171
3336
  }
3172
3337
  ),
3173
- /* @__PURE__ */ jsxs2("span", { className: "studio-note-level", children: [
3338
+ /* @__PURE__ */ jsxs3("span", { className: "studio-note-level", children: [
3174
3339
  "L",
3175
3340
  getNoteLevel({ type: "note", data }),
3176
3341
  " note"
3177
3342
  ] }),
3178
- typeof data.createdAt === "number" && /* @__PURE__ */ jsx2("span", { className: "studio-note-date", children: new Date(data.createdAt).toLocaleDateString(void 0, {
3343
+ typeof data.createdAt === "number" && /* @__PURE__ */ jsx3("span", { className: "studio-note-date", children: new Date(data.createdAt).toLocaleDateString(void 0, {
3179
3344
  day: "numeric",
3180
3345
  month: "short"
3181
3346
  }) })
@@ -3203,18 +3368,18 @@ var followPointer = (onMove, onEnd) => {
3203
3368
  window.addEventListener("pointerup", end);
3204
3369
  window.addEventListener("pointercancel", end);
3205
3370
  };
3206
- var TextNode = memo2(function TextNode2({ id, data, selected }) {
3207
- const [editing, setEditing] = useState2(
3371
+ var TextNode = memo3(function TextNode2({ id, data, selected }) {
3372
+ const [editing, setEditing] = useState4(
3208
3373
  useContext(StartWritingContext) === id
3209
3374
  );
3210
- const { deleteElements } = useReactFlow();
3375
+ const { deleteElements } = useReactFlow2();
3211
3376
  const updateNodeData2 = useContext(UpdateNodeDataContext);
3212
3377
  const liveEdit = useContext(EditingContext);
3213
- const boxRef = useRef(null);
3378
+ const boxRef = useRef3(null);
3214
3379
  const savedFont = typeof data.fontSize === "number" ? data.fontSize : TEXT_FONT_SIZE;
3215
3380
  const savedAngle = typeof data.angle === "number" ? data.angle : 0;
3216
- const [scaling, setScaling] = useState2(null);
3217
- const [turning, setTurning] = useState2(null);
3381
+ const [scaling, setScaling] = useState4(null);
3382
+ const [turning, setTurning] = useState4(null);
3218
3383
  const fontSize = scaling ?? savedFont;
3219
3384
  const angle = turning ?? savedAngle;
3220
3385
  const startScaling = (corner) => (event) => {
@@ -3280,7 +3445,7 @@ var TextNode = memo2(function TextNode2({ id, data, selected }) {
3280
3445
  };
3281
3446
  const locked = useContext(LockedContext);
3282
3447
  const framed = (selected || scaling !== null || turning !== null) && !editing && !locked;
3283
- return /* @__PURE__ */ jsxs2(
3448
+ return /* @__PURE__ */ jsxs3(
3284
3449
  "div",
3285
3450
  {
3286
3451
  ref: boxRef,
@@ -3288,8 +3453,8 @@ var TextNode = memo2(function TextNode2({ id, data, selected }) {
3288
3453
  style: angle ? { transform: `rotate(${angle}deg)` } : void 0,
3289
3454
  onDoubleClick: () => !locked && setEditing(true),
3290
3455
  children: [
3291
- framed && /* @__PURE__ */ jsxs2(Fragment, { children: [
3292
- TEXT_CORNERS.map((corner) => /* @__PURE__ */ jsx2(
3456
+ framed && /* @__PURE__ */ jsxs3(Fragment3, { children: [
3457
+ TEXT_CORNERS.map((corner) => /* @__PURE__ */ jsx3(
3293
3458
  "span",
3294
3459
  {
3295
3460
  className: `nodrag nopan studio-text-corner is-${corner}`,
@@ -3297,7 +3462,7 @@ var TextNode = memo2(function TextNode2({ id, data, selected }) {
3297
3462
  },
3298
3463
  corner
3299
3464
  )),
3300
- /* @__PURE__ */ jsx2(
3465
+ /* @__PURE__ */ jsx3(
3301
3466
  "span",
3302
3467
  {
3303
3468
  className: "nodrag nopan studio-text-turn",
@@ -3306,7 +3471,7 @@ var TextNode = memo2(function TextNode2({ id, data, selected }) {
3306
3471
  }
3307
3472
  )
3308
3473
  ] }),
3309
- /* @__PURE__ */ jsx2(
3474
+ /* @__PURE__ */ jsx3(
3310
3475
  Writing,
3311
3476
  {
3312
3477
  id,
@@ -3327,42 +3492,42 @@ var useDomainData = ({
3327
3492
  type,
3328
3493
  data,
3329
3494
  parentId
3330
- }) => useMemo(() => {
3495
+ }) => useMemo3(() => {
3331
3496
  const isDomain2 = type === GROUP_TYPES.domain || type === "context-domain";
3332
3497
  return isDomain2 && parentId && data.subdomain === void 0 ? { ...data, subdomain: true } : data;
3333
3498
  }, [type, data, parentId]);
3334
- var EntityCard = memo2(function EntityCard2(props) {
3335
- const data = useMemo(
3499
+ var EntityCard = memo3(function EntityCard2(props) {
3500
+ const data = useMemo3(
3336
3501
  () => ({ ...props.data, entity: { data: props.data.entity ?? {} } }),
3337
3502
  [props.data]
3338
3503
  );
3339
- return /* @__PURE__ */ jsxs2(Fragment, { children: [
3340
- /* @__PURE__ */ jsx2(Entity_default, { ...props, data }),
3341
- /* @__PURE__ */ jsx2(
3342
- Handle2,
3504
+ return /* @__PURE__ */ jsxs3(Fragment3, { children: [
3505
+ /* @__PURE__ */ jsx3(Entity_default, { ...props, data }),
3506
+ /* @__PURE__ */ jsx3(
3507
+ Handle3,
3343
3508
  {
3344
3509
  type: "source",
3345
- position: Position2.Right,
3510
+ position: Position3.Right,
3346
3511
  id: ENTITY_SOURCE_HANDLE,
3347
3512
  className: "studio-entity-source"
3348
3513
  }
3349
3514
  )
3350
3515
  ] });
3351
3516
  });
3352
- var DomainCard = memo2(function DomainCard2(props) {
3353
- return /* @__PURE__ */ jsx2(DomainCard_default, { ...props, data: useDomainData(props) });
3517
+ var DomainCard = memo3(function DomainCard2(props) {
3518
+ return /* @__PURE__ */ jsx3(DomainCard_default, { ...props, data: useDomainData(props) });
3354
3519
  });
3355
- var GroupNode = memo2(function GroupNode2(props) {
3520
+ var GroupNode = memo3(function GroupNode2(props) {
3356
3521
  const isDropTarget = useContext(DropTargetContext) === props.id;
3357
3522
  const locked = useContext(LockedContext);
3358
3523
  const data = useDomainData(props);
3359
3524
  const store = useStoreApi2();
3360
3525
  const updateNodeInternals = useUpdateNodeInternals();
3361
- useEffect2(() => {
3526
+ useEffect4(() => {
3362
3527
  updateNodeInternals(props.id);
3363
3528
  }, [updateNodeInternals, props.id, props.width, props.height]);
3364
- const contents = useRef(null);
3365
- const onResizeStart = useCallback(() => {
3529
+ const contents = useRef3(null);
3530
+ const onResizeStart = useCallback2(() => {
3366
3531
  const { nodeLookup } = store.getState();
3367
3532
  const container = nodeLookup.get(props.id);
3368
3533
  const children = [...nodeLookup.values()].filter(
@@ -3401,7 +3566,7 @@ var GroupNode = memo2(function GroupNode2(props) {
3401
3566
  )
3402
3567
  };
3403
3568
  }, [store, props.id]);
3404
- const shouldResize = useCallback(
3569
+ const shouldResize = useCallback2(
3405
3570
  (_, {
3406
3571
  x,
3407
3572
  y,
@@ -3413,8 +3578,8 @@ var GroupNode = memo2(function GroupNode2(props) {
3413
3578
  },
3414
3579
  []
3415
3580
  );
3416
- return /* @__PURE__ */ jsxs2("div", { style: { width: "100%", height: "100%", position: "relative" }, children: [
3417
- /* @__PURE__ */ jsx2(
3581
+ return /* @__PURE__ */ jsxs3("div", { style: { width: "100%", height: "100%", position: "relative" }, children: [
3582
+ /* @__PURE__ */ jsx3(
3418
3583
  NodeResizer,
3419
3584
  {
3420
3585
  isVisible: props.selected && !locked,
@@ -3426,16 +3591,16 @@ var GroupNode = memo2(function GroupNode2(props) {
3426
3591
  handleClassName: "!h-2.5 !w-2.5 !rounded-sm !border-2 !bg-[rgb(var(--ec-card-bg))] !border-[rgb(var(--ec-accent))]"
3427
3592
  }
3428
3593
  ),
3429
- /* @__PURE__ */ jsx2(SystemGroupComponent, { ...props, data }),
3430
- /* @__PURE__ */ jsx2("div", { className: "ec-group-grip absolute inset-x-0 -top-3 h-[60px] cursor-grab" }),
3594
+ /* @__PURE__ */ jsx3(SystemGroupComponent, { ...props, data }),
3595
+ /* @__PURE__ */ jsx3("div", { className: "ec-group-grip absolute inset-x-0 -top-3 h-[60px] cursor-grab" }),
3431
3596
  isDropTarget ? (
3432
3597
  // What's dragged over it goes in it when it's dropped
3433
- /* @__PURE__ */ jsx2("div", { className: "ec-drop-target", children: /* @__PURE__ */ jsxs2("span", { className: "ec-drop-target-label", children: [
3598
+ /* @__PURE__ */ jsx3("div", { className: "ec-drop-target", children: /* @__PURE__ */ jsxs3("span", { className: "ec-drop-target-label", children: [
3434
3599
  "Drop to add to",
3435
3600
  " ",
3436
3601
  getNodeName(props.type, props.data, "this container")
3437
3602
  ] }) })
3438
- ) : props.selected && /* @__PURE__ */ jsx2("div", { className: "ec-group-selected" })
3603
+ ) : props.selected && /* @__PURE__ */ jsx3("div", { className: "ec-group-selected" })
3439
3604
  ] });
3440
3605
  });
3441
3606
  var components = {
@@ -3453,7 +3618,9 @@ var components = {
3453
3618
  team: TeamNode,
3454
3619
  // Domains and systems as containers
3455
3620
  [GROUP_TYPES.domain]: GroupNode,
3456
- [GROUP_TYPES.system]: GroupNode
3621
+ [GROUP_TYPES.system]: GroupNode,
3622
+ // Where a connection let go of on empty canvas makes something new, until what it is is chosen
3623
+ [CONNECT_PLACEHOLDER]: ConnectPlaceholderNode
3457
3624
  };
3458
3625
  var nodeTypes = Object.fromEntries(
3459
3626
  Object.entries(components).map(([type, component]) => [
@@ -3465,17 +3632,17 @@ var nodeTypes = Object.fromEntries(
3465
3632
  // src/studio/components/Comments.tsx
3466
3633
  import {
3467
3634
  createContext as createContext2,
3468
- memo as memo3,
3469
- useCallback as useCallback2,
3635
+ memo as memo4,
3636
+ useCallback as useCallback3,
3470
3637
  useContext as useContext2,
3471
- useEffect as useEffect3,
3472
- useRef as useRef2,
3473
- useState as useState4
3638
+ useEffect as useEffect5,
3639
+ useRef as useRef4,
3640
+ useState as useState6
3474
3641
  } from "react";
3475
3642
  import { createPortal } from "react-dom";
3476
3643
  import {
3477
3644
  useInternalNode,
3478
- useReactFlow as useReactFlow2
3645
+ useReactFlow as useReactFlow3
3479
3646
  } from "@xyflow/react";
3480
3647
  import {
3481
3648
  Check,
@@ -3483,7 +3650,7 @@ import {
3483
3650
  Maximize2,
3484
3651
  RotateCcw,
3485
3652
  Trash2,
3486
- X
3653
+ X as X2
3487
3654
  } from "lucide-react";
3488
3655
 
3489
3656
  // src/studio/components/status.ts
@@ -3532,15 +3699,15 @@ var CANVAS_STATUS_LOOK = {
3532
3699
  };
3533
3700
 
3534
3701
  // src/studio/components/Picture.tsx
3535
- import { useState as useState3 } from "react";
3536
- import { jsx as jsx3 } from "react/jsx-runtime";
3702
+ import { useState as useState5 } from "react";
3703
+ import { jsx as jsx4 } from "react/jsx-runtime";
3537
3704
  function Picture({
3538
3705
  src,
3539
3706
  className = "absolute inset-0 h-full w-full"
3540
3707
  }) {
3541
- const [failed, setFailed] = useState3();
3708
+ const [failed, setFailed] = useState5();
3542
3709
  if (!src || failed === src) return null;
3543
- return /* @__PURE__ */ jsx3(
3710
+ return /* @__PURE__ */ jsx4(
3544
3711
  "img",
3545
3712
  {
3546
3713
  src,
@@ -3555,15 +3722,15 @@ function Picture({
3555
3722
 
3556
3723
  // src/studio/components/ClientLogos.tsx
3557
3724
  import { Bot } from "lucide-react";
3558
- import { jsx as jsx4 } from "react/jsx-runtime";
3559
- var ClaudeLogo = (props) => /* @__PURE__ */ jsx4("svg", { viewBox: "0 0 24 24", "aria-hidden": true, ...props, children: /* @__PURE__ */ jsx4(
3725
+ import { jsx as jsx5 } from "react/jsx-runtime";
3726
+ var ClaudeLogo = (props) => /* @__PURE__ */ jsx5("svg", { viewBox: "0 0 24 24", "aria-hidden": true, ...props, children: /* @__PURE__ */ jsx5(
3560
3727
  "path",
3561
3728
  {
3562
3729
  fill: "#D97757",
3563
3730
  d: "M4.709 15.955l4.72-2.647.08-.23-.08-.128H9.2l-.79-.048-2.698-.073-2.339-.097-2.266-.122-.571-.121L0 11.784l.055-.352.48-.321.686.06 1.52.103 2.278.158 1.652.097 2.449.255h.389l.055-.157-.134-.098-.103-.097-2.358-1.596-2.552-1.688-1.336-.972-.724-.491-.364-.462-.158-1.008.656-.722.881.06.225.061.893.686 1.908 1.476 2.491 1.833.365.304.145-.103.019-.073-.164-.274-1.355-2.446-1.446-2.49-.644-1.032-.17-.619a2.97 2.97 0 01-.104-.729L6.283.134 6.696 0l.996.134.42.364.62 1.414 1.002 2.229 1.555 3.03.456.898.243.832.091.255h.158V9.01l.128-1.706.237-2.095.23-2.695.08-.76.376-.91.747-.492.584.28.48.685-.067.444-.286 1.851-.559 2.903-.364 1.942h.212l.243-.242.985-1.306 1.652-2.064.73-.82.85-.904.547-.431h1.033l.76 1.129-.34 1.166-1.064 1.347-.881 1.142-1.264 1.7-.79 1.36.073.11.188-.02 2.856-.606 1.543-.28 1.841-.315.833.388.091.395-.328.807-1.969.486-2.309.462-3.439.813-.042.03.049.061 1.549.146.662.036h1.622l3.02.225.79.522.474.638-.079.485-1.215.62-1.64-.389-3.829-.91-1.312-.329h-.182v.11l1.093 1.068 2.006 1.81 2.509 2.33.127.578-.322.455-.34-.049-2.205-1.657-.851-.747-1.926-1.62h-.128v.17l.444.649 2.345 3.521.122 1.08-.17.353-.608.213-.668-.122-1.374-1.925-1.415-2.167-1.143-1.943-.14.08-.674 7.254-.316.37-.729.28-.607-.461-.322-.747.322-1.476.389-1.924.315-1.53.286-1.9.17-.632-.012-.042-.14.018-1.434 1.967-2.18 2.945-1.726 1.845-.414.164-.717-.37.067-.662.401-.589 2.388-3.036 1.44-1.882.93-1.086-.006-.158h-.055L4.132 18.56l-1.13.146-.487-.456.061-.746.231-.243 1.908-1.312-.006.006z"
3564
3731
  }
3565
3732
  ) });
3566
- var ClaudeCodeLogo = (props) => /* @__PURE__ */ jsx4("svg", { viewBox: "0 0 24 24", "aria-hidden": true, ...props, children: /* @__PURE__ */ jsx4(
3733
+ var ClaudeCodeLogo = (props) => /* @__PURE__ */ jsx5("svg", { viewBox: "0 0 24 24", "aria-hidden": true, ...props, children: /* @__PURE__ */ jsx5(
3567
3734
  "path",
3568
3735
  {
3569
3736
  fill: "#D97757",
@@ -3572,14 +3739,14 @@ var ClaudeCodeLogo = (props) => /* @__PURE__ */ jsx4("svg", { viewBox: "0 0 24 2
3572
3739
  d: "M20.998 10.949H24v3.102h-3v3.028h-1.487V20H18v-2.921h-1.487V20H15v-2.921H9V20H7.488v-2.921H6V20H4.487v-2.921H3V14.05H0V10.95h3V5h17.998v5.949zM6 10.949h1.488V8.102H6v2.847zm10.51 0H18V8.102h-1.49v2.847z"
3573
3740
  }
3574
3741
  ) });
3575
- var OpenAILogo = (props) => /* @__PURE__ */ jsx4("svg", { viewBox: "0 0 24 24", "aria-hidden": true, ...props, children: /* @__PURE__ */ jsx4(
3742
+ var OpenAILogo = (props) => /* @__PURE__ */ jsx5("svg", { viewBox: "0 0 24 24", "aria-hidden": true, ...props, children: /* @__PURE__ */ jsx5(
3576
3743
  "path",
3577
3744
  {
3578
3745
  fill: "currentColor",
3579
3746
  d: "M9.205 8.658v-2.26c0-.19.072-.333.238-.428l4.543-2.616c.619-.357 1.356-.523 2.117-.523 2.854 0 4.662 2.212 4.662 4.566 0 .167 0 .357-.024.547l-4.71-2.759a.797.797 0 00-.856 0l-5.97 3.473zm10.609 8.8V12.06c0-.333-.143-.57-.429-.737l-5.97-3.473 1.95-1.118a.433.433 0 01.476 0l4.543 2.617c1.309.76 2.189 2.378 2.189 3.948 0 1.808-1.07 3.473-2.76 4.163zM7.802 12.703l-1.95-1.142c-.167-.095-.239-.238-.239-.428V5.899c0-2.545 1.95-4.472 4.591-4.472 1 0 1.927.333 2.712.928L8.23 5.067c-.285.166-.428.404-.428.737v6.898zM12 15.128l-2.795-1.57v-3.33L12 8.658l2.795 1.57v3.33L12 15.128zm1.796 7.23c-1 0-1.927-.332-2.712-.927l4.686-2.712c.285-.166.428-.404.428-.737v-6.898l1.974 1.142c.167.095.238.238.238.428v5.233c0 2.545-1.974 4.472-4.614 4.472zm-5.637-5.303l-4.544-2.617c-1.308-.761-2.188-2.378-2.188-3.948A4.482 4.482 0 014.21 6.327v5.423c0 .333.143.571.428.738l5.947 3.449-1.95 1.118a.432.432 0 01-.476 0zm-.262 3.9c-2.688 0-4.662-2.021-4.662-4.519 0-.19.024-.38.047-.57l4.686 2.71c.286.167.571.167.856 0l5.97-3.448v2.26c0 .19-.07.333-.237.428l-4.543 2.616c-.619.357-1.356.523-2.117.523zm5.899 2.83a5.947 5.947 0 005.827-4.756C22.287 18.339 24 15.84 24 13.296c0-1.665-.713-3.282-1.998-4.448.119-.5.19-.999.19-1.498 0-3.401-2.759-5.947-5.946-5.947-.642 0-1.26.095-1.88.31A5.962 5.962 0 0010.205 0a5.947 5.947 0 00-5.827 4.757C1.713 5.447 0 7.945 0 10.49c0 1.666.713 3.283 1.998 4.448-.119.5-.19 1-.19 1.499 0 3.401 2.759 5.946 5.946 5.946.642 0 1.26-.095 1.88-.309a5.96 5.96 0 004.162 1.713z"
3580
3747
  }
3581
3748
  ) });
3582
- var CursorLogo = (props) => /* @__PURE__ */ jsx4("svg", { viewBox: "0 0 24 24", "aria-hidden": true, ...props, children: /* @__PURE__ */ jsx4(
3749
+ var CursorLogo = (props) => /* @__PURE__ */ jsx5("svg", { viewBox: "0 0 24 24", "aria-hidden": true, ...props, children: /* @__PURE__ */ jsx5(
3583
3750
  "path",
3584
3751
  {
3585
3752
  fill: "currentColor",
@@ -3599,18 +3766,18 @@ function AgentMark({
3599
3766
  size = 14
3600
3767
  }) {
3601
3768
  const Logo = agentLogoFor(name);
3602
- return Logo ? /* @__PURE__ */ jsx4(
3769
+ return Logo ? /* @__PURE__ */ jsx5(
3603
3770
  "span",
3604
3771
  {
3605
3772
  className: "flex flex-none items-center justify-center rounded-full bg-white",
3606
3773
  style: { width: size + 4, height: size + 4, color: "#111827" },
3607
- children: /* @__PURE__ */ jsx4(Logo, { width: size - 2, height: size - 2 })
3774
+ children: /* @__PURE__ */ jsx5(Logo, { width: size - 2, height: size - 2 })
3608
3775
  }
3609
- ) : /* @__PURE__ */ jsx4(Bot, { size });
3776
+ ) : /* @__PURE__ */ jsx5(Bot, { size });
3610
3777
  }
3611
3778
 
3612
3779
  // src/studio/components/Comments.tsx
3613
- import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
3780
+ import { Fragment as Fragment4, jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
3614
3781
  var initials = (name) => {
3615
3782
  const words = name.trim().split(/\s+/).filter(Boolean);
3616
3783
  return (words.length > 1 ? words.map((word) => word[0]).join("") : name.trim()).slice(0, 2).toUpperCase();
@@ -3659,7 +3826,7 @@ function Avatar({
3659
3826
  muted,
3660
3827
  size = "h-6 w-6"
3661
3828
  }) {
3662
- return /* @__PURE__ */ jsxs3(
3829
+ return /* @__PURE__ */ jsxs4(
3663
3830
  "span",
3664
3831
  {
3665
3832
  title: author.name,
@@ -3668,8 +3835,8 @@ function Avatar({
3668
3835
  backgroundColor: muted ? "rgb(var(--ec-page-text-muted))" : author.color
3669
3836
  },
3670
3837
  children: [
3671
- author.agent ? /* @__PURE__ */ jsx5(AgentMark, { name: author.name, size: 13 }) : initials(author.name),
3672
- /* @__PURE__ */ jsx5(
3838
+ author.agent ? /* @__PURE__ */ jsx6(AgentMark, { name: author.name, size: 13 }) : initials(author.name),
3839
+ /* @__PURE__ */ jsx6(
3673
3840
  Picture,
3674
3841
  {
3675
3842
  src: author.picture,
@@ -3689,11 +3856,11 @@ function Pin({
3689
3856
  onClick,
3690
3857
  onDrag
3691
3858
  }) {
3692
- const drag = useRef2(null);
3693
- const [hovered, setHovered] = useState4(false);
3694
- const hoverTimer = useRef2(void 0);
3695
- useEffect3(() => () => clearTimeout(hoverTimer.current), []);
3696
- const [pressed, setPressed] = useState4(false);
3859
+ const drag = useRef4(null);
3860
+ const [hovered, setHovered] = useState6(false);
3861
+ const hoverTimer = useRef4(void 0);
3862
+ useEffect5(() => () => clearTimeout(hoverTimer.current), []);
3863
+ const [pressed, setPressed] = useState6(false);
3697
3864
  const tipOf = (event) => ({
3698
3865
  x: event.clientX - drag.current.grab.x,
3699
3866
  y: event.clientY - drag.current.grab.y
@@ -3701,7 +3868,7 @@ function Pin({
3701
3868
  const people = thread ? participantsOf(thread) : [author];
3702
3869
  const [first, ...rest] = thread?.messages ?? [];
3703
3870
  const expanded = !!thread && !!first && hovered && !active && !pressed;
3704
- return /* @__PURE__ */ jsx5(
3871
+ return /* @__PURE__ */ jsx6(
3705
3872
  "button",
3706
3873
  {
3707
3874
  onPointerEnter: () => {
@@ -3761,9 +3928,9 @@ function Pin({
3761
3928
  style: selected ? {
3762
3929
  boxShadow: "0 0 0 2px rgb(var(--ec-card-bg)), 0 0 0 4px rgb(var(--ec-button-bg))"
3763
3930
  } : void 0,
3764
- children: expanded ? /* @__PURE__ */ jsxs3("span", { className: "block space-y-1 px-1.5 py-1", children: [
3765
- /* @__PURE__ */ jsxs3("span", { className: "flex items-center gap-2", children: [
3766
- /* @__PURE__ */ jsx5("span", { className: "flex -space-x-0.5", children: people.slice(0, MAX_PIN_AVATARS).map((person) => /* @__PURE__ */ jsx5(
3931
+ children: expanded ? /* @__PURE__ */ jsxs4("span", { className: "block space-y-1 px-1.5 py-1", children: [
3932
+ /* @__PURE__ */ jsxs4("span", { className: "flex items-center gap-2", children: [
3933
+ /* @__PURE__ */ jsx6("span", { className: "flex -space-x-0.5", children: people.slice(0, MAX_PIN_AVATARS).map((person) => /* @__PURE__ */ jsx6(
3767
3934
  Avatar,
3768
3935
  {
3769
3936
  author: person,
@@ -3772,26 +3939,26 @@ function Pin({
3772
3939
  },
3773
3940
  person.name
3774
3941
  )) }),
3775
- /* @__PURE__ */ jsx5("span", { className: "min-w-0 truncate text-xs font-semibold", children: thread.author.name }),
3776
- /* @__PURE__ */ jsx5("span", { className: "shrink-0 text-[11px] text-[rgb(var(--ec-page-text-muted))]", children: timeAgo(first.createdAt) })
3942
+ /* @__PURE__ */ jsx6("span", { className: "min-w-0 truncate text-xs font-semibold", children: thread.author.name }),
3943
+ /* @__PURE__ */ jsx6("span", { className: "shrink-0 text-[11px] text-[rgb(var(--ec-page-text-muted))]", children: timeAgo(first.createdAt) })
3777
3944
  ] }),
3778
- /* @__PURE__ */ jsx5("span", { className: "line-clamp-3 block whitespace-pre-wrap break-words text-xs", children: first.text }),
3779
- (rest.length > 0 || resolved) && /* @__PURE__ */ jsxs3("span", { className: "flex items-center gap-2 text-[11px] font-medium text-[rgb(var(--ec-page-text-muted))]", children: [
3780
- rest.length > 0 && /* @__PURE__ */ jsx5("span", { children: repliesLabel(rest.length) }),
3781
- resolved && /* @__PURE__ */ jsxs3(
3945
+ /* @__PURE__ */ jsx6("span", { className: "line-clamp-3 block whitespace-pre-wrap break-words text-xs", children: first.text }),
3946
+ (rest.length > 0 || resolved) && /* @__PURE__ */ jsxs4("span", { className: "flex items-center gap-2 text-[11px] font-medium text-[rgb(var(--ec-page-text-muted))]", children: [
3947
+ rest.length > 0 && /* @__PURE__ */ jsx6("span", { children: repliesLabel(rest.length) }),
3948
+ resolved && /* @__PURE__ */ jsxs4(
3782
3949
  "span",
3783
3950
  {
3784
3951
  className: `flex items-center gap-0.5 ${STATUS.success.text}`,
3785
3952
  children: [
3786
- /* @__PURE__ */ jsx5(Check, { size: 11 }),
3953
+ /* @__PURE__ */ jsx6(Check, { size: 11 }),
3787
3954
  " Resolved"
3788
3955
  ]
3789
3956
  }
3790
3957
  )
3791
3958
  ] })
3792
- ] }) : /* @__PURE__ */ jsxs3("span", { className: "flex -space-x-1", children: [
3793
- people.slice(0, MAX_PIN_AVATARS).map((person) => /* @__PURE__ */ jsx5(Avatar, { author: person, muted: resolved }, person.name)),
3794
- people.length > MAX_PIN_AVATARS && /* @__PURE__ */ jsxs3("span", { className: "flex h-6 w-6 items-center justify-center rounded-full text-[10px] font-semibold ring-2 ring-[rgb(var(--ec-card-bg))] bg-[rgb(var(--ec-page-border))]", children: [
3959
+ ] }) : /* @__PURE__ */ jsxs4("span", { className: "flex -space-x-1", children: [
3960
+ people.slice(0, MAX_PIN_AVATARS).map((person) => /* @__PURE__ */ jsx6(Avatar, { author: person, muted: resolved }, person.name)),
3961
+ people.length > MAX_PIN_AVATARS && /* @__PURE__ */ jsxs4("span", { className: "flex h-6 w-6 items-center justify-center rounded-full text-[10px] font-semibold ring-2 ring-[rgb(var(--ec-card-bg))] bg-[rgb(var(--ec-page-border))]", children: [
3795
3962
  "+",
3796
3963
  people.length - MAX_PIN_AVATARS
3797
3964
  ] })
@@ -3804,14 +3971,14 @@ function Composer({
3804
3971
  onSubmit,
3805
3972
  onCancel
3806
3973
  }) {
3807
- const [text, setText] = useState4("");
3974
+ const [text, setText] = useState6("");
3808
3975
  const submit = () => {
3809
3976
  if (!text.trim()) return;
3810
3977
  onSubmit(text.trim());
3811
3978
  setText("");
3812
3979
  };
3813
- return /* @__PURE__ */ jsxs3("div", { className: "flex items-end gap-2 p-2", children: [
3814
- /* @__PURE__ */ jsx5(
3980
+ return /* @__PURE__ */ jsxs4("div", { className: "flex items-end gap-2 p-2", children: [
3981
+ /* @__PURE__ */ jsx6(
3815
3982
  "textarea",
3816
3983
  {
3817
3984
  autoFocus: true,
@@ -3829,7 +3996,7 @@ function Composer({
3829
3996
  className: "max-h-32 min-h-[34px] flex-1 resize-none rounded-md border px-2 py-1.5 text-sm bg-[rgb(var(--ec-input-bg))] border-[rgb(var(--ec-input-border))] text-[rgb(var(--ec-input-text))]"
3830
3997
  }
3831
3998
  ),
3832
- /* @__PURE__ */ jsx5(
3999
+ /* @__PURE__ */ jsx6(
3833
4000
  "button",
3834
4001
  {
3835
4002
  onClick: submit,
@@ -3845,7 +4012,7 @@ function IconButton({
3845
4012
  onClick,
3846
4013
  children
3847
4014
  }) {
3848
- return /* @__PURE__ */ jsx5(
4015
+ return /* @__PURE__ */ jsx6(
3849
4016
  "button",
3850
4017
  {
3851
4018
  title,
@@ -3862,14 +4029,14 @@ function FloatingPanel({
3862
4029
  children,
3863
4030
  onClickOutside
3864
4031
  }) {
3865
- const ref = useRef2(null);
3866
- const [offset, setOffset] = useState4({ x: 0, y: 0 });
3867
- const offsetRef = useRef2(offset);
4032
+ const ref = useRef4(null);
4033
+ const [offset, setOffset] = useState6({ x: 0, y: 0 });
4034
+ const offsetRef = useRef4(offset);
3868
4035
  offsetRef.current = offset;
3869
- const clickedOutside = useRef2(onClickOutside);
4036
+ const clickedOutside = useRef4(onClickOutside);
3870
4037
  clickedOutside.current = onClickOutside;
3871
4038
  const closesOnClickOutside = !!onClickOutside;
3872
- useEffect3(() => {
4039
+ useEffect5(() => {
3873
4040
  if (!closesOnClickOutside) return;
3874
4041
  const onPointerDown = (event) => {
3875
4042
  const element = ref.current;
@@ -3882,7 +4049,7 @@ function FloatingPanel({
3882
4049
  document.addEventListener("pointerdown", onPointerDown, true);
3883
4050
  return () => document.removeEventListener("pointerdown", onPointerDown, true);
3884
4051
  }, [closesOnClickOutside]);
3885
- useEffect3(() => {
4052
+ useEffect5(() => {
3886
4053
  const element = ref.current;
3887
4054
  if (!element) return;
3888
4055
  const fit = () => {
@@ -3898,7 +4065,7 @@ function FloatingPanel({
3898
4065
  observer.observe(element);
3899
4066
  return () => observer.disconnect();
3900
4067
  }, []);
3901
- const startDrag = useCallback2((event) => {
4068
+ const startDrag = useCallback3((event) => {
3902
4069
  if (event.button !== 0 || event.target.closest("button"))
3903
4070
  return;
3904
4071
  event.preventDefault();
@@ -3919,7 +4086,7 @@ function FloatingPanel({
3919
4086
  element.addEventListener("pointerup", end);
3920
4087
  element.addEventListener("pointercancel", end);
3921
4088
  }, []);
3922
- return /* @__PURE__ */ jsx5(
4089
+ return /* @__PURE__ */ jsx6(
3923
4090
  "div",
3924
4091
  {
3925
4092
  ref,
@@ -3929,7 +4096,7 @@ function FloatingPanel({
3929
4096
  top: offset.y,
3930
4097
  maxHeight: PANEL_MAX_HEIGHT_PX
3931
4098
  },
3932
- children: /* @__PURE__ */ jsx5(DragPanelContext.Provider, { value: startDrag, children })
4099
+ children: /* @__PURE__ */ jsx6(DragPanelContext.Provider, { value: startDrag, children })
3933
4100
  }
3934
4101
  );
3935
4102
  }
@@ -3941,21 +4108,21 @@ function ThreadPopover({
3941
4108
  onClose,
3942
4109
  onExpand
3943
4110
  }) {
3944
- const listRef = useRef2(null);
4111
+ const listRef = useRef4(null);
3945
4112
  const startDrag = useContext2(DragPanelContext);
3946
- useEffect3(() => {
4113
+ useEffect5(() => {
3947
4114
  listRef.current?.scrollTo({ top: listRef.current.scrollHeight });
3948
4115
  }, [thread.messages.length]);
3949
- return /* @__PURE__ */ jsxs3(Fragment2, { children: [
3950
- /* @__PURE__ */ jsxs3(
4116
+ return /* @__PURE__ */ jsxs4(Fragment4, { children: [
4117
+ /* @__PURE__ */ jsxs4(
3951
4118
  "div",
3952
4119
  {
3953
4120
  onPointerDown: startDrag ?? void 0,
3954
4121
  title: startDrag ? "Drag to move" : void 0,
3955
4122
  className: `flex shrink-0 select-none items-center justify-between border-b px-3 py-2 border-[rgb(var(--ec-page-border))] ${startDrag ? "cursor-move" : ""}`,
3956
4123
  children: [
3957
- /* @__PURE__ */ jsxs3("span", { className: "flex items-center gap-1 text-xs font-semibold", children: [
3958
- startDrag && /* @__PURE__ */ jsx5(
4124
+ /* @__PURE__ */ jsxs4("span", { className: "flex items-center gap-1 text-xs font-semibold", children: [
4125
+ startDrag && /* @__PURE__ */ jsx6(
3959
4126
  GripVertical,
3960
4127
  {
3961
4128
  size: 14,
@@ -3965,51 +4132,51 @@ function ThreadPopover({
3965
4132
  ),
3966
4133
  thread.resolved ? "Resolved thread" : "Thread"
3967
4134
  ] }),
3968
- /* @__PURE__ */ jsxs3("span", { className: "flex items-center gap-0.5", children: [
3969
- /* @__PURE__ */ jsx5(
4135
+ /* @__PURE__ */ jsxs4("span", { className: "flex items-center gap-0.5", children: [
4136
+ /* @__PURE__ */ jsx6(
3970
4137
  IconButton,
3971
4138
  {
3972
4139
  title: thread.resolved ? "Reopen" : "Resolve",
3973
4140
  onClick: () => onResolve(!thread.resolved),
3974
- children: thread.resolved ? /* @__PURE__ */ jsx5(RotateCcw, { size: 14 }) : /* @__PURE__ */ jsx5(Check, { size: 14 })
4141
+ children: thread.resolved ? /* @__PURE__ */ jsx6(RotateCcw, { size: 14 }) : /* @__PURE__ */ jsx6(Check, { size: 14 })
3975
4142
  }
3976
4143
  ),
3977
- /* @__PURE__ */ jsx5(IconButton, { title: "Delete thread", onClick: onDelete, children: /* @__PURE__ */ jsx5(Trash2, { size: 14 }) }),
3978
- onExpand && /* @__PURE__ */ jsx5(IconButton, { title: "Open bigger", onClick: onExpand, children: /* @__PURE__ */ jsx5(Maximize2, { size: 14 }) }),
3979
- /* @__PURE__ */ jsx5(IconButton, { title: "Close", onClick: onClose, children: /* @__PURE__ */ jsx5(X, { size: 14 }) })
4144
+ /* @__PURE__ */ jsx6(IconButton, { title: "Delete thread", onClick: onDelete, children: /* @__PURE__ */ jsx6(Trash2, { size: 14 }) }),
4145
+ onExpand && /* @__PURE__ */ jsx6(IconButton, { title: "Open bigger", onClick: onExpand, children: /* @__PURE__ */ jsx6(Maximize2, { size: 14 }) }),
4146
+ /* @__PURE__ */ jsx6(IconButton, { title: "Close", onClick: onClose, children: /* @__PURE__ */ jsx6(X2, { size: 14 }) })
3980
4147
  ] })
3981
4148
  ]
3982
4149
  }
3983
4150
  ),
3984
- /* @__PURE__ */ jsx5(
4151
+ /* @__PURE__ */ jsx6(
3985
4152
  "div",
3986
4153
  {
3987
4154
  ref: listRef,
3988
4155
  className: "min-h-0 flex-1 space-y-3 overflow-y-auto px-3 py-3",
3989
- children: thread.messages.map((message) => /* @__PURE__ */ jsxs3("div", { className: "flex gap-2", children: [
3990
- /* @__PURE__ */ jsxs3(
4156
+ children: thread.messages.map((message) => /* @__PURE__ */ jsxs4("div", { className: "flex gap-2", children: [
4157
+ /* @__PURE__ */ jsxs4(
3991
4158
  "span",
3992
4159
  {
3993
4160
  className: "relative flex h-6 w-6 shrink-0 items-center justify-center rounded-full text-[10px] font-semibold text-white",
3994
4161
  style: { backgroundColor: message.author.color },
3995
4162
  children: [
3996
- message.author.agent ? /* @__PURE__ */ jsx5(AgentMark, { name: message.author.name, size: 13 }) : initials(message.author.name),
3997
- /* @__PURE__ */ jsx5(Picture, { src: message.author.picture })
4163
+ message.author.agent ? /* @__PURE__ */ jsx6(AgentMark, { name: message.author.name, size: 13 }) : initials(message.author.name),
4164
+ /* @__PURE__ */ jsx6(Picture, { src: message.author.picture })
3998
4165
  ]
3999
4166
  }
4000
4167
  ),
4001
- /* @__PURE__ */ jsxs3("div", { className: "min-w-0", children: [
4002
- /* @__PURE__ */ jsxs3("p", { className: "text-xs", children: [
4003
- /* @__PURE__ */ jsx5("span", { className: "font-semibold", children: message.author.name }),
4168
+ /* @__PURE__ */ jsxs4("div", { className: "min-w-0", children: [
4169
+ /* @__PURE__ */ jsxs4("p", { className: "text-xs", children: [
4170
+ /* @__PURE__ */ jsx6("span", { className: "font-semibold", children: message.author.name }),
4004
4171
  " ",
4005
- /* @__PURE__ */ jsx5("span", { className: "text-[rgb(var(--ec-page-text-muted))]", children: timeAgo(message.createdAt) })
4172
+ /* @__PURE__ */ jsx6("span", { className: "text-[rgb(var(--ec-page-text-muted))]", children: timeAgo(message.createdAt) })
4006
4173
  ] }),
4007
- /* @__PURE__ */ jsx5("p", { className: "whitespace-pre-wrap break-words text-sm", children: message.text })
4174
+ /* @__PURE__ */ jsx6("p", { className: "whitespace-pre-wrap break-words text-sm", children: message.text })
4008
4175
  ] })
4009
4176
  ] }, message.id))
4010
4177
  }
4011
4178
  ),
4012
- /* @__PURE__ */ jsx5("div", { className: "shrink-0 border-t border-[rgb(var(--ec-page-border))]", children: /* @__PURE__ */ jsx5(Composer, { placeholder: "Reply", onSubmit: onReply, onCancel: onClose }) })
4179
+ /* @__PURE__ */ jsx6("div", { className: "shrink-0 border-t border-[rgb(var(--ec-page-border))]", children: /* @__PURE__ */ jsx6(Composer, { placeholder: "Reply", onSubmit: onReply, onCancel: onClose }) })
4013
4180
  ] });
4014
4181
  }
4015
4182
  function ThreadDialog({
@@ -4020,12 +4187,12 @@ function ThreadDialog({
4020
4187
  onShrink,
4021
4188
  onClose
4022
4189
  }) {
4023
- useEffect3(() => {
4190
+ useEffect5(() => {
4024
4191
  const onKeyDown = (event) => event.key === "Escape" && onShrink();
4025
4192
  window.addEventListener("keydown", onKeyDown);
4026
4193
  return () => window.removeEventListener("keydown", onKeyDown);
4027
4194
  }, [onShrink]);
4028
- return /* @__PURE__ */ jsx5(
4195
+ return /* @__PURE__ */ jsx6(
4029
4196
  "div",
4030
4197
  {
4031
4198
  className: "fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4",
@@ -4038,14 +4205,14 @@ function ThreadDialog({
4038
4205
  onDoubleClick: (event) => event.stopPropagation(),
4039
4206
  onContextMenu: (event) => event.stopPropagation(),
4040
4207
  onWheel: (event) => event.stopPropagation(),
4041
- children: /* @__PURE__ */ jsx5(
4208
+ children: /* @__PURE__ */ jsx6(
4042
4209
  "div",
4043
4210
  {
4044
4211
  role: "dialog",
4045
4212
  "aria-label": "Comment thread",
4046
4213
  onClick: (event) => event.stopPropagation(),
4047
4214
  className: "flex max-h-[80vh] w-full max-w-xl flex-col rounded-xl border shadow-2xl bg-[rgb(var(--ec-card-bg))] border-[rgb(var(--ec-page-border))] text-[rgb(var(--ec-page-text))]",
4048
- children: /* @__PURE__ */ jsx5(
4215
+ children: /* @__PURE__ */ jsx6(
4049
4216
  ThreadPopover,
4050
4217
  {
4051
4218
  thread,
@@ -4068,7 +4235,7 @@ function PinAt({
4068
4235
  const node = useInternalNode(anchor.nodeId ?? "");
4069
4236
  const origin = anchor.nodeId && anchor.offset ? node?.internals.positionAbsolute : void 0;
4070
4237
  const { x, y } = origin && anchor.offset ? { x: origin.x + anchor.offset.x, y: origin.y + anchor.offset.y } : anchor.position;
4071
- return /* @__PURE__ */ jsx5(
4238
+ return /* @__PURE__ */ jsx6(
4072
4239
  "div",
4073
4240
  {
4074
4241
  className: "absolute",
@@ -4079,11 +4246,11 @@ function PinAt({
4079
4246
  transformOrigin: "0 0",
4080
4247
  zIndex
4081
4248
  },
4082
- children: /* @__PURE__ */ jsx5("div", { className: "nopan nodrag nowheel pointer-events-auto absolute bottom-0 left-0", children })
4249
+ children: /* @__PURE__ */ jsx6("div", { className: "nopan nodrag nowheel pointer-events-auto absolute bottom-0 left-0", children })
4083
4250
  }
4084
4251
  );
4085
4252
  }
4086
- var CommentLayer = memo3(function CommentLayer2({
4253
+ var CommentLayer = memo4(function CommentLayer2({
4087
4254
  threads,
4088
4255
  author,
4089
4256
  openThreadId,
@@ -4101,12 +4268,12 @@ var CommentLayer = memo3(function CommentLayer2({
4101
4268
  selectionOffset,
4102
4269
  live
4103
4270
  }) {
4104
- const layer = useRef2(null);
4271
+ const layer = useRef4(null);
4105
4272
  useCounterScale(layer);
4106
- const { screenToFlowPosition, getInternalNode } = useReactFlow2();
4107
- const [moving, setMoving] = useState4(null);
4273
+ const { screenToFlowPosition, getInternalNode } = useReactFlow3();
4274
+ const [moving, setMoving] = useState6(null);
4108
4275
  const remote = useRemoteMoves(live, "comment");
4109
- const [expandedId, setExpandedId] = useState4(null);
4276
+ const [expandedId, setExpandedId] = useState6(null);
4110
4277
  const expanded = expandedId && expandedId === openThreadId ? threads.find((thread) => thread.id === expandedId) : void 0;
4111
4278
  const nodeUnder = (point) => {
4112
4279
  for (const element of document.elementsFromPoint(point.x, point.y)) {
@@ -4131,7 +4298,7 @@ var CommentLayer = memo3(function CommentLayer2({
4131
4298
  const visible = threads.filter(
4132
4299
  (thread) => showResolved || !thread.resolved || thread.id === openThreadId
4133
4300
  );
4134
- return /* @__PURE__ */ jsx5(CanvasPortal, { children: /* @__PURE__ */ jsxs3(
4301
+ return /* @__PURE__ */ jsx6(CanvasPortal, { children: /* @__PURE__ */ jsxs4(
4135
4302
  "div",
4136
4303
  {
4137
4304
  ref: layer,
@@ -4140,7 +4307,7 @@ var CommentLayer = memo3(function CommentLayer2({
4140
4307
  children: [
4141
4308
  visible.map((thread) => {
4142
4309
  const isOpen = thread.id === openThreadId;
4143
- return /* @__PURE__ */ jsxs3(
4310
+ return /* @__PURE__ */ jsxs4(
4144
4311
  PinAt,
4145
4312
  {
4146
4313
  anchor: moving?.threadId === thread.id ? moving.anchor : remote.has(thread.id) ? { position: remote.get(thread.id) } : selectionOffset && !thread.nodeId && selectedIds.has(thread.id) ? {
@@ -4151,7 +4318,7 @@ var CommentLayer = memo3(function CommentLayer2({
4151
4318
  } : thread,
4152
4319
  zIndex: isOpen ? 2 : 1,
4153
4320
  children: [
4154
- /* @__PURE__ */ jsx5(
4321
+ /* @__PURE__ */ jsx6(
4155
4322
  Pin,
4156
4323
  {
4157
4324
  author: thread.author,
@@ -4172,7 +4339,7 @@ var CommentLayer = memo3(function CommentLayer2({
4172
4339
  }
4173
4340
  }
4174
4341
  ),
4175
- isOpen && expanded?.id !== thread.id && /* @__PURE__ */ jsx5(FloatingPanel, { onClickOutside: () => onOpen(null), children: /* @__PURE__ */ jsx5(
4342
+ isOpen && expanded?.id !== thread.id && /* @__PURE__ */ jsx6(FloatingPanel, { onClickOutside: () => onOpen(null), children: /* @__PURE__ */ jsx6(
4176
4343
  ThreadPopover,
4177
4344
  {
4178
4345
  thread,
@@ -4189,7 +4356,7 @@ var CommentLayer = memo3(function CommentLayer2({
4189
4356
  );
4190
4357
  }),
4191
4358
  expanded && createPortal(
4192
- /* @__PURE__ */ jsx5(
4359
+ /* @__PURE__ */ jsx6(
4193
4360
  ThreadDialog,
4194
4361
  {
4195
4362
  thread: expanded,
@@ -4208,8 +4375,8 @@ var CommentLayer = memo3(function CommentLayer2({
4208
4375
  ),
4209
4376
  document.body
4210
4377
  ),
4211
- draft && /* @__PURE__ */ jsxs3(PinAt, { anchor: draft, zIndex: 3, children: [
4212
- /* @__PURE__ */ jsx5(
4378
+ draft && /* @__PURE__ */ jsxs4(PinAt, { anchor: draft, zIndex: 3, children: [
4379
+ /* @__PURE__ */ jsx6(
4213
4380
  Pin,
4214
4381
  {
4215
4382
  author,
@@ -4217,7 +4384,7 @@ var CommentLayer = memo3(function CommentLayer2({
4217
4384
  onDrag: (tip, phase) => onMoveDraft(anchorFor(tip, phase))
4218
4385
  }
4219
4386
  ),
4220
- /* @__PURE__ */ jsx5(FloatingPanel, { children: /* @__PURE__ */ jsx5(
4387
+ /* @__PURE__ */ jsx6(FloatingPanel, { children: /* @__PURE__ */ jsx6(
4221
4388
  Composer,
4222
4389
  {
4223
4390
  placeholder: "Add a comment",
@@ -4237,9 +4404,9 @@ function CommentList({
4237
4404
  onOpen
4238
4405
  }) {
4239
4406
  const shown = threads.filter((thread) => showResolved || !thread.resolved).reverse();
4240
- return /* @__PURE__ */ jsxs3("div", { className: "flex min-h-0 flex-1 flex-col", children: [
4241
- /* @__PURE__ */ jsxs3("label", { className: "mx-3 mb-2 flex items-center gap-2 text-xs text-[rgb(var(--ec-page-text-muted))]", children: [
4242
- /* @__PURE__ */ jsx5(
4407
+ return /* @__PURE__ */ jsxs4("div", { className: "flex min-h-0 flex-1 flex-col", children: [
4408
+ /* @__PURE__ */ jsxs4("label", { className: "mx-3 mb-2 flex items-center gap-2 text-xs text-[rgb(var(--ec-page-text-muted))]", children: [
4409
+ /* @__PURE__ */ jsx6(
4243
4410
  "input",
4244
4411
  {
4245
4412
  type: "checkbox",
@@ -4249,27 +4416,27 @@ function CommentList({
4249
4416
  ),
4250
4417
  "Show resolved"
4251
4418
  ] }),
4252
- /* @__PURE__ */ jsxs3("div", { className: "min-h-0 flex-1 space-y-1.5 overflow-y-auto px-3 pb-3", children: [
4253
- shown.length === 0 && /* @__PURE__ */ jsx5("p", { className: "py-6 text-center text-xs text-[rgb(var(--ec-page-text-muted))]", children: "No comments yet. Right click the canvas, or press C, to add one." }),
4419
+ /* @__PURE__ */ jsxs4("div", { className: "min-h-0 flex-1 space-y-1.5 overflow-y-auto px-3 pb-3", children: [
4420
+ shown.length === 0 && /* @__PURE__ */ jsx6("p", { className: "py-6 text-center text-xs text-[rgb(var(--ec-page-text-muted))]", children: "No comments yet. Right click the canvas, or press C, to add one." }),
4254
4421
  shown.map((thread) => {
4255
4422
  const [first, ...replies] = thread.messages;
4256
- return /* @__PURE__ */ jsxs3(
4423
+ return /* @__PURE__ */ jsxs4(
4257
4424
  "button",
4258
4425
  {
4259
4426
  onClick: () => onOpen(thread),
4260
4427
  className: `w-full space-y-1 rounded-md border px-2.5 py-2 text-left bg-[rgb(var(--ec-page-bg))] border-[rgb(var(--ec-page-border))] hover:border-[rgb(var(--ec-accent))] ${thread.resolved ? "opacity-60" : ""}`,
4261
4428
  children: [
4262
- /* @__PURE__ */ jsxs3("p", { className: "flex items-center gap-1.5 text-xs", children: [
4263
- /* @__PURE__ */ jsx5(
4429
+ /* @__PURE__ */ jsxs4("p", { className: "flex items-center gap-1.5 text-xs", children: [
4430
+ /* @__PURE__ */ jsx6(
4264
4431
  "span",
4265
4432
  {
4266
4433
  className: "h-2 w-2 shrink-0 rounded-full",
4267
4434
  style: { backgroundColor: thread.author.color }
4268
4435
  }
4269
4436
  ),
4270
- /* @__PURE__ */ jsx5("span", { className: "font-semibold", children: thread.author.name }),
4271
- /* @__PURE__ */ jsx5("span", { className: "text-[rgb(var(--ec-page-text-muted))]", children: timeAgo(thread.createdAt) }),
4272
- thread.resolved && /* @__PURE__ */ jsx5(
4437
+ /* @__PURE__ */ jsx6("span", { className: "font-semibold", children: thread.author.name }),
4438
+ /* @__PURE__ */ jsx6("span", { className: "text-[rgb(var(--ec-page-text-muted))]", children: timeAgo(thread.createdAt) }),
4439
+ thread.resolved && /* @__PURE__ */ jsx6(
4273
4440
  Check,
4274
4441
  {
4275
4442
  size: 12,
@@ -4277,8 +4444,8 @@ function CommentList({
4277
4444
  }
4278
4445
  )
4279
4446
  ] }),
4280
- /* @__PURE__ */ jsx5("p", { className: "line-clamp-2 text-xs", children: first?.text }),
4281
- replies.length > 0 && /* @__PURE__ */ jsxs3("p", { className: "text-[11px] text-[rgb(var(--ec-page-text-muted))]", children: [
4447
+ /* @__PURE__ */ jsx6("p", { className: "line-clamp-2 text-xs", children: first?.text }),
4448
+ replies.length > 0 && /* @__PURE__ */ jsxs4("p", { className: "text-[11px] text-[rgb(var(--ec-page-text-muted))]", children: [
4282
4449
  replies.length,
4283
4450
  " ",
4284
4451
  replies.length === 1 ? "reply" : "replies"
@@ -4294,11 +4461,11 @@ function CommentList({
4294
4461
 
4295
4462
  // src/studio/components/ContextMenu.tsx
4296
4463
  import {
4297
- memo as memo4,
4298
- useEffect as useEffect4,
4464
+ memo as memo5,
4465
+ useEffect as useEffect6,
4299
4466
  useLayoutEffect as useLayoutEffect2,
4300
- useRef as useRef3,
4301
- useState as useState5
4467
+ useRef as useRef5,
4468
+ useState as useState7
4302
4469
  } from "react";
4303
4470
  import {
4304
4471
  ClipboardPaste,
@@ -4312,9 +4479,9 @@ import {
4312
4479
  Trash2 as Trash22,
4313
4480
  TriangleAlert
4314
4481
  } from "lucide-react";
4315
- import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
4482
+ import { Fragment as Fragment5, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
4316
4483
  var EDGE = 8;
4317
- var ContextMenu = memo4(function ContextMenu2({
4484
+ var ContextMenu = memo5(function ContextMenu2({
4318
4485
  menu,
4319
4486
  questions,
4320
4487
  onCopy,
@@ -4328,7 +4495,7 @@ var ContextMenu = memo4(function ContextMenu2({
4328
4495
  onDeleteNode,
4329
4496
  onClose
4330
4497
  }) {
4331
- useEffect4(() => {
4498
+ useEffect6(() => {
4332
4499
  if (!menu) return;
4333
4500
  const close = (event) => {
4334
4501
  if (event instanceof KeyboardEvent && event.key !== "Escape") return;
@@ -4343,8 +4510,8 @@ var ContextMenu = memo4(function ContextMenu2({
4343
4510
  window.removeEventListener("wheel", close);
4344
4511
  };
4345
4512
  }, [menu, onClose]);
4346
- const menuRef = useRef3(null);
4347
- const [placed, setPlaced] = useState5(
4513
+ const menuRef = useRef5(null);
4514
+ const [placed, setPlaced] = useState7(
4348
4515
  null
4349
4516
  );
4350
4517
  useLayoutEffect2(() => {
@@ -4360,13 +4527,13 @@ var ContextMenu = memo4(function ContextMenu2({
4360
4527
  if (!menu) return null;
4361
4528
  const itemClass = "flex w-full items-center gap-2 rounded px-2.5 py-1.5 text-left text-xs hover:bg-[rgb(var(--ec-page-border)/0.5)]";
4362
4529
  const shortcutClass = "ml-auto text-[rgb(var(--ec-page-text-muted))]";
4363
- const item = (icon, label, onClick, shortcut, className = "") => /* @__PURE__ */ jsxs4("button", { className: `${itemClass} ${className}`, onClick, children: [
4530
+ const item = (icon, label, onClick, shortcut, className = "") => /* @__PURE__ */ jsxs5("button", { className: `${itemClass} ${className}`, onClick, children: [
4364
4531
  icon,
4365
4532
  label,
4366
- shortcut && /* @__PURE__ */ jsx6("span", { className: shortcutClass, children: shortcut })
4533
+ shortcut && /* @__PURE__ */ jsx7("span", { className: shortcutClass, children: shortcut })
4367
4534
  ] });
4368
- const separator = /* @__PURE__ */ jsx6("div", { className: "my-1 h-px bg-[rgb(var(--ec-page-border))]" });
4369
- return /* @__PURE__ */ jsxs4(
4535
+ const separator = /* @__PURE__ */ jsx7("div", { className: "my-1 h-px bg-[rgb(var(--ec-page-border))]" });
4536
+ return /* @__PURE__ */ jsxs5(
4370
4537
  "div",
4371
4538
  {
4372
4539
  onPointerDown: (event) => event.stopPropagation(),
@@ -4380,14 +4547,14 @@ var ContextMenu = memo4(function ContextMenu2({
4380
4547
  visibility: placed ? "visible" : "hidden"
4381
4548
  },
4382
4549
  children: [
4383
- menu.node && questions?.length ? /* @__PURE__ */ jsxs4(Fragment3, { children: [
4384
- questions.map((question) => /* @__PURE__ */ jsxs4(
4550
+ menu.node && questions?.length ? /* @__PURE__ */ jsxs5(Fragment5, { children: [
4551
+ questions.map((question) => /* @__PURE__ */ jsxs5(
4385
4552
  "button",
4386
4553
  {
4387
4554
  className: itemClass,
4388
4555
  onClick: question.onSelect,
4389
4556
  children: [
4390
- /* @__PURE__ */ jsx6(MessageCircleQuestion, { size: 14 }),
4557
+ /* @__PURE__ */ jsx7(MessageCircleQuestion, { size: 14 }),
4391
4558
  question.label
4392
4559
  ]
4393
4560
  },
@@ -4395,30 +4562,30 @@ var ContextMenu = memo4(function ContextMenu2({
4395
4562
  )),
4396
4563
  separator
4397
4564
  ] }) : null,
4398
- menu.node && /* @__PURE__ */ jsxs4(Fragment3, { children: [
4399
- onAddComment && item(/* @__PURE__ */ jsx6(MessageCircle, { size: 14 }), "Add comment", onAddComment, "C"),
4400
- onAddHotspot && !isWrittenOnCanvas(menu.node.type) && item(/* @__PURE__ */ jsx6(TriangleAlert, { size: 14 }), "Add hotspot", onAddHotspot, "A"),
4401
- !isWrittenOnCanvas(menu.node.type) && item(/* @__PURE__ */ jsx6(StickyNote3, { size: 14 }), "Add a note", onAddNote),
4402
- onEditDetails && !isWrittenOnCanvas(menu.node.type) && item(/* @__PURE__ */ jsx6(Pencil, { size: 14 }), "Edit details", onEditDetails),
4403
- item(/* @__PURE__ */ jsx6(Copy, { size: 14 }), "Copy", onCopy, "\u2318C"),
4404
- item(/* @__PURE__ */ jsx6(CopyPlus, { size: 14 }), "Duplicate", onDuplicate, "\u2318D"),
4565
+ menu.node && /* @__PURE__ */ jsxs5(Fragment5, { children: [
4566
+ onAddComment && item(/* @__PURE__ */ jsx7(MessageCircle, { size: 14 }), "Add comment", onAddComment, "C"),
4567
+ onAddHotspot && !isWrittenOnCanvas(menu.node.type) && item(/* @__PURE__ */ jsx7(TriangleAlert, { size: 14 }), "Add hotspot", onAddHotspot, "A"),
4568
+ !isWrittenOnCanvas(menu.node.type) && item(/* @__PURE__ */ jsx7(StickyNote3, { size: 14 }), "Add a note", onAddNote),
4569
+ onEditDetails && !isWrittenOnCanvas(menu.node.type) && item(/* @__PURE__ */ jsx7(Pencil, { size: 14 }), "Edit details", onEditDetails),
4570
+ item(/* @__PURE__ */ jsx7(Copy, { size: 14 }), "Copy", onCopy, "\u2318C"),
4571
+ item(/* @__PURE__ */ jsx7(CopyPlus, { size: 14 }), "Duplicate", onDuplicate, "\u2318D"),
4405
4572
  separator,
4406
4573
  item(
4407
- /* @__PURE__ */ jsx6(Trash22, { size: 14 }),
4574
+ /* @__PURE__ */ jsx7(Trash22, { size: 14 }),
4408
4575
  "Delete",
4409
4576
  onDeleteNode,
4410
4577
  "\u232B",
4411
4578
  STATUS.danger.text
4412
4579
  )
4413
4580
  ] }),
4414
- !menu.node && /* @__PURE__ */ jsxs4(Fragment3, { children: [
4415
- onAddComment && item(/* @__PURE__ */ jsx6(MessageCircle, { size: 14 }), "Add comment", onAddComment, "C"),
4416
- onAddHotspot && item(/* @__PURE__ */ jsx6(TriangleAlert, { size: 14 }), "Add hotspot", onAddHotspot, "A"),
4417
- item(/* @__PURE__ */ jsx6(StickyNote3, { size: 14 }), "Add a sticky note", onAddNote, "N"),
4418
- onPaste && item(/* @__PURE__ */ jsx6(ClipboardPaste, { size: 14 }), "Paste here", onPaste, "\u2318V"),
4419
- onReorder && /* @__PURE__ */ jsxs4(Fragment3, { children: [
4581
+ !menu.node && /* @__PURE__ */ jsxs5(Fragment5, { children: [
4582
+ onAddComment && item(/* @__PURE__ */ jsx7(MessageCircle, { size: 14 }), "Add comment", onAddComment, "C"),
4583
+ onAddHotspot && item(/* @__PURE__ */ jsx7(TriangleAlert, { size: 14 }), "Add hotspot", onAddHotspot, "A"),
4584
+ item(/* @__PURE__ */ jsx7(StickyNote3, { size: 14 }), "Add a sticky note", onAddNote, "N"),
4585
+ onPaste && item(/* @__PURE__ */ jsx7(ClipboardPaste, { size: 14 }), "Paste here", onPaste, "\u2318V"),
4586
+ onReorder && /* @__PURE__ */ jsxs5(Fragment5, { children: [
4420
4587
  separator,
4421
- item(/* @__PURE__ */ jsx6(SendToBack, { size: 14 }), "Reorder diagram", onReorder)
4588
+ item(/* @__PURE__ */ jsx7(SendToBack, { size: 14 }), "Reorder diagram", onReorder)
4422
4589
  ] })
4423
4590
  ] })
4424
4591
  ]
@@ -4428,18 +4595,18 @@ var ContextMenu = memo4(function ContextMenu2({
4428
4595
 
4429
4596
  // src/studio/components/DragGhost.tsx
4430
4597
  import {
4431
- useCallback as useCallback3,
4432
- useEffect as useEffect5,
4433
- useMemo as useMemo2,
4434
- useRef as useRef4,
4435
- useState as useState6
4598
+ useCallback as useCallback4,
4599
+ useEffect as useEffect7,
4600
+ useMemo as useMemo4,
4601
+ useRef as useRef6,
4602
+ useState as useState8
4436
4603
  } from "react";
4437
4604
  import {
4438
4605
  ReactFlow,
4439
4606
  ReactFlowProvider,
4440
4607
  useStoreApi as useStoreApi3
4441
4608
  } from "@xyflow/react";
4442
- import { jsx as jsx7 } from "react/jsx-runtime";
4609
+ import { jsx as jsx8 } from "react/jsx-runtime";
4443
4610
  var NO_DRAG_IMAGE = typeof Image === "undefined" ? void 0 : Object.assign(new Image(), {
4444
4611
  src: "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
4445
4612
  });
@@ -4447,8 +4614,8 @@ var MARGIN = 16;
4447
4614
  var PRO_OPTIONS = { hideAttribution: true };
4448
4615
  function useDragGhost() {
4449
4616
  const store = useStoreApi3();
4450
- const [ghost, setGhost] = useState6(null);
4451
- const startDrag = useCallback3(
4617
+ const [ghost, setGhost] = useState8(null);
4618
+ const startDrag = useCallback4(
4452
4619
  (dragType, value, preview) => (event) => {
4453
4620
  event.dataTransfer.setData(dragType, value);
4454
4621
  event.dataTransfer.effectAllowed = "move";
@@ -4461,11 +4628,11 @@ function useDragGhost() {
4461
4628
  },
4462
4629
  [store]
4463
4630
  );
4464
- const element = ghost && /* @__PURE__ */ jsx7(DragGhost, { ghost, onEnd: () => setGhost(null) });
4631
+ const element = ghost && /* @__PURE__ */ jsx8(DragGhost, { ghost, onEnd: () => setGhost(null) });
4465
4632
  return { startDrag, ghost: element };
4466
4633
  }
4467
4634
  function DragGhost({ ghost, onEnd }) {
4468
- const ref = useRef4(null);
4635
+ const ref = useRef6(null);
4469
4636
  const { preview, zoom } = ghost;
4470
4637
  const container = isGroupType(preview.type);
4471
4638
  const size = getNodeSize2(preview.type);
@@ -4473,7 +4640,7 @@ function DragGhost({ ghost, onEnd }) {
4473
4640
  x: size.width / 2 * zoom + MARGIN,
4474
4641
  y: size.height / 2 * zoom + MARGIN
4475
4642
  };
4476
- useEffect5(() => {
4643
+ useEffect7(() => {
4477
4644
  const move = (x, y) => {
4478
4645
  if (ref.current)
4479
4646
  ref.current.style.transform = `translate(${x - offset.x}px, ${y - offset.y}px)`;
@@ -4491,7 +4658,7 @@ function DragGhost({ ghost, onEnd }) {
4491
4658
  document.removeEventListener("dragend", onEnd);
4492
4659
  };
4493
4660
  }, [ghost]);
4494
- const nodes = useMemo2(
4661
+ const nodes = useMemo4(
4495
4662
  () => [
4496
4663
  {
4497
4664
  id: "drag-ghost",
@@ -4503,8 +4670,8 @@ function DragGhost({ ghost, onEnd }) {
4503
4670
  ],
4504
4671
  [preview, container, size]
4505
4672
  );
4506
- const viewport = useMemo2(() => ({ x: MARGIN, y: MARGIN, zoom }), [zoom]);
4507
- return /* @__PURE__ */ jsx7(
4673
+ const viewport = useMemo4(() => ({ x: MARGIN, y: MARGIN, zoom }), [zoom]);
4674
+ return /* @__PURE__ */ jsx8(
4508
4675
  "div",
4509
4676
  {
4510
4677
  ref,
@@ -4514,7 +4681,7 @@ function DragGhost({ ghost, onEnd }) {
4514
4681
  width: size.width * zoom + MARGIN * 2,
4515
4682
  height: size.height * zoom + MARGIN * 2
4516
4683
  },
4517
- children: /* @__PURE__ */ jsx7(ReactFlowProvider, { children: /* @__PURE__ */ jsx7(
4684
+ children: /* @__PURE__ */ jsx8(ReactFlowProvider, { children: /* @__PURE__ */ jsx8(
4518
4685
  ReactFlow,
4519
4686
  {
4520
4687
  nodes,
@@ -4536,14 +4703,14 @@ function DragGhost({ ghost, onEnd }) {
4536
4703
 
4537
4704
  // src/studio/components/Hotspots.tsx
4538
4705
  import {
4539
- memo as memo5,
4706
+ memo as memo6,
4540
4707
  useLayoutEffect as useLayoutEffect3,
4541
- useRef as useRef5,
4542
- useState as useState7
4708
+ useRef as useRef7,
4709
+ useState as useState9
4543
4710
  } from "react";
4544
4711
  import {
4545
4712
  useInternalNode as useInternalNode2,
4546
- useReactFlow as useReactFlow3,
4713
+ useReactFlow as useReactFlow4,
4547
4714
  useStoreApi as useStoreApi4
4548
4715
  } from "@xyflow/react";
4549
4716
  import {
@@ -4552,9 +4719,9 @@ import {
4552
4719
  Pencil as Pencil2,
4553
4720
  Trash2 as Trash23,
4554
4721
  TriangleAlert as TriangleAlert2,
4555
- X as X2
4722
+ X as X3
4556
4723
  } from "lucide-react";
4557
- import { Fragment as Fragment4, jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
4724
+ import { Fragment as Fragment6, jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
4558
4725
  var SEVERITIES = {
4559
4726
  critical: {
4560
4727
  label: "Critical",
@@ -4604,7 +4771,7 @@ function SpotAt({
4604
4771
  at = { x: x + (node.measured.width ?? node.width ?? 0), y };
4605
4772
  }
4606
4773
  if (!at) return null;
4607
- return /* @__PURE__ */ jsx8(
4774
+ return /* @__PURE__ */ jsx9(
4608
4775
  "div",
4609
4776
  {
4610
4777
  className: "absolute",
@@ -4615,7 +4782,7 @@ function SpotAt({
4615
4782
  transformOrigin: "0 0",
4616
4783
  zIndex
4617
4784
  },
4618
- children: /* @__PURE__ */ jsx8("div", { className: "nopan nodrag nowheel pointer-events-auto absolute left-[-14px] top-[-14px]", children })
4785
+ children: /* @__PURE__ */ jsx9("div", { className: "nopan nodrag nowheel pointer-events-auto absolute left-[-14px] top-[-14px]", children })
4619
4786
  }
4620
4787
  );
4621
4788
  }
@@ -4624,7 +4791,7 @@ function SeverityIcon({
4624
4791
  size = 13
4625
4792
  }) {
4626
4793
  const { icon: Icon } = SEVERITIES[severity];
4627
- return /* @__PURE__ */ jsx8(Icon, { size, strokeWidth: 2.5, "aria-hidden": true });
4794
+ return /* @__PURE__ */ jsx9(Icon, { size, strokeWidth: 2.5, "aria-hidden": true });
4628
4795
  }
4629
4796
  var DRAG_THRESHOLD_PX2 = 4;
4630
4797
  var ICON_CENTRE_PX = 14;
@@ -4635,7 +4802,7 @@ function Marker({
4635
4802
  onClick,
4636
4803
  onDrag
4637
4804
  }) {
4638
- const drag = useRef5(null);
4805
+ const drag = useRef7(null);
4639
4806
  const pointOf = (event) => ({
4640
4807
  x: event.clientX - drag.current.grab.x,
4641
4808
  y: event.clientY - drag.current.grab.y
@@ -4644,7 +4811,7 @@ function Marker({
4644
4811
  const severity = sorted[0].severity;
4645
4812
  const count = sorted.length;
4646
4813
  const label = spot.inside ? `${count} hotspot${count === 1 ? "" : "s"}` : count > 1 ? `${sorted[0].title} +${count - 1}` : sorted[0].title;
4647
- return /* @__PURE__ */ jsxs5(
4814
+ return /* @__PURE__ */ jsxs6(
4648
4815
  "button",
4649
4816
  {
4650
4817
  type: "button",
@@ -4704,8 +4871,8 @@ function Marker({
4704
4871
  }
4705
4872
  },
4706
4873
  children: [
4707
- /* @__PURE__ */ jsx8("span", { className: "flex h-5 w-5 flex-none items-center justify-center rounded-full bg-white/20", children: /* @__PURE__ */ jsx8(SeverityIcon, { severity }) }),
4708
- /* @__PURE__ */ jsx8("span", { className: "studio-hotspot-label truncate", children: label })
4874
+ /* @__PURE__ */ jsx9("span", { className: "flex h-5 w-5 flex-none items-center justify-center rounded-full bg-white/20", children: /* @__PURE__ */ jsx9(SeverityIcon, { severity }) }),
4875
+ /* @__PURE__ */ jsx9("span", { className: "studio-hotspot-label truncate", children: label })
4709
4876
  ]
4710
4877
  }
4711
4878
  );
@@ -4718,11 +4885,11 @@ function HotspotForm({
4718
4885
  onSubmit,
4719
4886
  onCancel
4720
4887
  }) {
4721
- const [severity, setSeverity] = useState7(
4888
+ const [severity, setSeverity] = useState9(
4722
4889
  initial?.severity ?? "warning"
4723
4890
  );
4724
- const [title, setTitle] = useState7(initial?.title ?? "");
4725
- const [description, setDescription] = useState7(initial?.description ?? "");
4891
+ const [title, setTitle] = useState9(initial?.title ?? "");
4892
+ const [description, setDescription] = useState9(initial?.description ?? "");
4726
4893
  const submit = (event) => {
4727
4894
  event?.preventDefault();
4728
4895
  if (!title.trim()) return;
@@ -4732,7 +4899,7 @@ function HotspotForm({
4732
4899
  ...description.trim() && { description: description.trim() }
4733
4900
  });
4734
4901
  };
4735
- return /* @__PURE__ */ jsxs5(
4902
+ return /* @__PURE__ */ jsxs6(
4736
4903
  "form",
4737
4904
  {
4738
4905
  onSubmit: submit,
@@ -4744,9 +4911,9 @@ function HotspotForm({
4744
4911
  },
4745
4912
  className: "space-y-2.5 p-3",
4746
4913
  children: [
4747
- /* @__PURE__ */ jsx8("div", { role: "radiogroup", "aria-label": "How important", className: "flex gap-1", children: SEVERITY_ORDER.map((value) => {
4914
+ /* @__PURE__ */ jsx9("div", { role: "radiogroup", "aria-label": "How important", className: "flex gap-1", children: SEVERITY_ORDER.map((value) => {
4748
4915
  const picked = value === severity;
4749
- return /* @__PURE__ */ jsxs5(
4916
+ return /* @__PURE__ */ jsxs6(
4750
4917
  "button",
4751
4918
  {
4752
4919
  type: "button",
@@ -4763,14 +4930,14 @@ function HotspotForm({
4763
4930
  color: SEVERITIES[value].color
4764
4931
  },
4765
4932
  children: [
4766
- /* @__PURE__ */ jsx8(SeverityIcon, { severity: value, size: 12 }),
4933
+ /* @__PURE__ */ jsx9(SeverityIcon, { severity: value, size: 12 }),
4767
4934
  SEVERITIES[value].label
4768
4935
  ]
4769
4936
  },
4770
4937
  value
4771
4938
  );
4772
4939
  }) }),
4773
- /* @__PURE__ */ jsx8(
4940
+ /* @__PURE__ */ jsx9(
4774
4941
  "input",
4775
4942
  {
4776
4943
  autoFocus: true,
@@ -4781,7 +4948,7 @@ function HotspotForm({
4781
4948
  className: inputClass
4782
4949
  }
4783
4950
  ),
4784
- /* @__PURE__ */ jsx8(
4951
+ /* @__PURE__ */ jsx9(
4785
4952
  "textarea",
4786
4953
  {
4787
4954
  value: description,
@@ -4796,8 +4963,8 @@ function HotspotForm({
4796
4963
  className: `${inputClass} resize-none`
4797
4964
  }
4798
4965
  ),
4799
- /* @__PURE__ */ jsxs5("div", { className: "flex justify-end gap-2", children: [
4800
- /* @__PURE__ */ jsx8(
4966
+ /* @__PURE__ */ jsxs6("div", { className: "flex justify-end gap-2", children: [
4967
+ /* @__PURE__ */ jsx9(
4801
4968
  "button",
4802
4969
  {
4803
4970
  type: "button",
@@ -4806,7 +4973,7 @@ function HotspotForm({
4806
4973
  children: "Cancel"
4807
4974
  }
4808
4975
  ),
4809
- /* @__PURE__ */ jsx8(
4976
+ /* @__PURE__ */ jsx9(
4810
4977
  "button",
4811
4978
  {
4812
4979
  type: "submit",
@@ -4821,13 +4988,13 @@ function HotspotForm({
4821
4988
  );
4822
4989
  }
4823
4990
  function SeverityTag({ severity }) {
4824
- return /* @__PURE__ */ jsxs5(
4991
+ return /* @__PURE__ */ jsxs6(
4825
4992
  "span",
4826
4993
  {
4827
4994
  className: "inline-flex items-center gap-1 rounded px-1.5 py-0.5 text-[10px] font-bold uppercase tracking-wide text-white",
4828
4995
  style: { background: SEVERITIES[severity].color },
4829
4996
  children: [
4830
- /* @__PURE__ */ jsx8(SeverityIcon, { severity, size: 10 }),
4997
+ /* @__PURE__ */ jsx9(SeverityIcon, { severity, size: 10 }),
4831
4998
  SEVERITIES[severity].label
4832
4999
  ]
4833
5000
  }
@@ -4837,24 +5004,24 @@ function HotspotItem({
4837
5004
  hotspot,
4838
5005
  actions
4839
5006
  }) {
4840
- return /* @__PURE__ */ jsxs5(
5007
+ return /* @__PURE__ */ jsxs6(
4841
5008
  "div",
4842
5009
  {
4843
5010
  className: "border-l-[3px] pl-2.5",
4844
5011
  style: { borderColor: SEVERITIES[hotspot.severity].color },
4845
5012
  children: [
4846
- /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-2", children: [
4847
- /* @__PURE__ */ jsx8(SeverityTag, { severity: hotspot.severity }),
4848
- /* @__PURE__ */ jsxs5("span", { className: "flex min-w-0 items-center gap-1 truncate text-[11px] text-[rgb(var(--ec-page-text-muted))]", children: [
4849
- hotspot.author.agent && /* @__PURE__ */ jsx8(AgentMark, { name: hotspot.author.name, size: 11 }),
5013
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2", children: [
5014
+ /* @__PURE__ */ jsx9(SeverityTag, { severity: hotspot.severity }),
5015
+ /* @__PURE__ */ jsxs6("span", { className: "flex min-w-0 items-center gap-1 truncate text-[11px] text-[rgb(var(--ec-page-text-muted))]", children: [
5016
+ hotspot.author.agent && /* @__PURE__ */ jsx9(AgentMark, { name: hotspot.author.name, size: 11 }),
4850
5017
  hotspot.author.name,
4851
5018
  " \xB7 ",
4852
5019
  timeAgo(hotspot.createdAt)
4853
5020
  ] }),
4854
- actions && /* @__PURE__ */ jsx8("span", { className: "ml-auto flex flex-none items-center gap-0.5", children: actions })
5021
+ actions && /* @__PURE__ */ jsx9("span", { className: "ml-auto flex flex-none items-center gap-0.5", children: actions })
4855
5022
  ] }),
4856
- /* @__PURE__ */ jsx8("p", { className: "mt-1.5 text-sm font-semibold leading-snug", children: hotspot.title }),
4857
- hotspot.description && /* @__PURE__ */ jsx8("p", { className: "mt-1 whitespace-pre-wrap text-xs leading-relaxed text-[rgb(var(--ec-page-text-muted))]", children: hotspot.description })
5023
+ /* @__PURE__ */ jsx9("p", { className: "mt-1.5 text-sm font-semibold leading-snug", children: hotspot.title }),
5024
+ hotspot.description && /* @__PURE__ */ jsx9("p", { className: "mt-1 whitespace-pre-wrap text-xs leading-relaxed text-[rgb(var(--ec-page-text-muted))]", children: hotspot.description })
4858
5025
  ]
4859
5026
  }
4860
5027
  );
@@ -4864,7 +5031,7 @@ function IconButton2({
4864
5031
  onClick,
4865
5032
  children
4866
5033
  }) {
4867
- return /* @__PURE__ */ jsx8(
5034
+ return /* @__PURE__ */ jsx9(
4868
5035
  "button",
4869
5036
  {
4870
5037
  type: "button",
@@ -4884,15 +5051,15 @@ function SpotPanel({
4884
5051
  onDelete,
4885
5052
  onGo
4886
5053
  }) {
4887
- const [editing, setEditing] = useState7(null);
5054
+ const [editing, setEditing] = useState9(null);
4888
5055
  const sorted = [...spot.hotspots].sort(bySeverity);
4889
- return /* @__PURE__ */ jsxs5("div", { className: panelClass2, children: [
4890
- /* @__PURE__ */ jsxs5("div", { className: "flex items-center justify-between border-b border-[rgb(var(--ec-page-border))] px-3 py-2", children: [
4891
- /* @__PURE__ */ jsx8("span", { className: "text-xs font-semibold", children: sorted.length === 1 ? "Hotspot" : `${sorted.length} hotspots` }),
4892
- /* @__PURE__ */ jsx8(IconButton2, { label: "Close", onClick: onClose, children: /* @__PURE__ */ jsx8(X2, { size: 14 }) })
5056
+ return /* @__PURE__ */ jsxs6("div", { className: panelClass2, children: [
5057
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-between border-b border-[rgb(var(--ec-page-border))] px-3 py-2", children: [
5058
+ /* @__PURE__ */ jsx9("span", { className: "text-xs font-semibold", children: sorted.length === 1 ? "Hotspot" : `${sorted.length} hotspots` }),
5059
+ /* @__PURE__ */ jsx9(IconButton2, { label: "Close", onClick: onClose, children: /* @__PURE__ */ jsx9(X3, { size: 14 }) })
4893
5060
  ] }),
4894
- /* @__PURE__ */ jsx8("div", { className: "max-h-80 space-y-3 overflow-y-auto p-3", children: sorted.map(
4895
- (hotspot) => editing === hotspot.id ? /* @__PURE__ */ jsx8("div", { className: "-m-3", children: /* @__PURE__ */ jsx8(
5061
+ /* @__PURE__ */ jsx9("div", { className: "max-h-80 space-y-3 overflow-y-auto p-3", children: sorted.map(
5062
+ (hotspot) => editing === hotspot.id ? /* @__PURE__ */ jsx9("div", { className: "-m-3", children: /* @__PURE__ */ jsx9(
4896
5063
  HotspotForm,
4897
5064
  {
4898
5065
  initial: hotspot,
@@ -4905,35 +5072,35 @@ function SpotPanel({
4905
5072
  }
4906
5073
  ) }, hotspot.id) : spot.inside ? (
4907
5074
  // Inside a node on L1 or L2: goes to it on L3, where it is
4908
- /* @__PURE__ */ jsx8(
5075
+ /* @__PURE__ */ jsx9(
4909
5076
  "button",
4910
5077
  {
4911
5078
  type: "button",
4912
5079
  onClick: () => onGo(hotspot),
4913
5080
  className: "block w-full rounded-md text-left hover:bg-[rgb(var(--ec-content-hover))]!",
4914
- children: /* @__PURE__ */ jsx8(HotspotItem, { hotspot })
5081
+ children: /* @__PURE__ */ jsx9(HotspotItem, { hotspot })
4915
5082
  },
4916
5083
  hotspot.id
4917
5084
  )
4918
- ) : /* @__PURE__ */ jsx8(
5085
+ ) : /* @__PURE__ */ jsx9(
4919
5086
  HotspotItem,
4920
5087
  {
4921
5088
  hotspot,
4922
- actions: !locked && /* @__PURE__ */ jsxs5(Fragment4, { children: [
4923
- /* @__PURE__ */ jsx8(
5089
+ actions: !locked && /* @__PURE__ */ jsxs6(Fragment6, { children: [
5090
+ /* @__PURE__ */ jsx9(
4924
5091
  IconButton2,
4925
5092
  {
4926
5093
  label: "Edit",
4927
5094
  onClick: () => setEditing(hotspot.id),
4928
- children: /* @__PURE__ */ jsx8(Pencil2, { size: 13 })
5095
+ children: /* @__PURE__ */ jsx9(Pencil2, { size: 13 })
4929
5096
  }
4930
5097
  ),
4931
- /* @__PURE__ */ jsx8(
5098
+ /* @__PURE__ */ jsx9(
4932
5099
  IconButton2,
4933
5100
  {
4934
5101
  label: "Remove",
4935
5102
  onClick: () => onDelete(hotspot.id),
4936
- children: /* @__PURE__ */ jsx8(Trash23, { size: 13 })
5103
+ children: /* @__PURE__ */ jsx9(Trash23, { size: 13 })
4937
5104
  }
4938
5105
  )
4939
5106
  ] })
@@ -4941,10 +5108,10 @@ function SpotPanel({
4941
5108
  hotspot.id
4942
5109
  )
4943
5110
  ) }),
4944
- spot.inside && /* @__PURE__ */ jsx8("p", { className: "border-t border-[rgb(var(--ec-page-border))] px-3 py-2 text-[11px] text-[rgb(var(--ec-page-text-muted))]", children: "Inside this: click one to go to it." })
5111
+ spot.inside && /* @__PURE__ */ jsx9("p", { className: "border-t border-[rgb(var(--ec-page-border))] px-3 py-2 text-[11px] text-[rgb(var(--ec-page-text-muted))]", children: "Inside this: click one to go to it." })
4945
5112
  ] });
4946
5113
  }
4947
- var HotspotLayer = memo5(function HotspotLayer2({
5114
+ var HotspotLayer = memo6(function HotspotLayer2({
4948
5115
  spots,
4949
5116
  openKey,
4950
5117
  draft,
@@ -4961,10 +5128,10 @@ var HotspotLayer = memo5(function HotspotLayer2({
4961
5128
  onGo,
4962
5129
  live
4963
5130
  }) {
4964
- const layer = useRef5(null);
5131
+ const layer = useRef7(null);
4965
5132
  useMarkerScale(layer);
4966
- const { screenToFlowPosition } = useReactFlow3();
4967
- const [moving, setMoving] = useState7(null);
5133
+ const { screenToFlowPosition } = useReactFlow4();
5134
+ const [moving, setMoving] = useState9(null);
4968
5135
  const remote = useRemoteMoves(live, "hotspot");
4969
5136
  const remoteAt = (spot) => {
4970
5137
  for (const hotspot of spot.hotspots)
@@ -4995,7 +5162,7 @@ var HotspotLayer = memo5(function HotspotLayer2({
4995
5162
  );
4996
5163
  sendMove(live, "hotspot", spot.hotspots[0].id, null);
4997
5164
  } : void 0;
4998
- return /* @__PURE__ */ jsx8(CanvasPortal, { children: /* @__PURE__ */ jsxs5(
5165
+ return /* @__PURE__ */ jsx9(CanvasPortal, { children: /* @__PURE__ */ jsxs6(
4999
5166
  "div",
5000
5167
  {
5001
5168
  ref: layer,
@@ -5006,14 +5173,14 @@ var HotspotLayer = memo5(function HotspotLayer2({
5006
5173
  const open = spot.key === openKey;
5007
5174
  const remotely = remoteAt(spot);
5008
5175
  const dragged = moving?.key === spot.key ? moving : remotely ? { position: remotely } : void 0;
5009
- return /* @__PURE__ */ jsxs5(
5176
+ return /* @__PURE__ */ jsxs6(
5010
5177
  SpotAt,
5011
5178
  {
5012
5179
  nodeId: dragged ? void 0 : spot.nodeId,
5013
5180
  position: dragged ? dragged.position : spot.position,
5014
5181
  zIndex: dragged ? 5 : open ? 3 : 1,
5015
5182
  children: [
5016
- /* @__PURE__ */ jsx8(
5183
+ /* @__PURE__ */ jsx9(
5017
5184
  Marker,
5018
5185
  {
5019
5186
  spot,
@@ -5023,7 +5190,7 @@ var HotspotLayer = memo5(function HotspotLayer2({
5023
5190
  onDrag: dragHandler(spot)
5024
5191
  }
5025
5192
  ),
5026
- open && !dragged && /* @__PURE__ */ jsx8(
5193
+ open && !dragged && /* @__PURE__ */ jsx9(
5027
5194
  SpotPanel,
5028
5195
  {
5029
5196
  spot,
@@ -5039,22 +5206,22 @@ var HotspotLayer = memo5(function HotspotLayer2({
5039
5206
  spot.key
5040
5207
  );
5041
5208
  }),
5042
- draft && /* @__PURE__ */ jsxs5(
5209
+ draft && /* @__PURE__ */ jsxs6(
5043
5210
  SpotAt,
5044
5211
  {
5045
5212
  nodeId: draft.nodeId,
5046
5213
  position: draft.nodeId ? void 0 : draft.position,
5047
5214
  zIndex: 4,
5048
5215
  children: [
5049
- /* @__PURE__ */ jsx8(
5216
+ /* @__PURE__ */ jsx9(
5050
5217
  "span",
5051
5218
  {
5052
5219
  className: "studio-hotspot-marker flex h-7 w-7 items-center justify-center rounded-full text-white",
5053
5220
  style: { background: SEVERITIES.warning.color },
5054
- children: /* @__PURE__ */ jsx8(SeverityIcon, { severity: "warning" })
5221
+ children: /* @__PURE__ */ jsx9(SeverityIcon, { severity: "warning" })
5055
5222
  }
5056
5223
  ),
5057
- /* @__PURE__ */ jsx8("div", { className: panelClass2, children: /* @__PURE__ */ jsx8(
5224
+ /* @__PURE__ */ jsx9("div", { className: panelClass2, children: /* @__PURE__ */ jsx9(
5058
5225
  HotspotForm,
5059
5226
  {
5060
5227
  submitLabel: "Add hotspot",
@@ -5076,18 +5243,18 @@ function HotspotList({
5076
5243
  }) {
5077
5244
  const sorted = [...hotspots].sort(bySeverity);
5078
5245
  if (!sorted.length)
5079
- return /* @__PURE__ */ jsx8("p", { className: "px-4 py-6 text-center text-xs leading-relaxed text-[rgb(var(--ec-page-text-muted))]", children: "No hotspots yet. Press A, or right-click a node, to flag what people should know: a risk, a problem, or the key part." });
5080
- return /* @__PURE__ */ jsx8("div", { className: "space-y-1.5 p-3", children: sorted.map((hotspot) => {
5246
+ return /* @__PURE__ */ jsx9("p", { className: "px-4 py-6 text-center text-xs leading-relaxed text-[rgb(var(--ec-page-text-muted))]", children: "No hotspots yet. Press A, or right-click a node, to flag what people should know: a risk, a problem, or the key part." });
5247
+ return /* @__PURE__ */ jsx9("div", { className: "space-y-1.5 p-3", children: sorted.map((hotspot) => {
5081
5248
  const on = hotspot.nodeId && nameOf(hotspot.nodeId);
5082
- return /* @__PURE__ */ jsxs5(
5249
+ return /* @__PURE__ */ jsxs6(
5083
5250
  "button",
5084
5251
  {
5085
5252
  type: "button",
5086
5253
  onClick: () => onOpen(hotspot),
5087
5254
  className: "w-full rounded-md border border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-page-bg))] px-2.5 py-2 text-left hover:border-[rgb(var(--ec-accent))]!",
5088
5255
  children: [
5089
- /* @__PURE__ */ jsx8(HotspotItem, { hotspot }),
5090
- on && /* @__PURE__ */ jsxs5("p", { className: "mt-1.5 pl-[13px] text-[11px] text-[rgb(var(--ec-page-text-muted))]", children: [
5256
+ /* @__PURE__ */ jsx9(HotspotItem, { hotspot }),
5257
+ on && /* @__PURE__ */ jsxs6("p", { className: "mt-1.5 pl-[13px] text-[11px] text-[rgb(var(--ec-page-text-muted))]", children: [
5091
5258
  "On ",
5092
5259
  on
5093
5260
  ] })
@@ -5098,76 +5265,9 @@ function HotspotList({
5098
5265
  }) });
5099
5266
  }
5100
5267
 
5101
- // src/studio/components/icons.ts
5102
- import {
5103
- ArrowRightLeft,
5104
- Bot as Bot2,
5105
- Boxes,
5106
- Archive,
5107
- Database,
5108
- DatabaseZap,
5109
- Globe,
5110
- Group,
5111
- Mail,
5112
- MonitorSmartphone,
5113
- ScanSearch,
5114
- Search,
5115
- ServerIcon,
5116
- StickyNote as StickyNote4,
5117
- TableProperties,
5118
- Type,
5119
- User,
5120
- Users as Users2,
5121
- Zap
5122
- } from "lucide-react";
5123
- var NODE_ICONS = {
5124
- [GROUP_TYPES.domain]: { icon: Boxes, className: "text-yellow-500" },
5125
- [GROUP_TYPES.system]: { icon: Group, className: "text-violet-600" },
5126
- // Catalog domains and systems added as cards
5127
- "context-domain": { icon: Boxes, className: "text-yellow-500" },
5128
- system: { icon: Group, className: "text-violet-600" },
5129
- service: { icon: ServerIcon, className: "text-pink-600" },
5130
- event: { icon: Zap, className: "text-orange-600" },
5131
- command: { icon: Mail, className: "text-blue-600" },
5132
- query: { icon: Search, className: "text-green-600" },
5133
- channel: { icon: ArrowRightLeft, className: "text-gray-600" },
5134
- data: { icon: Database, className: "text-blue-600" },
5135
- // The other kinds of data store, in the components list
5136
- "data:cache": { icon: DatabaseZap, className: "text-blue-600" },
5137
- "data:searchIndex": { icon: ScanSearch, className: "text-blue-600" },
5138
- "data:objectStore": { icon: Archive, className: "text-blue-600" },
5139
- view: { icon: MonitorSmartphone, className: "text-sky-600" },
5140
- externalSystem: { icon: Globe, className: "text-purple-600" },
5141
- agent: { icon: Bot2, className: "text-violet-600" },
5142
- actor: { icon: User, className: "text-yellow-500" },
5143
- team: { icon: Users2, className: "text-emerald-600" },
5144
- // A table of its properties, as the node shows it
5145
- entity: { icon: TableProperties, className: "text-blue-600" },
5146
- note: { icon: StickyNote4, className: "text-yellow-500" },
5147
- text: { icon: Type, className: "text-[rgb(var(--ec-icon-color))]" }
5148
- };
5149
- var CATALOG_GROUPS = [
5150
- {
5151
- collection: "domains",
5152
- label: "Domains",
5153
- ...NODE_ICONS[GROUP_TYPES.domain]
5154
- },
5155
- {
5156
- collection: "systems",
5157
- label: "Systems",
5158
- ...NODE_ICONS[GROUP_TYPES.system]
5159
- },
5160
- { collection: "services", label: "Services", ...NODE_ICONS.service },
5161
- { collection: "events", label: "Events", ...NODE_ICONS.event },
5162
- { collection: "commands", label: "Commands", ...NODE_ICONS.command },
5163
- { collection: "queries", label: "Queries", ...NODE_ICONS.query },
5164
- { collection: "channels", label: "Channels", ...NODE_ICONS.channel },
5165
- { collection: "containers", label: "Data Stores", ...NODE_ICONS.data }
5166
- ];
5167
-
5168
5268
  // src/studio/components/CanvasControls.tsx
5169
- import { memo as memo6 } from "react";
5170
- import { useReactFlow as useReactFlow4 } from "@xyflow/react";
5269
+ import { memo as memo7 } from "react";
5270
+ import { useReactFlow as useReactFlow5 } from "@xyflow/react";
5171
5271
  import {
5172
5272
  Hand,
5173
5273
  Lock,
@@ -5176,24 +5276,24 @@ import {
5176
5276
  MessageCircle as MessageCircle2,
5177
5277
  MessageSquareText,
5178
5278
  MousePointer2,
5179
- Type as Type2,
5279
+ Type,
5180
5280
  Redo,
5181
5281
  SendToBack as SendToBack2,
5182
- StickyNote as StickyNote5,
5282
+ StickyNote as StickyNote4,
5183
5283
  TriangleAlert as TriangleAlert3,
5184
5284
  Undo,
5185
5285
  ZoomIn,
5186
5286
  ZoomOut
5187
5287
  } from "lucide-react";
5188
- import { Fragment as Fragment5, jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
5288
+ import { Fragment as Fragment7, jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
5189
5289
  var FIT_VIEW_OPTIONS = DIAGRAM_FIT_VIEW_OPTIONS;
5190
5290
  function WithKey({
5191
5291
  shortcut,
5192
5292
  children
5193
5293
  }) {
5194
- return /* @__PURE__ */ jsxs6("span", { className: "relative flex h-8 w-8 items-center justify-center", children: [
5195
- /* @__PURE__ */ jsx9("span", { className: "-translate-x-[3px] -translate-y-[2px]", children }),
5196
- /* @__PURE__ */ jsx9(
5294
+ return /* @__PURE__ */ jsxs7("span", { className: "relative flex h-8 w-8 items-center justify-center", children: [
5295
+ /* @__PURE__ */ jsx10("span", { className: "-translate-x-[3px] -translate-y-[2px]", children }),
5296
+ /* @__PURE__ */ jsx10(
5197
5297
  "span",
5198
5298
  {
5199
5299
  "aria-hidden": true,
@@ -5214,13 +5314,13 @@ function LevelSwitch({
5214
5314
  onChange,
5215
5315
  unavailable
5216
5316
  }) {
5217
- return /* @__PURE__ */ jsx9(
5317
+ return /* @__PURE__ */ jsx10(
5218
5318
  "div",
5219
5319
  {
5220
5320
  role: "group",
5221
5321
  "aria-label": "Level of detail",
5222
5322
  className: "flex items-center gap-0.5",
5223
- children: LEVELS2.map(({ level: value, description }) => /* @__PURE__ */ jsx9(
5323
+ children: LEVELS2.map(({ level: value, description }) => /* @__PURE__ */ jsx10(
5224
5324
  ToolbarButton,
5225
5325
  {
5226
5326
  label: `Level ${value}: ${description} (${value})`,
@@ -5228,7 +5328,7 @@ function LevelSwitch({
5228
5328
  active: value === level,
5229
5329
  disabled: !!unavailable?.[value],
5230
5330
  onClick: () => onChange(value),
5231
- children: /* @__PURE__ */ jsx9(WithKey, { shortcut: String(value), children: /* @__PURE__ */ jsxs6("span", { className: "text-xs font-semibold", children: [
5331
+ children: /* @__PURE__ */ jsx10(WithKey, { shortcut: String(value), children: /* @__PURE__ */ jsxs7("span", { className: "text-xs font-semibold", children: [
5232
5332
  "L",
5233
5333
  value
5234
5334
  ] }) })
@@ -5238,7 +5338,7 @@ function LevelSwitch({
5238
5338
  }
5239
5339
  );
5240
5340
  }
5241
- var CanvasControls_default = memo6(function CanvasControls({
5341
+ var CanvasControls_default = memo7(function CanvasControls({
5242
5342
  level,
5243
5343
  onLevelChange,
5244
5344
  unavailableLevels,
@@ -5262,38 +5362,38 @@ var CanvasControls_default = memo6(function CanvasControls({
5262
5362
  }) {
5263
5363
  return (
5264
5364
  // At the top, as drawing tools have their tools
5265
- /* @__PURE__ */ jsxs6("div", { className: "absolute left-1/2 top-3 z-10 -translate-x-1/2", children: [
5266
- /* @__PURE__ */ jsxs6(Toolbar, { children: [
5267
- /* @__PURE__ */ jsx9(
5365
+ /* @__PURE__ */ jsxs7("div", { className: "absolute left-1/2 top-3 z-10 -translate-x-1/2", children: [
5366
+ /* @__PURE__ */ jsxs7(Toolbar, { children: [
5367
+ /* @__PURE__ */ jsx10(
5268
5368
  ToolbarButton,
5269
5369
  {
5270
5370
  label: locked ? `Locked${lockedBy ? ` by ${lockedBy}` : ""}: unlock it to change it (for everyone on it)` : "Lock the canvas (it can be looked at, not changed, by everyone on it)",
5271
5371
  active: locked,
5272
5372
  onClick: onToggleLock,
5273
- children: locked ? /* @__PURE__ */ jsx9(Lock, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx9(LockOpen, { className: "h-4 w-4" })
5373
+ children: locked ? /* @__PURE__ */ jsx10(Lock, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx10(LockOpen, { className: "h-4 w-4" })
5274
5374
  }
5275
5375
  ),
5276
- /* @__PURE__ */ jsx9(ToolbarDivider, {}),
5277
- /* @__PURE__ */ jsx9(
5376
+ /* @__PURE__ */ jsx10(ToolbarDivider, {}),
5377
+ /* @__PURE__ */ jsx10(
5278
5378
  ToolbarButton,
5279
5379
  {
5280
5380
  label: "Select (V)",
5281
5381
  active: selectMode,
5282
5382
  onClick: onSelectMode,
5283
- children: /* @__PURE__ */ jsx9(WithKey, { shortcut: "V", children: /* @__PURE__ */ jsx9(MousePointer2, { className: "h-4 w-4" }) })
5383
+ children: /* @__PURE__ */ jsx10(WithKey, { shortcut: "V", children: /* @__PURE__ */ jsx10(MousePointer2, { className: "h-4 w-4" }) })
5284
5384
  }
5285
5385
  ),
5286
- /* @__PURE__ */ jsx9(
5386
+ /* @__PURE__ */ jsx10(
5287
5387
  ToolbarButton,
5288
5388
  {
5289
5389
  label: "Hand (H): drag to move around",
5290
5390
  active: handMode,
5291
5391
  onClick: onHandMode,
5292
- children: /* @__PURE__ */ jsx9(WithKey, { shortcut: "H", children: /* @__PURE__ */ jsx9(Hand, { className: "h-4 w-4" }) })
5392
+ children: /* @__PURE__ */ jsx10(WithKey, { shortcut: "H", children: /* @__PURE__ */ jsx10(Hand, { className: "h-4 w-4" }) })
5293
5393
  }
5294
5394
  ),
5295
- /* @__PURE__ */ jsx9(ToolbarDivider, {}),
5296
- /* @__PURE__ */ jsx9(
5395
+ /* @__PURE__ */ jsx10(ToolbarDivider, {}),
5396
+ /* @__PURE__ */ jsx10(
5297
5397
  LevelSwitch,
5298
5398
  {
5299
5399
  level,
@@ -5301,8 +5401,8 @@ var CanvasControls_default = memo6(function CanvasControls({
5301
5401
  unavailable: unavailableLevels
5302
5402
  }
5303
5403
  ),
5304
- /* @__PURE__ */ jsx9(ToolbarDivider, {}),
5305
- /* @__PURE__ */ jsx9(
5404
+ /* @__PURE__ */ jsx10(ToolbarDivider, {}),
5405
+ /* @__PURE__ */ jsx10(
5306
5406
  ToolbarButton,
5307
5407
  {
5308
5408
  label: editable ? "Sticky note (N): click where it goes" : `Sticky note (N): on L${level}, where it's clicked`,
@@ -5310,10 +5410,10 @@ var CanvasControls_default = memo6(function CanvasControls({
5310
5410
  disabled: locked,
5311
5411
  hint: locked ? "The canvas is locked" : void 0,
5312
5412
  onClick: onToggleNoteMode,
5313
- children: /* @__PURE__ */ jsx9(WithKey, { shortcut: "N", children: /* @__PURE__ */ jsx9(StickyNote5, { className: "h-4 w-4 text-yellow-500" }) })
5413
+ children: /* @__PURE__ */ jsx10(WithKey, { shortcut: "N", children: /* @__PURE__ */ jsx10(StickyNote4, { className: "h-4 w-4 text-yellow-500" }) })
5314
5414
  }
5315
5415
  ),
5316
- /* @__PURE__ */ jsx9(
5416
+ /* @__PURE__ */ jsx10(
5317
5417
  ToolbarButton,
5318
5418
  {
5319
5419
  label: editable ? "Text (T): click anywhere and type" : `Text (T): on L${level}, where it's clicked`,
@@ -5321,19 +5421,19 @@ var CanvasControls_default = memo6(function CanvasControls({
5321
5421
  disabled: locked,
5322
5422
  hint: locked ? "The canvas is locked" : void 0,
5323
5423
  onClick: onToggleTextMode,
5324
- children: /* @__PURE__ */ jsx9(WithKey, { shortcut: "T", children: /* @__PURE__ */ jsx9(Type2, { className: "h-4 w-4" }) })
5424
+ children: /* @__PURE__ */ jsx10(WithKey, { shortcut: "T", children: /* @__PURE__ */ jsx10(Type, { className: "h-4 w-4" }) })
5325
5425
  }
5326
5426
  ),
5327
- /* @__PURE__ */ jsx9(
5427
+ /* @__PURE__ */ jsx10(
5328
5428
  ToolbarButton,
5329
5429
  {
5330
5430
  label: "Comment (C): click where it goes, or on a node",
5331
5431
  active: commentMode,
5332
5432
  onClick: onToggleCommentMode,
5333
- children: /* @__PURE__ */ jsx9(WithKey, { shortcut: "C", children: /* @__PURE__ */ jsx9(MessageCircle2, { className: "h-4 w-4" }) })
5433
+ children: /* @__PURE__ */ jsx10(WithKey, { shortcut: "C", children: /* @__PURE__ */ jsx10(MessageCircle2, { className: "h-4 w-4" }) })
5334
5434
  }
5335
5435
  ),
5336
- /* @__PURE__ */ jsx9(
5436
+ /* @__PURE__ */ jsx10(
5337
5437
  ToolbarButton,
5338
5438
  {
5339
5439
  label: "Hotspot (A): click a node, or anywhere, to flag it",
@@ -5341,24 +5441,24 @@ var CanvasControls_default = memo6(function CanvasControls({
5341
5441
  disabled: locked,
5342
5442
  hint: locked ? "The canvas is locked" : void 0,
5343
5443
  onClick: onToggleHotspotMode,
5344
- children: /* @__PURE__ */ jsx9(WithKey, { shortcut: "A", children: /* @__PURE__ */ jsx9(TriangleAlert3, { className: "h-4 w-4 text-amber-600" }) })
5444
+ children: /* @__PURE__ */ jsx10(WithKey, { shortcut: "A", children: /* @__PURE__ */ jsx10(TriangleAlert3, { className: "h-4 w-4 text-amber-600" }) })
5345
5445
  }
5346
5446
  ),
5347
5447
  extras
5348
5448
  ] }),
5349
- (noteMode || textMode || commentMode || hotspotMode) && /* @__PURE__ */ jsxs6("p", { className: "pointer-events-none mt-2 text-center text-xs text-[rgb(var(--ec-page-text-muted))]", children: [
5449
+ (noteMode || textMode || commentMode || hotspotMode) && /* @__PURE__ */ jsxs7("p", { className: "pointer-events-none mt-2 text-center text-xs text-[rgb(var(--ec-page-text-muted))]", children: [
5350
5450
  TOOL_HINTS[noteMode ? "note" : commentMode ? "comment" : hotspotMode ? "hotspot" : "text"],
5351
5451
  " ",
5352
5452
  "\xB7",
5353
5453
  " ",
5354
- /* @__PURE__ */ jsx9("kbd", { className: "rounded border border-[rgb(var(--ec-page-border))] px-1 font-sans text-[11px]", children: "Esc" }),
5454
+ /* @__PURE__ */ jsx10("kbd", { className: "rounded border border-[rgb(var(--ec-page-border))] px-1 font-sans text-[11px]", children: "Esc" }),
5355
5455
  " ",
5356
5456
  "to cancel"
5357
5457
  ] })
5358
5458
  ] })
5359
5459
  );
5360
5460
  });
5361
- var ViewControls = memo6(function ViewControls2({
5461
+ var ViewControls = memo7(function ViewControls2({
5362
5462
  canUndo,
5363
5463
  canRedo,
5364
5464
  onUndo,
@@ -5370,91 +5470,91 @@ var ViewControls = memo6(function ViewControls2({
5370
5470
  comments,
5371
5471
  hotspots
5372
5472
  }) {
5373
- const { zoomIn, zoomOut, fitView } = useReactFlow4();
5374
- return /* @__PURE__ */ jsxs6(Fragment5, { children: [
5375
- /* @__PURE__ */ jsxs6(Toolbar, { children: [
5376
- /* @__PURE__ */ jsx9(
5473
+ const { zoomIn, zoomOut, fitView } = useReactFlow5();
5474
+ return /* @__PURE__ */ jsxs7(Fragment7, { children: [
5475
+ /* @__PURE__ */ jsxs7(Toolbar, { children: [
5476
+ /* @__PURE__ */ jsx10(
5377
5477
  ToolbarButton,
5378
5478
  {
5379
5479
  label: "Zoom out",
5380
5480
  onClick: () => void zoomOut({ duration: 200 }),
5381
- children: /* @__PURE__ */ jsx9(ZoomOut, { className: "h-4 w-4" })
5481
+ children: /* @__PURE__ */ jsx10(ZoomOut, { className: "h-4 w-4" })
5382
5482
  }
5383
5483
  ),
5384
- /* @__PURE__ */ jsx9(ZoomLevel, {}),
5385
- /* @__PURE__ */ jsx9(
5484
+ /* @__PURE__ */ jsx10(ZoomLevel, {}),
5485
+ /* @__PURE__ */ jsx10(
5386
5486
  ToolbarButton,
5387
5487
  {
5388
5488
  label: "Zoom in",
5389
5489
  onClick: () => void zoomIn({ duration: 200 }),
5390
- children: /* @__PURE__ */ jsx9(ZoomIn, { className: "h-4 w-4" })
5490
+ children: /* @__PURE__ */ jsx10(ZoomIn, { className: "h-4 w-4" })
5391
5491
  }
5392
5492
  )
5393
5493
  ] }),
5394
- /* @__PURE__ */ jsxs6(Toolbar, { children: [
5395
- /* @__PURE__ */ jsx9(
5494
+ /* @__PURE__ */ jsxs7(Toolbar, { children: [
5495
+ /* @__PURE__ */ jsx10(
5396
5496
  ToolbarButton,
5397
5497
  {
5398
5498
  label: "Undo (\u2318Z)",
5399
5499
  hint: canUndo ? void 0 : "Nothing to undo",
5400
5500
  disabled: !canUndo,
5401
5501
  onClick: onUndo,
5402
- children: /* @__PURE__ */ jsx9(Undo, { className: "h-4 w-4" })
5502
+ children: /* @__PURE__ */ jsx10(Undo, { className: "h-4 w-4" })
5403
5503
  }
5404
5504
  ),
5405
- /* @__PURE__ */ jsx9(
5505
+ /* @__PURE__ */ jsx10(
5406
5506
  ToolbarButton,
5407
5507
  {
5408
5508
  label: "Redo (\u21E7\u2318Z)",
5409
5509
  hint: canRedo ? void 0 : "Nothing to redo",
5410
5510
  disabled: !canRedo,
5411
5511
  onClick: onRedo,
5412
- children: /* @__PURE__ */ jsx9(Redo, { className: "h-4 w-4" })
5512
+ children: /* @__PURE__ */ jsx10(Redo, { className: "h-4 w-4" })
5413
5513
  }
5414
5514
  )
5415
5515
  ] }),
5416
- /* @__PURE__ */ jsxs6(Toolbar, { children: [
5417
- /* @__PURE__ */ jsx9(
5516
+ /* @__PURE__ */ jsxs7(Toolbar, { children: [
5517
+ /* @__PURE__ */ jsx10(
5418
5518
  ToolbarButton,
5419
5519
  {
5420
5520
  label: "Fit view (\u21E71)",
5421
5521
  onClick: () => void fitView({ ...fitOptions, duration: 500 }),
5422
- children: /* @__PURE__ */ jsx9(Maximize, { className: "h-4 w-4" })
5522
+ children: /* @__PURE__ */ jsx10(Maximize, { className: "h-4 w-4" })
5423
5523
  }
5424
5524
  ),
5425
- /* @__PURE__ */ jsx9(
5525
+ /* @__PURE__ */ jsx10(
5426
5526
  ToolbarButton,
5427
5527
  {
5428
5528
  label: reorderLabel,
5429
5529
  hint: locked ? "The canvas is locked" : void 0,
5430
5530
  disabled: locked,
5431
5531
  onClick: onReorder,
5432
- children: /* @__PURE__ */ jsx9(SendToBack2, { className: "h-4 w-4" })
5532
+ children: /* @__PURE__ */ jsx10(SendToBack2, { className: "h-4 w-4" })
5433
5533
  }
5434
5534
  )
5435
5535
  ] }),
5436
- comments && /* @__PURE__ */ jsxs6(Toolbar, { children: [
5437
- /* @__PURE__ */ jsx9(
5536
+ comments && /* @__PURE__ */ jsxs7(Toolbar, { children: [
5537
+ /* @__PURE__ */ jsx10(
5438
5538
  ToolbarButton,
5439
5539
  {
5440
5540
  label: comments.open ? `Comments (${comments.open} open)` : "Comments",
5441
5541
  active: comments.active,
5442
5542
  onClick: comments.onToggle,
5443
- children: /* @__PURE__ */ jsxs6("span", { className: "relative", children: [
5444
- /* @__PURE__ */ jsx9(MessageSquareText, { className: "h-4 w-4" }),
5445
- comments.open > 0 && /* @__PURE__ */ jsx9("span", { className: "absolute -right-2 -top-2 min-w-4 rounded-full bg-[rgb(var(--ec-accent))] px-1 text-center text-[9px] font-semibold leading-4 text-white", children: comments.open })
5543
+ children: /* @__PURE__ */ jsxs7("span", { className: "relative", children: [
5544
+ /* @__PURE__ */ jsx10(MessageSquareText, { className: "h-4 w-4" }),
5545
+ comments.open > 0 && /* @__PURE__ */ jsx10("span", { className: "absolute -right-2 -top-2 min-w-4 rounded-full bg-[rgb(var(--ec-accent))] px-1 text-center text-[9px] font-semibold leading-4 text-white", children: comments.open })
5446
5546
  ] })
5447
5547
  }
5448
5548
  ),
5449
- hotspots && /* @__PURE__ */ jsx9(
5549
+ hotspots && /* @__PURE__ */ jsx10(
5450
5550
  ToolbarButton,
5451
5551
  {
5452
5552
  label: hotspots.count ? `Hotspots (${hotspots.count})` : "Hotspots",
5453
5553
  active: hotspots.active,
5454
5554
  onClick: hotspots.onToggle,
5455
- children: /* @__PURE__ */ jsxs6("span", { className: "relative", children: [
5456
- /* @__PURE__ */ jsx9(TriangleAlert3, { className: "h-4 w-4" }),
5457
- hotspots.count > 0 && /* @__PURE__ */ jsx9(
5555
+ children: /* @__PURE__ */ jsxs7("span", { className: "relative", children: [
5556
+ /* @__PURE__ */ jsx10(TriangleAlert3, { className: "h-4 w-4" }),
5557
+ hotspots.count > 0 && /* @__PURE__ */ jsx10(
5458
5558
  "span",
5459
5559
  {
5460
5560
  className: "absolute -right-2 -top-2 min-w-4 rounded-full px-1 text-center text-[9px] font-semibold leading-4 text-white",
@@ -5472,12 +5572,12 @@ var ViewControls = memo6(function ViewControls2({
5472
5572
  });
5473
5573
 
5474
5574
  // src/studio/components/ContainerChooser.tsx
5475
- import { useEffect as useEffect6, useState as useState8 } from "react";
5476
- import { X as X3 } from "lucide-react";
5477
- import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
5575
+ import { useEffect as useEffect8, useState as useState10 } from "react";
5576
+ import { X as X4 } from "lucide-react";
5577
+ import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
5478
5578
  var plural = (count, noun) => `${count} ${noun}${count === 1 ? "" : "s"}`;
5479
- var CardPreview = () => /* @__PURE__ */ jsxs7("svg", { viewBox: "0 0 64 36", className: "h-9 w-16", "aria-hidden": true, children: [
5480
- /* @__PURE__ */ jsx10(
5579
+ var CardPreview = () => /* @__PURE__ */ jsxs8("svg", { viewBox: "0 0 64 36", className: "h-9 w-16", "aria-hidden": true, children: [
5580
+ /* @__PURE__ */ jsx11(
5481
5581
  "rect",
5482
5582
  {
5483
5583
  x: "18",
@@ -5492,7 +5592,7 @@ var CardPreview = () => /* @__PURE__ */ jsxs7("svg", { viewBox: "0 0 64 36", cla
5492
5592
  strokeWidth: "1.5"
5493
5593
  }
5494
5594
  ),
5495
- /* @__PURE__ */ jsx10(
5595
+ /* @__PURE__ */ jsx11(
5496
5596
  "rect",
5497
5597
  {
5498
5598
  x: "23",
@@ -5504,7 +5604,7 @@ var CardPreview = () => /* @__PURE__ */ jsxs7("svg", { viewBox: "0 0 64 36", cla
5504
5604
  fillOpacity: "0.6"
5505
5605
  }
5506
5606
  ),
5507
- /* @__PURE__ */ jsx10(
5607
+ /* @__PURE__ */ jsx11(
5508
5608
  "rect",
5509
5609
  {
5510
5610
  x: "23",
@@ -5516,7 +5616,7 @@ var CardPreview = () => /* @__PURE__ */ jsxs7("svg", { viewBox: "0 0 64 36", cla
5516
5616
  fillOpacity: "0.35"
5517
5617
  }
5518
5618
  ),
5519
- /* @__PURE__ */ jsx10(
5619
+ /* @__PURE__ */ jsx11(
5520
5620
  "path",
5521
5621
  {
5522
5622
  d: "M46 18h12",
@@ -5526,7 +5626,7 @@ var CardPreview = () => /* @__PURE__ */ jsxs7("svg", { viewBox: "0 0 64 36", cla
5526
5626
  strokeDasharray: "2 2"
5527
5627
  }
5528
5628
  ),
5529
- /* @__PURE__ */ jsx10(
5629
+ /* @__PURE__ */ jsx11(
5530
5630
  "rect",
5531
5631
  {
5532
5632
  x: "57",
@@ -5539,8 +5639,8 @@ var CardPreview = () => /* @__PURE__ */ jsxs7("svg", { viewBox: "0 0 64 36", cla
5539
5639
  }
5540
5640
  )
5541
5641
  ] });
5542
- var ContainerPreview = () => /* @__PURE__ */ jsxs7("svg", { viewBox: "0 0 64 36", className: "h-9 w-16", "aria-hidden": true, children: [
5543
- /* @__PURE__ */ jsx10(
5642
+ var ContainerPreview = () => /* @__PURE__ */ jsxs8("svg", { viewBox: "0 0 64 36", className: "h-9 w-16", "aria-hidden": true, children: [
5643
+ /* @__PURE__ */ jsx11(
5544
5644
  "rect",
5545
5645
  {
5546
5646
  x: "4",
@@ -5555,7 +5655,7 @@ var ContainerPreview = () => /* @__PURE__ */ jsxs7("svg", { viewBox: "0 0 64 36"
5555
5655
  strokeWidth: "1.5"
5556
5656
  }
5557
5657
  ),
5558
- /* @__PURE__ */ jsx10(
5658
+ /* @__PURE__ */ jsx11(
5559
5659
  "path",
5560
5660
  {
5561
5661
  d: "M4 10h56",
@@ -5564,7 +5664,7 @@ var ContainerPreview = () => /* @__PURE__ */ jsxs7("svg", { viewBox: "0 0 64 36"
5564
5664
  strokeWidth: "1"
5565
5665
  }
5566
5666
  ),
5567
- /* @__PURE__ */ jsx10(
5667
+ /* @__PURE__ */ jsx11(
5568
5668
  "rect",
5569
5669
  {
5570
5670
  x: "8",
@@ -5576,7 +5676,7 @@ var ContainerPreview = () => /* @__PURE__ */ jsxs7("svg", { viewBox: "0 0 64 36"
5576
5676
  fillOpacity: "0.6"
5577
5677
  }
5578
5678
  ),
5579
- /* @__PURE__ */ jsx10(
5679
+ /* @__PURE__ */ jsx11(
5580
5680
  "rect",
5581
5681
  {
5582
5682
  x: "10",
@@ -5588,7 +5688,7 @@ var ContainerPreview = () => /* @__PURE__ */ jsxs7("svg", { viewBox: "0 0 64 36"
5588
5688
  fillOpacity: "0.5"
5589
5689
  }
5590
5690
  ),
5591
- /* @__PURE__ */ jsx10(
5691
+ /* @__PURE__ */ jsx11(
5592
5692
  "rect",
5593
5693
  {
5594
5694
  x: "36",
@@ -5623,12 +5723,12 @@ function ContainerChooser({
5623
5723
  onChoose,
5624
5724
  onCancel
5625
5725
  }) {
5626
- const [withContents, setWithContents] = useState8(true);
5726
+ const [withContents, setWithContents] = useState10(true);
5627
5727
  const contentsLabel = contents ? [
5628
5728
  contents.systems > 0 && plural(contents.systems, "system"),
5629
5729
  contents.services > 0 && plural(contents.services, "service")
5630
5730
  ].filter(Boolean).join(" and ") : "";
5631
- useEffect6(() => {
5731
+ useEffect8(() => {
5632
5732
  const onKeyDown = (event) => event.key === "Escape" && onCancel();
5633
5733
  window.addEventListener("keydown", onKeyDown);
5634
5734
  return () => window.removeEventListener("keydown", onKeyDown);
@@ -5641,7 +5741,7 @@ function ContainerChooser({
5641
5741
  Math.max(position.y - 20, 12),
5642
5742
  window.innerHeight - (contentsLabel ? 260 : 200)
5643
5743
  );
5644
- return /* @__PURE__ */ jsx10("div", { className: "fixed inset-0 z-50", onPointerDown: onCancel, children: /* @__PURE__ */ jsxs7(
5744
+ return /* @__PURE__ */ jsx11("div", { className: "fixed inset-0 z-50", onPointerDown: onCancel, children: /* @__PURE__ */ jsxs8(
5645
5745
  "div",
5646
5746
  {
5647
5747
  role: "dialog",
@@ -5650,26 +5750,26 @@ function ContainerChooser({
5650
5750
  className: "absolute w-80 rounded-lg border p-1.5 shadow-xl bg-[rgb(var(--ec-card-bg))] border-[rgb(var(--ec-page-border))] text-[rgb(var(--ec-page-text))]",
5651
5751
  style: { left, top },
5652
5752
  children: [
5653
- /* @__PURE__ */ jsxs7("div", { className: "flex items-start justify-between gap-2 px-2 pb-1.5 pt-1", children: [
5654
- /* @__PURE__ */ jsxs7("div", { className: "min-w-0", children: [
5655
- /* @__PURE__ */ jsxs7("p", { className: "text-[10px] font-semibold uppercase tracking-wider text-[rgb(var(--ec-page-text-muted))]", children: [
5753
+ /* @__PURE__ */ jsxs8("div", { className: "flex items-start justify-between gap-2 px-2 pb-1.5 pt-1", children: [
5754
+ /* @__PURE__ */ jsxs8("div", { className: "min-w-0", children: [
5755
+ /* @__PURE__ */ jsxs8("p", { className: "text-[10px] font-semibold uppercase tracking-wider text-[rgb(var(--ec-page-text-muted))]", children: [
5656
5756
  "Add this ",
5657
5757
  kind,
5658
5758
  " as"
5659
5759
  ] }),
5660
- name && /* @__PURE__ */ jsx10("p", { className: "truncate text-xs font-semibold", children: name })
5760
+ name && /* @__PURE__ */ jsx11("p", { className: "truncate text-xs font-semibold", children: name })
5661
5761
  ] }),
5662
- /* @__PURE__ */ jsx10(
5762
+ /* @__PURE__ */ jsx11(
5663
5763
  "button",
5664
5764
  {
5665
5765
  onClick: onCancel,
5666
5766
  "aria-label": "Cancel",
5667
5767
  className: "rounded p-0.5 text-[rgb(var(--ec-icon-color))] hover:bg-[rgb(var(--ec-page-border)/0.5)]",
5668
- children: /* @__PURE__ */ jsx10(X3, { size: 14 })
5768
+ children: /* @__PURE__ */ jsx11(X4, { size: 14 })
5669
5769
  }
5670
5770
  )
5671
5771
  ] }),
5672
- /* @__PURE__ */ jsx10("div", { className: "grid grid-cols-2 gap-1.5 px-0.5 pb-0.5", children: OPTIONS.map(({ as, label, hint, Preview }) => /* @__PURE__ */ jsxs7(
5772
+ /* @__PURE__ */ jsx11("div", { className: "grid grid-cols-2 gap-1.5 px-0.5 pb-0.5", children: OPTIONS.map(({ as, label, hint, Preview }) => /* @__PURE__ */ jsxs8(
5673
5773
  "button",
5674
5774
  {
5675
5775
  autoFocus: as === "container",
@@ -5678,15 +5778,15 @@ function ContainerChooser({
5678
5778
  ),
5679
5779
  className: "flex flex-col items-center gap-1 rounded-md border px-2 pb-1.5 pt-2 text-xs outline-none transition-colors border-[rgb(var(--ec-page-border))] text-[rgb(var(--ec-page-text-muted))] hover:border-[rgb(var(--ec-accent))] hover:bg-[color-mix(in_srgb,rgb(var(--ec-accent))_8%,transparent)] hover:text-[rgb(var(--ec-accent))] focus-visible:border-[rgb(var(--ec-accent))] focus-visible:text-[rgb(var(--ec-accent))]",
5680
5780
  children: [
5681
- /* @__PURE__ */ jsx10(Preview, {}),
5682
- /* @__PURE__ */ jsx10("span", { className: "font-semibold", children: label }),
5683
- /* @__PURE__ */ jsx10("span", { className: "text-center text-[10px] leading-tight text-[rgb(var(--ec-page-text-muted))]", children: hint })
5781
+ /* @__PURE__ */ jsx11(Preview, {}),
5782
+ /* @__PURE__ */ jsx11("span", { className: "font-semibold", children: label }),
5783
+ /* @__PURE__ */ jsx11("span", { className: "text-center text-[10px] leading-tight text-[rgb(var(--ec-page-text-muted))]", children: hint })
5684
5784
  ]
5685
5785
  },
5686
5786
  as
5687
5787
  )) }),
5688
- contentsLabel && /* @__PURE__ */ jsxs7("label", { className: "mt-1 flex items-center gap-2 rounded-md px-2 py-1.5 text-[11px] text-[rgb(var(--ec-page-text-muted))]", children: [
5689
- /* @__PURE__ */ jsx10(
5788
+ contentsLabel && /* @__PURE__ */ jsxs8("label", { className: "mt-1 flex items-center gap-2 rounded-md px-2 py-1.5 text-[11px] text-[rgb(var(--ec-page-text-muted))]", children: [
5789
+ /* @__PURE__ */ jsx11(
5690
5790
  "input",
5691
5791
  {
5692
5792
  type: "checkbox",
@@ -5704,29 +5804,29 @@ function ContainerChooser({
5704
5804
  }
5705
5805
 
5706
5806
  // src/studio/components/EditButton.tsx
5707
- import { memo as memo7 } from "react";
5708
- import { NodeToolbar, Position as Position3, useStore } from "@xyflow/react";
5807
+ import { memo as memo8 } from "react";
5808
+ import { NodeToolbar, Position as Position4, useStore } from "@xyflow/react";
5709
5809
  import { Info as Info2, Pencil as Pencil3 } from "lucide-react";
5710
- import { Fragment as Fragment6, jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
5810
+ import { Fragment as Fragment8, jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
5711
5811
  var MIN_SCALE = 0.4;
5712
5812
  var MAX_SCALE = 1.6;
5713
5813
  var OFFSET = 8;
5714
- var EditButton_default = memo7(function EditButton({
5814
+ var EditButton_default = memo8(function EditButton({
5715
5815
  nodeId,
5716
5816
  locked,
5717
5817
  onClick
5718
5818
  }) {
5719
5819
  const zoom = useStore((state) => state.transform[2]);
5720
5820
  const scale = Math.min(MAX_SCALE, Math.max(MIN_SCALE, zoom));
5721
- return /* @__PURE__ */ jsx11(
5821
+ return /* @__PURE__ */ jsx12(
5722
5822
  NodeToolbar,
5723
5823
  {
5724
5824
  nodeId,
5725
5825
  isVisible: true,
5726
- position: Position3.Top,
5826
+ position: Position4.Top,
5727
5827
  align: "end",
5728
5828
  offset: OFFSET * scale,
5729
- children: /* @__PURE__ */ jsx11(
5829
+ children: /* @__PURE__ */ jsx12(
5730
5830
  "button",
5731
5831
  {
5732
5832
  type: "button",
@@ -5736,11 +5836,11 @@ var EditButton_default = memo7(function EditButton({
5736
5836
  transformOrigin: "bottom right"
5737
5837
  },
5738
5838
  onClick,
5739
- children: locked ? /* @__PURE__ */ jsxs8(Fragment6, { children: [
5740
- /* @__PURE__ */ jsx11(Info2, { "aria-hidden": true }),
5839
+ children: locked ? /* @__PURE__ */ jsxs9(Fragment8, { children: [
5840
+ /* @__PURE__ */ jsx12(Info2, { "aria-hidden": true }),
5741
5841
  " Details"
5742
- ] }) : /* @__PURE__ */ jsxs8(Fragment6, { children: [
5743
- /* @__PURE__ */ jsx11(Pencil3, { "aria-hidden": true }),
5842
+ ] }) : /* @__PURE__ */ jsxs9(Fragment8, { children: [
5843
+ /* @__PURE__ */ jsx12(Pencil3, { "aria-hidden": true }),
5744
5844
  " Edit"
5745
5845
  ] })
5746
5846
  }
@@ -5751,14 +5851,14 @@ var EditButton_default = memo7(function EditButton({
5751
5851
 
5752
5852
  // src/studio/components/Palette.tsx
5753
5853
  import {
5754
- memo as memo8,
5755
- useCallback as useCallback4,
5756
- useEffect as useEffect7,
5757
- useRef as useRef6,
5758
- useState as useState9
5854
+ memo as memo9,
5855
+ useCallback as useCallback5,
5856
+ useEffect as useEffect9,
5857
+ useRef as useRef8,
5858
+ useState as useState11
5759
5859
  } from "react";
5760
5860
  import { ChevronDown, GripVertical as GripVertical2 } from "lucide-react";
5761
- import { Fragment as Fragment7, jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
5861
+ import { Fragment as Fragment9, jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
5762
5862
  var COMPONENT_DRAG_TYPE = "application/eventcatalog-studio";
5763
5863
  var listedDefinitions = NODE_CATEGORIES.map((category) => ({
5764
5864
  ...category,
@@ -5802,7 +5902,7 @@ function PaletteItem({
5802
5902
  title,
5803
5903
  trailing
5804
5904
  }) {
5805
- return /* @__PURE__ */ jsxs9(
5905
+ return /* @__PURE__ */ jsxs10(
5806
5906
  "button",
5807
5907
  {
5808
5908
  type: "button",
@@ -5814,13 +5914,13 @@ function PaletteItem({
5814
5914
  title,
5815
5915
  className: `group flex w-full items-center gap-2.5 rounded-lg border border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-card-bg))] py-1 pl-1 pr-2 text-left text-[rgb(var(--ec-page-text))] shadow-[0_1px_2px_rgb(0_0_0/0.05)] transition-[transform,box-shadow,border-color] duration-150 ${usable ? "cursor-grab hover:-translate-y-px hover:border-[color-mix(in_srgb,rgb(var(--ec-accent))_45%,transparent)]! hover:shadow-[0_4px_12px_rgb(0_0_0/0.08)] active:translate-y-0 active:cursor-grabbing" : "cursor-not-allowed opacity-40 grayscale"}`,
5816
5916
  children: [
5817
- /* @__PURE__ */ jsx12("span", { className: "flex h-8 w-8 flex-none items-center justify-center rounded-md bg-[rgb(var(--ec-content-hover))]", children: /* @__PURE__ */ jsx12(Icon, { size: 16, className: iconClassName }) }),
5818
- /* @__PURE__ */ jsxs9("span", { className: "min-w-0 flex-1", children: [
5819
- /* @__PURE__ */ jsx12("span", { className: "block truncate text-[13px] font-medium leading-tight", children: label }),
5820
- description && /* @__PURE__ */ jsx12("span", { className: "block truncate text-[11px] leading-snug text-[rgb(var(--ec-page-text-muted))]", children: description })
5917
+ /* @__PURE__ */ jsx13("span", { className: "flex h-8 w-8 flex-none items-center justify-center rounded-md bg-[rgb(var(--ec-content-hover))]", children: /* @__PURE__ */ jsx13(Icon, { size: 16, className: iconClassName }) }),
5918
+ /* @__PURE__ */ jsxs10("span", { className: "min-w-0 flex-1", children: [
5919
+ /* @__PURE__ */ jsx13("span", { className: "block truncate text-[13px] font-medium leading-tight", children: label }),
5920
+ description && /* @__PURE__ */ jsx13("span", { className: "block truncate text-[11px] leading-snug text-[rgb(var(--ec-page-text-muted))]", children: description })
5821
5921
  ] }),
5822
5922
  trailing ?? (usable && onDragStart && // It's picked up and dragged on (a click adds it in the middle): a small handle says so
5823
- /* @__PURE__ */ jsx12(
5923
+ /* @__PURE__ */ jsx13(
5824
5924
  GripVertical2,
5825
5925
  {
5826
5926
  "aria-hidden": true,
@@ -5837,19 +5937,19 @@ function PaletteSection({
5837
5937
  divided = false,
5838
5938
  children
5839
5939
  }) {
5840
- return /* @__PURE__ */ jsxs9(
5940
+ return /* @__PURE__ */ jsxs10(
5841
5941
  "section",
5842
5942
  {
5843
5943
  className: divided ? "border-t border-[rgb(var(--ec-page-border))] pt-3" : "",
5844
5944
  children: [
5845
- /* @__PURE__ */ jsx12("h3", { className: "mb-1.5 text-[11px] font-medium text-[rgb(var(--ec-page-text-muted))]", children: title }),
5846
- /* @__PURE__ */ jsx12("div", { className: "space-y-1.5", children })
5945
+ /* @__PURE__ */ jsx13("h3", { className: "mb-1.5 text-[11px] font-medium text-[rgb(var(--ec-page-text-muted))]", children: title }),
5946
+ /* @__PURE__ */ jsx13("div", { className: "space-y-1.5", children })
5847
5947
  ]
5848
5948
  }
5849
5949
  );
5850
5950
  }
5851
5951
  var COMPONENTS_TAB = "components";
5852
- var Palette = memo8(function Palette2({
5952
+ var Palette = memo9(function Palette2({
5853
5953
  level,
5854
5954
  onAddComponent,
5855
5955
  footer,
@@ -5859,7 +5959,7 @@ var Palette = memo8(function Palette2({
5859
5959
  startCollapsed
5860
5960
  }) {
5861
5961
  const { startDrag, ghost } = useDragGhost();
5862
- const [collapsed, setCollapsed] = useState9(
5962
+ const [collapsed, setCollapsed] = useState11(
5863
5963
  () => startCollapsed ?? readCollapsed()
5864
5964
  );
5865
5965
  const remember = (next) => {
@@ -5869,13 +5969,13 @@ var Palette = memo8(function Palette2({
5869
5969
  } catch {
5870
5970
  }
5871
5971
  };
5872
- const toggle = useCallback4(() => {
5972
+ const toggle = useCallback5(() => {
5873
5973
  setCollapsed((current) => {
5874
5974
  remember(!current);
5875
5975
  return !current;
5876
5976
  });
5877
5977
  }, []);
5878
- const [ownTab, setOwnTab] = useState9(COMPONENTS_TAB);
5978
+ const [ownTab, setOwnTab] = useState11(COMPONENTS_TAB);
5879
5979
  const shown = tab ?? (tabs?.some((candidate) => candidate.id === ownTab) ? ownTab : COMPONENTS_TAB);
5880
5980
  const choose = (next) => {
5881
5981
  setOwnTab(next);
@@ -5885,8 +5985,8 @@ var Palette = memo8(function Palette2({
5885
5985
  remember(false);
5886
5986
  }
5887
5987
  };
5888
- const chosen = useRef6(tab);
5889
- useEffect7(() => {
5988
+ const chosen = useRef8(tab);
5989
+ useEffect9(() => {
5890
5990
  if (tab === chosen.current) return;
5891
5991
  chosen.current = tab;
5892
5992
  if (tab === void 0 || !collapsed) return;
@@ -5902,7 +6002,7 @@ var Palette = memo8(function Palette2({
5902
6002
  const { label, summary, firstLevel } = definition;
5903
6003
  const key = componentKey(definition);
5904
6004
  const { icon, className } = NODE_ICONS[key] ?? NODE_ICONS[definition.type];
5905
- return /* @__PURE__ */ jsx12(
6005
+ return /* @__PURE__ */ jsx13(
5906
6006
  PaletteItem,
5907
6007
  {
5908
6008
  icon,
@@ -5921,18 +6021,18 @@ var Palette = memo8(function Palette2({
5921
6021
  key
5922
6022
  );
5923
6023
  };
5924
- const components2 = /* @__PURE__ */ jsxs9(Fragment7, { children: [
6024
+ const components2 = /* @__PURE__ */ jsxs10(Fragment9, { children: [
5925
6025
  listedDefinitions.map((category) => {
5926
6026
  const definitions = category.definitions.filter(
5927
6027
  (definition) => isShownOnLevel(definition.type, level)
5928
6028
  );
5929
6029
  if (!definitions.length) return null;
5930
- return /* @__PURE__ */ jsx12(PaletteSection, { title: category.label, children: definitions.map((definition) => tile(definition)) }, category.id);
6030
+ return /* @__PURE__ */ jsx13(PaletteSection, { title: category.label, children: definitions.map((definition) => tile(definition)) }, category.id);
5931
6031
  }),
5932
- unavailable.length > 0 && /* @__PURE__ */ jsx12(PaletteSection, { title: `Not on Level ${level}`, divided: true, children: unavailable.map((definition) => tile(definition, false)) })
6032
+ unavailable.length > 0 && /* @__PURE__ */ jsx13(PaletteSection, { title: `Not on Level ${level}`, divided: true, children: unavailable.map((definition) => tile(definition, false)) })
5933
6033
  ] });
5934
6034
  const extra = tabs?.find((candidate) => candidate.id === shown);
5935
- const tabButton = (id, label, badge) => /* @__PURE__ */ jsxs9(
6035
+ const tabButton = (id, label, badge) => /* @__PURE__ */ jsxs10(
5936
6036
  "button",
5937
6037
  {
5938
6038
  type: "button",
@@ -5942,18 +6042,18 @@ var Palette = memo8(function Palette2({
5942
6042
  className: `flex flex-1 items-center justify-center gap-1 whitespace-nowrap rounded-md px-1.5 py-1 text-xs font-medium ${shown === id && !collapsed ? "bg-[rgb(var(--ec-card-bg))] text-[rgb(var(--ec-page-text))] shadow-sm" : "text-[rgb(var(--ec-page-text-muted))] hover:text-[rgb(var(--ec-page-text))]"}`,
5943
6043
  children: [
5944
6044
  label,
5945
- !!badge && /* @__PURE__ */ jsx12("span", { className: "rounded-full bg-[rgb(var(--ec-accent))] px-1.5 text-[10px] leading-4 text-white", children: badge })
6045
+ !!badge && /* @__PURE__ */ jsx13("span", { className: "rounded-full bg-[rgb(var(--ec-accent))] px-1.5 text-[10px] leading-4 text-white", children: badge })
5946
6046
  ]
5947
6047
  },
5948
6048
  id
5949
6049
  );
5950
- return /* @__PURE__ */ jsxs9(
6050
+ return /* @__PURE__ */ jsxs10(
5951
6051
  "div",
5952
6052
  {
5953
6053
  className: `absolute left-3 top-[62px] z-10 flex w-[264px] flex-col ${collapsed ? "" : "bottom-[68px]"} rounded-xl border border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-card-bg))] text-[rgb(var(--ec-page-text))] shadow-[0_8px_24px_rgb(0_0_0/0.08),0_1px_3px_rgb(0_0_0/0.05)]`,
5954
6054
  children: [
5955
- tabs?.length ? /* @__PURE__ */ jsxs9("div", { className: "flex flex-none items-center gap-1 p-2", children: [
5956
- /* @__PURE__ */ jsxs9(
6055
+ tabs?.length ? /* @__PURE__ */ jsxs10("div", { className: "flex flex-none items-center gap-1 p-2", children: [
6056
+ /* @__PURE__ */ jsxs10(
5957
6057
  "div",
5958
6058
  {
5959
6059
  role: "tablist",
@@ -5964,7 +6064,7 @@ var Palette = memo8(function Palette2({
5964
6064
  ]
5965
6065
  }
5966
6066
  ),
5967
- /* @__PURE__ */ jsx12(
6067
+ /* @__PURE__ */ jsx13(
5968
6068
  "button",
5969
6069
  {
5970
6070
  type: "button",
@@ -5972,7 +6072,7 @@ var Palette = memo8(function Palette2({
5972
6072
  "aria-expanded": !collapsed,
5973
6073
  "aria-label": collapsed ? "Show the palette" : "Fold the palette away",
5974
6074
  className: "flex-none rounded-md p-1 text-[rgb(var(--ec-page-text-muted))] hover:bg-[rgb(var(--ec-page-border)/0.5)]",
5975
- children: /* @__PURE__ */ jsx12(
6075
+ children: /* @__PURE__ */ jsx13(
5976
6076
  ChevronDown,
5977
6077
  {
5978
6078
  "aria-hidden": true,
@@ -5981,7 +6081,7 @@ var Palette = memo8(function Palette2({
5981
6081
  )
5982
6082
  }
5983
6083
  )
5984
- ] }) : /* @__PURE__ */ jsxs9(
6084
+ ] }) : /* @__PURE__ */ jsxs10(
5985
6085
  "button",
5986
6086
  {
5987
6087
  type: "button",
@@ -5989,8 +6089,8 @@ var Palette = memo8(function Palette2({
5989
6089
  "aria-expanded": !collapsed,
5990
6090
  className: "flex flex-none items-center justify-between rounded-xl px-3.5 py-2.5 text-left text-[13px] font-semibold hover:bg-[rgb(var(--ec-content-hover))]!",
5991
6091
  children: [
5992
- /* @__PURE__ */ jsx12("span", { children: "Resources" }),
5993
- /* @__PURE__ */ jsx12(
6092
+ /* @__PURE__ */ jsx13("span", { children: "Resources" }),
6093
+ /* @__PURE__ */ jsx13(
5994
6094
  ChevronDown,
5995
6095
  {
5996
6096
  "aria-hidden": true,
@@ -6000,8 +6100,8 @@ var Palette = memo8(function Palette2({
6000
6100
  ]
6001
6101
  }
6002
6102
  ),
6003
- !collapsed && /* @__PURE__ */ jsx12("div", { className: "min-h-0 flex-1 space-y-3 overflow-y-auto px-3 pb-3", children: extra ? extra.render(startDrag) : components2 }),
6004
- !collapsed && footer && /* @__PURE__ */ jsx12("div", { className: "flex-none border-t border-[rgb(var(--ec-page-border))] px-3 py-2.5", children: footer }),
6103
+ !collapsed && /* @__PURE__ */ jsx13("div", { className: "min-h-0 flex-1 space-y-3 overflow-y-auto px-3 pb-3", children: extra ? extra.render(startDrag) : components2 }),
6104
+ !collapsed && footer && /* @__PURE__ */ jsx13("div", { className: "flex-none border-t border-[rgb(var(--ec-page-border))] px-3 py-2.5", children: footer }),
6005
6105
  ghost
6006
6106
  ]
6007
6107
  }
@@ -6009,7 +6109,7 @@ var Palette = memo8(function Palette2({
6009
6109
  });
6010
6110
 
6011
6111
  // src/studio/components/Shortcuts.tsx
6012
- import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
6112
+ import { jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
6013
6113
  var isMac = typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform);
6014
6114
  var MOD = isMac ? "\u2318" : "Ctrl";
6015
6115
  var SHORTCUTS = [
@@ -6060,18 +6160,18 @@ var SHORTCUTS = [
6060
6160
  }
6061
6161
  ];
6062
6162
  function ShortcutsList({ omit = [] }) {
6063
- return /* @__PURE__ */ jsx13("div", { className: "grid min-h-0 gap-x-8 gap-y-5 overflow-y-auto px-5 py-4 md:grid-cols-2!", children: SHORTCUTS.map(({ group, items }) => ({
6163
+ return /* @__PURE__ */ jsx14("div", { className: "grid min-h-0 gap-x-8 gap-y-5 overflow-y-auto px-5 py-4 md:grid-cols-2!", children: SHORTCUTS.map(({ group, items }) => ({
6064
6164
  group,
6065
6165
  items: items.filter(([label]) => !omit.includes(label))
6066
- })).map(({ group, items }) => /* @__PURE__ */ jsxs10("section", { children: [
6067
- /* @__PURE__ */ jsx13("h3", { className: "mb-2 text-[11px] font-semibold uppercase tracking-wide text-[rgb(var(--ec-page-text-muted))]", children: group }),
6068
- /* @__PURE__ */ jsx13("ul", { className: "divide-y divide-[rgb(var(--ec-page-border))]", children: items.map(([label, keys]) => /* @__PURE__ */ jsxs10(
6166
+ })).map(({ group, items }) => /* @__PURE__ */ jsxs11("section", { children: [
6167
+ /* @__PURE__ */ jsx14("h3", { className: "mb-2 text-[11px] font-semibold uppercase tracking-wide text-[rgb(var(--ec-page-text-muted))]", children: group }),
6168
+ /* @__PURE__ */ jsx14("ul", { className: "divide-y divide-[rgb(var(--ec-page-border))]", children: items.map(([label, keys]) => /* @__PURE__ */ jsxs11(
6069
6169
  "li",
6070
6170
  {
6071
6171
  className: "flex items-center justify-between gap-3 py-1.5 text-sm",
6072
6172
  children: [
6073
- /* @__PURE__ */ jsx13("span", { children: label }),
6074
- /* @__PURE__ */ jsx13("span", { className: "flex gap-1", children: keys.map((key) => /* @__PURE__ */ jsx13(
6173
+ /* @__PURE__ */ jsx14("span", { children: label }),
6174
+ /* @__PURE__ */ jsx14("span", { className: "flex gap-1", children: keys.map((key) => /* @__PURE__ */ jsx14(
6075
6175
  "kbd",
6076
6176
  {
6077
6177
  className: "min-w-6 rounded-md border border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-content-hover))] px-1.5 py-0.5 text-center font-sans text-xs text-[rgb(var(--ec-page-text-muted))]",
@@ -6087,9 +6187,9 @@ function ShortcutsList({ omit = [] }) {
6087
6187
  }
6088
6188
 
6089
6189
  // src/studio/components/EmptyCanvas.tsx
6090
- import { useEffect as useEffect8, useState as useState10 } from "react";
6190
+ import { useEffect as useEffect10, useState as useState12 } from "react";
6091
6191
  import { CircleHelp, FolderOpen, Plug } from "lucide-react";
6092
- import { jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
6192
+ import { jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
6093
6193
  var hintText = "font-[Excalifont,Inter,sans-serif] text-[14px] leading-snug text-[color-mix(in_srgb,rgb(var(--ec-page-text))_22%,transparent)]";
6094
6194
  var arrow = {
6095
6195
  fill: "none",
@@ -6099,24 +6199,24 @@ var arrow = {
6099
6199
  strokeLinejoin: "round"
6100
6200
  };
6101
6201
  function Hints({ palette, live }) {
6102
- return /* @__PURE__ */ jsxs11("div", { "aria-hidden": true, className: `hidden md:block! ${hintText}`, children: [
6103
- palette && /* @__PURE__ */ jsxs11("div", { className: "absolute bottom-[120px] left-[290px] flex items-start gap-1", children: [
6104
- /* @__PURE__ */ jsxs11("svg", { width: "56", height: "32", viewBox: "0 0 70 40", ...arrow, children: [
6105
- /* @__PURE__ */ jsx14("path", { d: "M66 8 C 45 4, 22 10, 6 26" }),
6106
- /* @__PURE__ */ jsx14("path", { d: "M6 26 L15.7 23.4 M6 26 L8.6 16.3" })
6202
+ return /* @__PURE__ */ jsxs12("div", { "aria-hidden": true, className: `hidden md:block! ${hintText}`, children: [
6203
+ palette && /* @__PURE__ */ jsxs12("div", { className: "absolute bottom-[120px] left-[290px] flex items-start gap-1", children: [
6204
+ /* @__PURE__ */ jsxs12("svg", { width: "56", height: "32", viewBox: "0 0 70 40", ...arrow, children: [
6205
+ /* @__PURE__ */ jsx15("path", { d: "M66 8 C 45 4, 22 10, 6 26" }),
6206
+ /* @__PURE__ */ jsx15("path", { d: "M6 26 L15.7 23.4 M6 26 L8.6 16.3" })
6107
6207
  ] }),
6108
- /* @__PURE__ */ jsx14("p", { className: "-mt-0.5 max-w-[160px]", children: "Drag resources onto the canvas, then connect them" })
6208
+ /* @__PURE__ */ jsx15("p", { className: "-mt-0.5 max-w-[160px]", children: "Drag resources onto the canvas, then connect them" })
6109
6209
  ] }),
6110
- /* @__PURE__ */ jsxs11("div", { className: "absolute left-[calc(50%+6px)] top-[66px] flex -translate-x-1/2 flex-col items-center", children: [
6111
- /* @__PURE__ */ jsxs11("svg", { width: "32", height: "45", viewBox: "0 0 40 56", ...arrow, children: [
6112
- /* @__PURE__ */ jsx14("path", { d: "M14 54 C 6 38, 10 18, 20 4" }),
6113
- /* @__PURE__ */ jsx14("path", { d: "M20 4 L11.8 7.7 M20 4 L19.1 13" })
6210
+ /* @__PURE__ */ jsxs12("div", { className: "absolute left-[calc(50%+6px)] top-[66px] flex -translate-x-1/2 flex-col items-center", children: [
6211
+ /* @__PURE__ */ jsxs12("svg", { width: "32", height: "45", viewBox: "0 0 40 56", ...arrow, children: [
6212
+ /* @__PURE__ */ jsx15("path", { d: "M14 54 C 6 38, 10 18, 20 4" }),
6213
+ /* @__PURE__ */ jsx15("path", { d: "M20 4 L11.8 7.7 M20 4 L19.1 13" })
6114
6214
  ] }),
6115
- /* @__PURE__ */ jsx14("p", { className: "mt-1 whitespace-nowrap", children: "Switch between levels of detail" })
6215
+ /* @__PURE__ */ jsx15("p", { className: "mt-1 whitespace-nowrap", children: "Switch between levels of detail" })
6116
6216
  ] }),
6117
- live && /* @__PURE__ */ jsxs11("div", { className: "absolute right-[52px] top-[66px] flex items-end gap-1", children: [
6118
- /* @__PURE__ */ jsx14("p", { className: "mb-[-5px] max-w-[200px] text-right", children: "Start live collaboration with your team or agents" }),
6119
- /* @__PURE__ */ jsxs11(
6217
+ live && /* @__PURE__ */ jsxs12("div", { className: "absolute right-[52px] top-[66px] flex items-end gap-1", children: [
6218
+ /* @__PURE__ */ jsx15("p", { className: "mb-[-5px] max-w-[200px] text-right", children: "Start live collaboration with your team or agents" }),
6219
+ /* @__PURE__ */ jsxs12(
6120
6220
  "svg",
6121
6221
  {
6122
6222
  width: "40",
@@ -6125,8 +6225,8 @@ function Hints({ palette, live }) {
6125
6225
  className: "flex-none",
6126
6226
  ...arrow,
6127
6227
  children: [
6128
- /* @__PURE__ */ jsx14("path", { d: "M6 56 C 30 52, 42 30, 40 4" }),
6129
- /* @__PURE__ */ jsx14("path", { d: "M40 4 L36.1 12.1 M40 4 L45.1 11.4" })
6228
+ /* @__PURE__ */ jsx15("path", { d: "M6 56 C 30 52, 42 30, 40 4" }),
6229
+ /* @__PURE__ */ jsx15("path", { d: "M40 4 L36.1 12.1 M40 4 L45.1 11.4" })
6130
6230
  ]
6131
6231
  }
6132
6232
  )
@@ -6143,9 +6243,9 @@ function EmptyCanvas({
6143
6243
  palette,
6144
6244
  live
6145
6245
  }) {
6146
- const [dragging, setDragging] = useState10(false);
6147
- const [dropped, setDropped] = useState10(false);
6148
- useEffect8(() => {
6246
+ const [dragging, setDragging] = useState12(false);
6247
+ const [dropped, setDropped] = useState12(false);
6248
+ useEffect10(() => {
6149
6249
  const start = () => setDragging(true);
6150
6250
  const end = () => setDragging(false);
6151
6251
  const drop = () => {
@@ -6162,353 +6262,60 @@ function EmptyCanvas({
6162
6262
  };
6163
6263
  }, []);
6164
6264
  if (dragging || dropped) return null;
6165
- const item = (icon, label, onClick, hint) => /* @__PURE__ */ jsxs11(
6265
+ const item = (icon, label, onClick, hint) => /* @__PURE__ */ jsxs12(
6166
6266
  "button",
6167
6267
  {
6168
6268
  type: "button",
6169
6269
  onClick,
6170
6270
  className: "group flex h-11 w-full items-center gap-3.5 rounded-lg px-3 text-left text-[15px] text-[rgb(var(--ec-page-text-muted))] transition-colors hover:bg-[rgb(var(--ec-content-hover))]! hover:text-[rgb(var(--ec-page-text))]! [&_svg]:h-[18px] [&_svg]:w-[18px] [&_svg]:stroke-[1.75]",
6171
6271
  children: [
6172
- /* @__PURE__ */ jsx14("span", { className: "flex flex-none", children: icon }),
6173
- /* @__PURE__ */ jsx14("span", { className: "min-w-0 flex-1 truncate", children: label }),
6174
- hint && /* @__PURE__ */ jsx14("span", { className: "flex-none text-[13px] opacity-80", children: hint })
6272
+ /* @__PURE__ */ jsx15("span", { className: "flex flex-none", children: icon }),
6273
+ /* @__PURE__ */ jsx15("span", { className: "min-w-0 flex-1 truncate", children: label }),
6274
+ hint && /* @__PURE__ */ jsx15("span", { className: "flex-none text-[13px] opacity-80", children: hint })
6175
6275
  ]
6176
6276
  }
6177
6277
  );
6178
6278
  return (
6179
6279
  // On the canvas itself: what's dragged in from the left still lands on it
6180
- /* @__PURE__ */ jsxs11("div", { className: "pointer-events-none absolute inset-0 z-[5] flex items-center justify-center px-4 pb-16 pt-40", children: [
6181
- /* @__PURE__ */ jsx14(Hints, { palette, live }),
6182
- welcome && /* @__PURE__ */ jsxs11("div", { className: "pointer-events-auto flex w-full max-w-[440px] flex-col items-center", children: [
6183
- /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-3 text-[rgb(var(--ec-page-text))]", children: [
6184
- /* @__PURE__ */ jsx14(
6280
+ /* @__PURE__ */ jsxs12("div", { className: "pointer-events-none absolute inset-0 z-[5] flex items-center justify-center px-4 pb-16 pt-40", children: [
6281
+ /* @__PURE__ */ jsx15(Hints, { palette, live }),
6282
+ welcome && /* @__PURE__ */ jsxs12("div", { className: "pointer-events-auto flex w-full max-w-[440px] flex-col items-center", children: [
6283
+ /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-3 text-[rgb(var(--ec-page-text))]", children: [
6284
+ /* @__PURE__ */ jsx15(
6185
6285
  "span",
6186
6286
  {
6187
6287
  className: "h-11 w-11 [&_svg]:h-full [&_svg]:w-full",
6188
6288
  dangerouslySetInnerHTML: { __html: eventcatalog_logo_default }
6189
6289
  }
6190
6290
  ),
6191
- /* @__PURE__ */ jsxs11("span", { className: "text-[34px] font-bold tracking-tight", children: [
6291
+ /* @__PURE__ */ jsxs12("span", { className: "text-[34px] font-bold tracking-tight", children: [
6192
6292
  "EventCatalog",
6193
6293
  " ",
6194
- /* @__PURE__ */ jsx14("span", { className: "font-light text-[rgb(var(--ec-page-text-muted))]", children: "Studio" })
6294
+ /* @__PURE__ */ jsx15("span", { className: "font-light text-[rgb(var(--ec-page-text-muted))]", children: "Studio" })
6195
6295
  ] })
6196
6296
  ] }),
6197
- /* @__PURE__ */ jsx14("p", { className: "mt-5 text-center font-[Excalifont,Inter,sans-serif] text-[22px] leading-snug text-[color-mix(in_srgb,rgb(var(--ec-page-text))_38%,transparent)]", children: "Sketch, design and share architecture with your team and AI agents." }),
6198
- /* @__PURE__ */ jsxs11("div", { className: "mt-10 w-full", children: [
6199
- onOpen && item(/* @__PURE__ */ jsx14(FolderOpen, { "aria-hidden": true }), "Open", onOpen, `${MOD2}+O`),
6200
- onConnect && item(/* @__PURE__ */ jsx14(Plug, { "aria-hidden": true }), "Connect to MCP Server", onConnect),
6201
- item(/* @__PURE__ */ jsx14(CircleHelp, { "aria-hidden": true }), "Help", onHelp, "?")
6297
+ /* @__PURE__ */ jsx15("p", { className: "mt-5 text-center font-[Excalifont,Inter,sans-serif] text-[22px] leading-snug text-[color-mix(in_srgb,rgb(var(--ec-page-text))_38%,transparent)]", children: "Sketch, design and share architecture with your team and AI agents." }),
6298
+ /* @__PURE__ */ jsxs12("div", { className: "mt-10 w-full", children: [
6299
+ onOpen && item(/* @__PURE__ */ jsx15(FolderOpen, { "aria-hidden": true }), "Open", onOpen, `${MOD2}+O`),
6300
+ onConnect && item(/* @__PURE__ */ jsx15(Plug, { "aria-hidden": true }), "Connect to MCP Server", onConnect),
6301
+ item(/* @__PURE__ */ jsx15(CircleHelp, { "aria-hidden": true }), "Help", onHelp, "?")
6202
6302
  ] })
6203
6303
  ] })
6204
6304
  ] })
6205
6305
  );
6206
6306
  }
6207
6307
 
6208
- // src/studio/components/NodeCard.tsx
6209
- import {
6210
- useCallback as useCallback5,
6211
- useEffect as useEffect9,
6212
- useRef as useRef7,
6213
- useState as useState11
6214
- } from "react";
6215
- import { Check as Check2, X as X4 } from "lucide-react";
6216
- import { Fragment as Fragment8, jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
6217
- var MODAL_WIDTH = 300;
6218
- var GAP2 = 12;
6219
- var EDGE2 = 8;
6220
- var ARROW_DOWN = 32;
6221
- function useNodeAnchor(nodeId, containerRef, modalRef, bottomInset = EDGE2) {
6222
- const [anchor, setAnchor] = useState11(null);
6223
- useEffect9(() => {
6224
- let frame = 0;
6225
- const update = () => {
6226
- const container = containerRef.current;
6227
- const element = container?.querySelector(
6228
- `.react-flow__node[data-id="${CSS.escape(nodeId)}"]`
6229
- );
6230
- if (container && element) {
6231
- const bounds = container.getBoundingClientRect();
6232
- const rect = element.getBoundingClientRect();
6233
- const height = modalRef.current?.offsetHeight ?? 200;
6234
- const width = modalRef.current?.offsetWidth || MODAL_WIDTH;
6235
- const side = rect.right + GAP2 + width <= bounds.right - EDGE2 ? "right" : "left";
6236
- const left = side === "right" ? rect.right - bounds.left + GAP2 : rect.left - bounds.left - GAP2 - width;
6237
- const clamp = (value, max) => Math.min(Math.max(value, EDGE2), Math.max(max, EDGE2));
6238
- const top = clamp(
6239
- Math.min(rect.top, rect.top + rect.height / 2 - ARROW_DOWN) - bounds.top,
6240
- bounds.height - height - bottomInset
6241
- );
6242
- const placed = clamp(left, bounds.width - width - EDGE2);
6243
- const middle = rect.top + rect.height / 2 - bounds.top - top;
6244
- const pointsAt = placed === left && middle >= 14 && middle <= height - 14 ? Math.round(middle) : void 0;
6245
- const next = { side, left: placed, top, pointsAt };
6246
- setAnchor(
6247
- (previous) => previous?.left === next.left && previous?.top === next.top && previous?.side === next.side && previous?.pointsAt === next.pointsAt ? previous : next
6248
- );
6249
- }
6250
- frame = requestAnimationFrame(update);
6251
- };
6252
- update();
6253
- return () => cancelAnimationFrame(frame);
6254
- }, [nodeId, containerRef, modalRef, bottomInset]);
6255
- return anchor;
6256
- }
6257
- function useSavedFlash() {
6258
- const [saved, setSaved] = useState11(false);
6259
- const timer = useRef7(void 0);
6260
- const showSaved = useCallback5(() => {
6261
- setSaved(true);
6262
- clearTimeout(timer.current);
6263
- timer.current = setTimeout(() => setSaved(false), 1600);
6264
- }, []);
6265
- useEffect9(() => () => clearTimeout(timer.current), []);
6266
- return { saved, showSaved };
6267
- }
6268
- function EditStatus({ saved }) {
6269
- return /* @__PURE__ */ jsx15(
6270
- "p",
6271
- {
6272
- className: `ec-edit-status ${saved ? "is-saved" : ""}`,
6273
- "aria-live": "polite",
6274
- children: saved ? /* @__PURE__ */ jsxs12(Fragment8, { children: [
6275
- /* @__PURE__ */ jsx15(Check2, { "aria-hidden": true }),
6276
- " Saved"
6277
- ] }) : "Changes save as you type"
6278
- }
6279
- );
6280
- }
6281
- function NodeCard({
6282
- nodeId,
6283
- containerRef,
6284
- label,
6285
- kicker,
6286
- header,
6287
- children,
6288
- width = 340,
6289
- bottomInset = 76,
6290
- onClose
6291
- }) {
6292
- const cardRef = useRef7(null);
6293
- const anchor = useNodeAnchor(nodeId, containerRef, cardRef, bottomInset);
6294
- const onCloseRef = useRef7(onClose);
6295
- onCloseRef.current = onClose;
6296
- useEffect9(() => {
6297
- const close = () => {
6298
- const active = document.activeElement;
6299
- if (active instanceof HTMLElement && cardRef.current?.contains(active))
6300
- active.blur();
6301
- onCloseRef.current();
6302
- };
6303
- const onPointerDown = (event) => {
6304
- if (!cardRef.current?.contains(event.target)) close();
6305
- };
6306
- const onKeyDown = (event) => event.key === "Escape" && close();
6307
- document.addEventListener("pointerdown", onPointerDown, true);
6308
- document.addEventListener("keydown", onKeyDown);
6309
- return () => {
6310
- document.removeEventListener("pointerdown", onPointerDown, true);
6311
- document.removeEventListener("keydown", onKeyDown);
6312
- };
6313
- }, []);
6314
- const shown = !!anchor;
6315
- const focusedFirst = useRef7(false);
6316
- useEffect9(() => {
6317
- if (!shown || focusedFirst.current) return;
6318
- focusedFirst.current = true;
6319
- const field = cardRef.current?.querySelector(
6320
- "input:not([readonly]):not([disabled]), textarea:not([readonly]):not([disabled])"
6321
- );
6322
- if (!field) return;
6323
- field.focus({ preventScroll: true });
6324
- try {
6325
- field.setSelectionRange(field.value.length, field.value.length);
6326
- } catch {
6327
- }
6328
- }, [shown]);
6329
- return /* @__PURE__ */ jsxs12(Fragment8, { children: [
6330
- anchor?.pointsAt !== void 0 && /* @__PURE__ */ jsx15(
6331
- "span",
6332
- {
6333
- "aria-hidden": true,
6334
- className: `ec-doc-card-arrow is-${anchor.side}`,
6335
- style: {
6336
- top: anchor.top + anchor.pointsAt - 7,
6337
- left: anchor.side === "right" ? anchor.left - 6 : anchor.left + width - 8
6338
- }
6339
- }
6340
- ),
6341
- /* @__PURE__ */ jsxs12(
6342
- "div",
6343
- {
6344
- ref: cardRef,
6345
- className: "ec-doc-card",
6346
- role: "dialog",
6347
- "aria-label": label,
6348
- style: {
6349
- width,
6350
- top: anchor?.top ?? 8,
6351
- left: anchor?.left ?? 8,
6352
- visibility: anchor ? "visible" : "hidden"
6353
- },
6354
- children: [
6355
- /* @__PURE__ */ jsxs12("header", { className: "ec-doc-card-header", children: [
6356
- /* @__PURE__ */ jsxs12("div", { className: "ec-doc-card-kicker", children: [
6357
- kicker,
6358
- /* @__PURE__ */ jsx15(
6359
- "button",
6360
- {
6361
- type: "button",
6362
- className: "ec-icon-button ec-doc-card-close",
6363
- "aria-label": "Close",
6364
- onClick: onClose,
6365
- children: /* @__PURE__ */ jsx15(X4, { "aria-hidden": true })
6366
- }
6367
- )
6368
- ] }),
6369
- header
6370
- ] }),
6371
- children
6372
- ]
6373
- }
6374
- )
6375
- ] });
6376
- }
6377
- var SAVE_DELAY = 250;
6378
- function EditableText({
6379
- value,
6380
- onSave,
6381
- multiline = false,
6382
- placeholder,
6383
- className = "",
6384
- label,
6385
- required = false,
6386
- onSaved
6387
- }) {
6388
- const [draft, setDraft] = useState11(value);
6389
- const focused = useRef7(false);
6390
- const before = useRef7(value);
6391
- const pending = useRef7(null);
6392
- const timer = useRef7(void 0);
6393
- const latest = useRef7({ value, onSave, onSaved, required });
6394
- latest.current = { value, onSave, onSaved, required };
6395
- useEffect9(() => {
6396
- if (!focused.current) setDraft(value);
6397
- }, [value]);
6398
- const flush = () => {
6399
- clearTimeout(timer.current);
6400
- const next = pending.current;
6401
- pending.current = null;
6402
- if (next === null) return;
6403
- const {
6404
- value: saved,
6405
- onSave: save,
6406
- onSaved: said,
6407
- required: needed
6408
- } = latest.current;
6409
- if (needed && !next.trim() || next === saved) return;
6410
- save(next);
6411
- said?.();
6412
- };
6413
- useEffect9(() => flush, []);
6414
- const change = (next) => {
6415
- setDraft(next);
6416
- pending.current = next;
6417
- clearTimeout(timer.current);
6418
- timer.current = setTimeout(flush, SAVE_DELAY);
6419
- };
6420
- const reverted = useRef7(false);
6421
- const leave = () => {
6422
- focused.current = false;
6423
- if (reverted.current) {
6424
- reverted.current = false;
6425
- return;
6426
- }
6427
- const trimmed = draft.trim();
6428
- if (required && !trimmed) {
6429
- setDraft(before.current);
6430
- pending.current = before.current;
6431
- } else {
6432
- if (trimmed !== draft) setDraft(trimmed);
6433
- pending.current = trimmed;
6434
- }
6435
- flush();
6436
- };
6437
- const keys = (event) => {
6438
- if (event.key === "Escape") {
6439
- event.stopPropagation();
6440
- setDraft(before.current);
6441
- pending.current = before.current;
6442
- flush();
6443
- reverted.current = true;
6444
- event.target.blur();
6445
- } else if (event.key === "Enter" && (!multiline || event.metaKey || event.ctrlKey)) {
6446
- event.preventDefault();
6447
- event.target.blur();
6448
- }
6449
- };
6450
- const focus = () => {
6451
- focused.current = true;
6452
- before.current = value;
6453
- };
6454
- const fit = (area) => {
6455
- if (!area) return;
6456
- area.style.height = "auto";
6457
- area.style.height = `${area.scrollHeight + 2}px`;
6458
- };
6459
- return multiline ? /* @__PURE__ */ jsx15(
6460
- "textarea",
6461
- {
6462
- ref: fit,
6463
- "aria-label": label,
6464
- value: draft,
6465
- rows: 2,
6466
- placeholder,
6467
- onChange: (event) => {
6468
- change(event.target.value);
6469
- fit(event.target);
6470
- },
6471
- onFocus: focus,
6472
- onBlur: leave,
6473
- onKeyDown: keys,
6474
- className: `ec-editable ${className}`
6475
- }
6476
- ) : /* @__PURE__ */ jsx15(
6477
- "input",
6478
- {
6479
- "aria-label": label,
6480
- value: draft,
6481
- placeholder,
6482
- onChange: (event) => change(event.target.value),
6483
- onFocus: focus,
6484
- onBlur: leave,
6485
- onKeyDown: keys,
6486
- className: `ec-editable ${className}`
6487
- }
6488
- );
6489
- }
6490
- function Field({
6491
- label,
6492
- children,
6493
- className = ""
6494
- }) {
6495
- return /* @__PURE__ */ jsxs12("label", { className: `ec-field ${className}`, children: [
6496
- /* @__PURE__ */ jsx15("span", { className: "ec-field-label", children: label }),
6497
- children
6498
- ] });
6499
- }
6500
-
6501
6308
  // src/studio/components/RemeasureHandles.tsx
6502
- import { memo as memo9, useEffect as useEffect10 } from "react";
6309
+ import { memo as memo10, useEffect as useEffect11 } from "react";
6503
6310
  import {
6504
6311
  useStore as useStore2,
6505
6312
  useUpdateNodeInternals as useUpdateNodeInternals2
6506
6313
  } from "@xyflow/react";
6507
6314
  var selectDomNode = (state) => state.domNode;
6508
- var RemeasureHandles = memo9(function RemeasureHandles2() {
6315
+ var RemeasureHandles = memo10(function RemeasureHandles2() {
6509
6316
  const domNode = useStore2(selectDomNode);
6510
6317
  const updateNodeInternals = useUpdateNodeInternals2();
6511
- useEffect10(() => {
6318
+ useEffect11(() => {
6512
6319
  if (!domNode) return;
6513
6320
  const pending = /* @__PURE__ */ new Set();
6514
6321
  let frame = 0;
@@ -6547,6 +6354,10 @@ export {
6547
6354
  CLIPBOARD_TYPE,
6548
6355
  COMPONENT_DRAG_TYPE,
6549
6356
  COMPONENT_TYPES,
6357
+ CONNECT_MIN_DISTANCE,
6358
+ CONNECT_PLACEHOLDER,
6359
+ CONNECT_PLACEHOLDER_EDGE,
6360
+ CONNECT_PLACEHOLDER_SIZE,
6550
6361
  COUNTER_SCALE,
6551
6362
  CanvasControls_default as CanvasControls,
6552
6363
  CanvasPortal,
@@ -6555,6 +6366,8 @@ export {
6555
6366
  ClaudeLogo,
6556
6367
  CommentLayer,
6557
6368
  CommentList,
6369
+ ConnectChooser,
6370
+ ConnectPlaceholderNode,
6558
6371
  ContainerChooser,
6559
6372
  ContextMenu,
6560
6373
  CursorLogo,
@@ -6615,10 +6428,12 @@ export {
6615
6428
  canPickWhereToSave,
6616
6429
  canvasImage,
6617
6430
  canvasToModel,
6431
+ centreBeyond,
6618
6432
  changesNodesOrEdges,
6619
6433
  cleanFileName,
6620
6434
  componentKey,
6621
6435
  connectNodes,
6436
+ connectedType,
6622
6437
  containerFor,
6623
6438
  copyNodes,
6624
6439
  createEdge,
@@ -6632,6 +6447,7 @@ export {
6632
6447
  deleteThreads,
6633
6448
  downloadFile,
6634
6449
  fileNameFor,
6450
+ filterConnectOptions,
6635
6451
  findDropTarget,
6636
6452
  findDropTargets,
6637
6453
  findGroupAtPoint,
@@ -6643,6 +6459,7 @@ export {
6643
6459
  getAnchorPosition,
6644
6460
  getCanvasMaps,
6645
6461
  getCanvasStatus,
6462
+ getConnectOptions,
6646
6463
  getDiagramLevel,
6647
6464
  getDiagramLevelUnavailable,
6648
6465
  getEdgeLabel,
@@ -6659,8 +6476,11 @@ export {
6659
6476
  getNoteLevel,
6660
6477
  getResource,
6661
6478
  getStructureKey,
6479
+ isAwayFrom,
6480
+ isCardType,
6662
6481
  isCatalogCollection,
6663
6482
  isDecided,
6483
+ isEmptyCanvasAt,
6664
6484
  isGroupType,
6665
6485
  isOnLevel,
6666
6486
  isShownOnLevel,
@@ -6670,12 +6490,15 @@ export {
6670
6490
  keepUnchanged,
6671
6491
  layoutGraph,
6672
6492
  levelPlaces,
6493
+ linkConnection,
6673
6494
  modelToCanvas,
6674
6495
  moveNode,
6675
6496
  moveThread,
6676
6497
  moveThreads,
6498
+ newCardData,
6677
6499
  nodeDefinitions,
6678
6500
  nodeTypes,
6501
+ notPlaceholder,
6679
6502
  pasteNodes,
6680
6503
  patchShared,
6681
6504
  pickDiagramFile,
@@ -6719,6 +6542,7 @@ export {
6719
6542
  updateHotspot,
6720
6543
  updateNodeData,
6721
6544
  updateResource,
6545
+ useConnectNew,
6722
6546
  useCounterScale,
6723
6547
  useDragGhost,
6724
6548
  useNodeAnchor,