@almadar/ui 6.4.0 → 6.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/dist/{EntityBindingContext-0Evn_LcT.d.cts → EntityBindingContext-Bn3ePJQC.d.cts} +1 -1
  2. package/dist/{EntityBindingContext-0Evn_LcT.d.ts → EntityBindingContext-Bn3ePJQC.d.ts} +1 -1
  3. package/dist/{GameAudioProvider-B48iXwz3.d.ts → GameAudioProvider-Ctceau1s.d.ts} +6 -18
  4. package/dist/{GameAudioProvider-CQAdPreB.d.cts → GameAudioProvider-Dk_Y3LN3.d.cts} +6 -18
  5. package/dist/avl/index.cjs +2755 -1532
  6. package/dist/avl/index.js +1710 -487
  7. package/dist/{avl-schema-parser-dvJKXn-o.d.ts → avl-schema-parser-DncJLEn9.d.ts} +18 -0
  8. package/dist/{avl-schema-parser-Bt4NzAam.d.cts → avl-schema-parser-FQ1474v8.d.cts} +18 -0
  9. package/dist/{cn-DJSBBm5W.d.cts → cn-CCjFspAo.d.cts} +25 -1
  10. package/dist/{cn-BbhJq_nr.d.ts → cn-sgpqpN0U.d.ts} +25 -1
  11. package/dist/components/index.cjs +2518 -1692
  12. package/dist/components/index.d.cts +178 -25
  13. package/dist/components/index.d.ts +178 -25
  14. package/dist/components/index.js +1500 -677
  15. package/dist/context/index.cjs +10 -13
  16. package/dist/context/index.js +10 -13
  17. package/dist/hooks/index.cjs +63 -13
  18. package/dist/hooks/index.d.cts +2 -2
  19. package/dist/hooks/index.d.ts +2 -2
  20. package/dist/hooks/index.js +64 -15
  21. package/dist/lib/drawable/three/index.cjs +126 -13
  22. package/dist/lib/drawable/three/index.d.cts +2 -2
  23. package/dist/lib/drawable/three/index.d.ts +2 -2
  24. package/dist/lib/drawable/three/index.js +127 -14
  25. package/dist/lib/index.cjs +180 -0
  26. package/dist/lib/index.d.cts +1 -1
  27. package/dist/lib/index.d.ts +1 -1
  28. package/dist/lib/index.js +178 -1
  29. package/dist/locales/index.cjs +6 -3
  30. package/dist/locales/index.js +6 -3
  31. package/dist/providers/index.cjs +2346 -1399
  32. package/dist/providers/index.d.cts +2 -2
  33. package/dist/providers/index.d.ts +2 -2
  34. package/dist/providers/index.js +1389 -442
  35. package/dist/runtime/index.cjs +2892 -1356
  36. package/dist/runtime/index.d.cts +78 -6
  37. package/dist/runtime/index.d.ts +78 -6
  38. package/dist/runtime/index.js +1974 -441
  39. package/dist/{useEventBus-CQWyAWpK.d.ts → useKeyboardRouter-D84cNWmA.d.ts} +31 -1
  40. package/dist/{useEventBus-Ckr4wqW3.d.cts → useKeyboardRouter-DQEE_9mq.d.cts} +31 -1
  41. package/locales/ar.json +2 -1
  42. package/locales/en.json +2 -1
  43. package/locales/sl.json +2 -1
  44. package/package.json +4 -4
  45. package/themes/comic.css +437 -0
  46. package/themes/index.css +1 -0
@@ -1,4 +1,4 @@
1
- import React3, { createContext, forwardRef, useRef, useState, useMemo, useEffect, useImperativeHandle, useCallback, useContext, Component, useReducer } from 'react';
1
+ import React3, { createContext, forwardRef, useRef, useState, useMemo, useEffect, useCallback, useImperativeHandle, useContext, Component, useReducer } from 'react';
2
2
  import { EventBusContext, useTraitScopeChain } from '@almadar/ui/providers';
3
3
  import { createLogger } from '@almadar/logger';
4
4
  import { Canvas, useThree, useFrame } from '@react-three/fiber';
@@ -161,7 +161,7 @@ function collectDrawnItems(nodes) {
161
161
  for (const n of nodes) {
162
162
  switch (n.type) {
163
163
  case "draw-sprite":
164
- if (isValidScenePos(n.position)) out.push({ pos: n.position, id: n.id, anchor: n.anchor, width: n.width, height: n.height });
164
+ if (isValidScenePos(n.position)) out.push({ pos: n.position, id: n.id, anchor: n.anchor, width: n.width, height: n.height, rotation: n.rotation });
165
165
  break;
166
166
  case "draw-shape":
167
167
  case "draw-text":
@@ -171,7 +171,7 @@ function collectDrawnItems(nodes) {
171
171
  break;
172
172
  case "draw-sprite-layer":
173
173
  for (const it of n.items) {
174
- if (isValidScenePos(it.position)) out.push({ pos: it.position, id: it.id, anchor: it.anchor, width: it.width, height: it.height });
174
+ if (isValidScenePos(it.position)) out.push({ pos: it.position, id: it.id, anchor: it.anchor, width: it.width, height: it.height, rotation: it.rotation });
175
175
  }
176
176
  break;
177
177
  case "draw-shape-layer":
@@ -191,6 +191,22 @@ function buildHitIndex(items) {
191
191
  }
192
192
  return m;
193
193
  }
194
+ function withPreviewPosition(nodes, id, pos) {
195
+ return nodes.map((n) => {
196
+ if (n.type === "draw-sprite-layer" || n.type === "draw-shape-layer" || n.type === "draw-text-layer") {
197
+ if (!n.items.some((it) => it.id === id)) return n;
198
+ return { ...n, items: n.items.map((it) => it.id === id ? { ...it, position: pos } : it) };
199
+ }
200
+ if (n.type === "draw-group") {
201
+ if (!Array.isArray(n.items)) return n;
202
+ return { ...n, items: withPreviewPosition(n.items, id, pos) };
203
+ }
204
+ if (n.id === id && "position" in n) {
205
+ return { ...n, position: pos };
206
+ }
207
+ return n;
208
+ });
209
+ }
194
210
  function useGameCanvas3DEvents(options) {
195
211
  const {
196
212
  tileClickEvent,
@@ -1355,7 +1371,7 @@ function Sprite3D({ node, projector, groupOpacity = 1 }) {
1355
1371
  {
1356
1372
  url: asset.url,
1357
1373
  scale,
1358
- rotation: [0, (node.rotation ?? 0) * 180 / Math.PI, 0],
1374
+ rotation: [0, node.rotation ?? 0, 0],
1359
1375
  animation: node.animation,
1360
1376
  fallbackGeometry: "box",
1361
1377
  castShadow: true,
@@ -1830,6 +1846,8 @@ function cn(...inputs) {
1830
1846
  }
1831
1847
  var DEFAULT_GRID_CONFIG = {
1832
1848
  cellSize: 1};
1849
+ var EDIT_SELECTION_COLOR = "#3b82f6";
1850
+ var EDIT_SELECTION_RADIUS = 0.6;
1833
1851
  function CameraPose({
1834
1852
  position,
1835
1853
  fov,
@@ -1893,7 +1911,13 @@ var Canvas3DHost = forwardRef(
1893
1911
  lighting,
1894
1912
  post,
1895
1913
  children,
1896
- drawables
1914
+ drawables,
1915
+ editable = false,
1916
+ selectedId = null,
1917
+ onSelect,
1918
+ onMove,
1919
+ selectEvent,
1920
+ moveEvent
1897
1921
  }, ref) => {
1898
1922
  const containerRef = useRef(null);
1899
1923
  const controlsRef = useRef(null);
@@ -1979,6 +2003,25 @@ var Canvas3DHost = forwardRef(
1979
2003
  }),
1980
2004
  [gridBounds, gridConfig]
1981
2005
  );
2006
+ const editDragRef = useRef(null);
2007
+ const [dragPreview, setDragPreview] = useState(null);
2008
+ const groundPointToScene = useCallback((point) => ({
2009
+ x: Math.round(point.x / gridConfig.cellSize + gridBounds.minX),
2010
+ y: Math.round(point.z / gridConfig.cellSize + gridBounds.minZ)
2011
+ }), [gridConfig, gridBounds]);
2012
+ const paintDrawables = useMemo(
2013
+ () => dragPreview ? withPreviewPosition(allDrawables, dragPreview.id, { x: dragPreview.x, y: dragPreview.y }) : allDrawables,
2014
+ [allDrawables, dragPreview]
2015
+ );
2016
+ const selectedItem = useMemo(
2017
+ () => editable && selectedId != null ? drawnItems.find((it) => it.id === selectedId) : void 0,
2018
+ [editable, selectedId, drawnItems]
2019
+ );
2020
+ const selectionPos = useMemo(() => {
2021
+ if (!selectedItem) return void 0;
2022
+ if (dragPreview && dragPreview.id === selectedItem.id) return { x: dragPreview.x, y: dragPreview.y };
2023
+ return selectedItem.pos;
2024
+ }, [selectedItem, dragPreview]);
1982
2025
  useImperativeHandle(ref, () => ({
1983
2026
  getCameraPosition: () => {
1984
2027
  if (controlsRef.current) {
@@ -2059,17 +2102,14 @@ var Canvas3DHost = forwardRef(
2059
2102
  const handleGroundClick = useCallback((e) => {
2060
2103
  if (!tileClickEvent && !unitClickEvent) return;
2061
2104
  e.stopPropagation();
2062
- const cell = {
2063
- x: Math.round(e.point.x / gridConfig.cellSize + gridBounds.minX),
2064
- y: Math.round(e.point.z / gridConfig.cellSize + gridBounds.minZ)
2065
- };
2105
+ const cell = groundPointToScene(e.point);
2066
2106
  const hitId = hitIndex.get(`${cell.x},${cell.y}`);
2067
2107
  if (hitId !== void 0 && unitClickEvent) {
2068
2108
  eventBus.emit(`UI:${unitClickEvent}`, { unitId: hitId, x: cell.x, z: cell.y });
2069
2109
  } else if (tileClickEvent) {
2070
2110
  eventBus.emit(`UI:${tileClickEvent}`, { x: cell.x, z: cell.y });
2071
2111
  }
2072
- }, [tileClickEvent, unitClickEvent, gridConfig, gridBounds, hitIndex, eventBus]);
2112
+ }, [tileClickEvent, unitClickEvent, groundPointToScene, hitIndex, eventBus]);
2073
2113
  const handleDrawableClick = useCallback((e) => {
2074
2114
  if (!unitClickEvent) return;
2075
2115
  let obj = e.object;
@@ -2087,6 +2127,57 @@ var Canvas3DHost = forwardRef(
2087
2127
  obj = obj.parent;
2088
2128
  }
2089
2129
  }, [unitClickEvent, gridConfig, gridBounds, eventBus]);
2130
+ const handleEditDrawablePointerDown = useCallback((e) => {
2131
+ if (!editable) return;
2132
+ let obj = e.object;
2133
+ while (obj) {
2134
+ const id = obj.userData.drawableId;
2135
+ if (id !== void 0) {
2136
+ e.stopPropagation();
2137
+ editDragRef.current = {
2138
+ id,
2139
+ startClientX: e.nativeEvent.clientX,
2140
+ startClientY: e.nativeEvent.clientY,
2141
+ moved: false
2142
+ };
2143
+ return;
2144
+ }
2145
+ obj = obj.parent;
2146
+ }
2147
+ }, [editable]);
2148
+ const handleEditGroundPointerMove = useCallback((e) => {
2149
+ const drag = editDragRef.current;
2150
+ if (!editable || !drag) return;
2151
+ const dx = e.nativeEvent.clientX - drag.startClientX;
2152
+ const dy = e.nativeEvent.clientY - drag.startClientY;
2153
+ if (!drag.moved && Math.abs(dx) + Math.abs(dy) <= 5) return;
2154
+ drag.moved = true;
2155
+ const cell = groundPointToScene(e.point);
2156
+ setDragPreview({ id: drag.id, x: cell.x, y: cell.y });
2157
+ }, [editable, groundPointToScene]);
2158
+ const handleEditPointerUp = useCallback((_e) => {
2159
+ if (!editable) return;
2160
+ const drag = editDragRef.current;
2161
+ editDragRef.current = null;
2162
+ if (!drag) {
2163
+ onSelect?.(null);
2164
+ if (selectEvent) eventBus.emit(`UI:${selectEvent}`, { id: null });
2165
+ return;
2166
+ }
2167
+ if (drag.moved) {
2168
+ setDragPreview((preview) => {
2169
+ if (preview && preview.id === drag.id) {
2170
+ onMove?.(drag.id, preview.x, preview.y);
2171
+ if (moveEvent) eventBus.emit(`UI:${moveEvent}`, { id: drag.id, x: preview.x, y: preview.y });
2172
+ }
2173
+ return null;
2174
+ });
2175
+ return;
2176
+ }
2177
+ const next = selectedId === drag.id ? null : drag.id;
2178
+ onSelect?.(next);
2179
+ if (selectEvent) eventBus.emit(`UI:${selectEvent}`, { id: next });
2180
+ }, [editable, selectedId, onMove, moveEvent, onSelect, selectEvent, eventBus]);
2090
2181
  if (externalLoading) {
2091
2182
  return /* @__PURE__ */ jsx(
2092
2183
  Canvas3DLoadingState,
@@ -2138,6 +2229,7 @@ var Canvas3DHost = forwardRef(
2138
2229
  eventHandlers.handleCanvasClick(e);
2139
2230
  }
2140
2231
  },
2232
+ onPointerUp: handleEditPointerUp,
2141
2233
  children: [
2142
2234
  /* @__PURE__ */ jsx(CameraController3D, { onCameraChange: eventHandlers.handleCameraChange }),
2143
2235
  cameraMode !== "follow" && cameraMode !== "chase" && /* @__PURE__ */ jsx(CameraPose, { position: cameraConfig.position, fov: cameraConfig.fov, controls: controlsRef }),
@@ -2185,8 +2277,28 @@ var Canvas3DHost = forwardRef(
2185
2277
  fadeStrength: 1
2186
2278
  }
2187
2279
  ),
2188
- allDrawables.length > 0 && /* @__PURE__ */ jsx(BoneRegistryContext.Provider, { value: boneStore, children: /* @__PURE__ */ jsx("group", { onClick: unitClickEvent ? handleDrawableClick : void 0, children: allDrawables.map((node, i) => /* @__PURE__ */ jsx(Drawable3D, { node, projector: drawableProjector }, i)) }) }),
2189
- (tileClickEvent || unitClickEvent) && /* @__PURE__ */ jsxs(
2280
+ allDrawables.length > 0 && /* @__PURE__ */ jsx(BoneRegistryContext.Provider, { value: boneStore, children: /* @__PURE__ */ jsx(
2281
+ "group",
2282
+ {
2283
+ onClick: !editable && unitClickEvent ? handleDrawableClick : void 0,
2284
+ onPointerDown: editable ? handleEditDrawablePointerDown : void 0,
2285
+ children: paintDrawables.map((node, i) => /* @__PURE__ */ jsx(Drawable3D, { node, projector: drawableProjector }, i))
2286
+ }
2287
+ ) }),
2288
+ selectionPos && /* @__PURE__ */ jsx(
2289
+ Shape3D,
2290
+ {
2291
+ node: {
2292
+ type: "draw-shape",
2293
+ shape: "ellipse",
2294
+ position: selectionPos,
2295
+ radiusX: EDIT_SELECTION_RADIUS,
2296
+ stroke: EDIT_SELECTION_COLOR
2297
+ },
2298
+ projector: drawableProjector
2299
+ }
2300
+ ),
2301
+ (tileClickEvent || unitClickEvent || editable) && /* @__PURE__ */ jsxs(
2190
2302
  "mesh",
2191
2303
  {
2192
2304
  rotation: [-Math.PI / 2, 0, 0],
@@ -2195,7 +2307,8 @@ var Canvas3DHost = forwardRef(
2195
2307
  0,
2196
2308
  (gridBounds.maxZ - gridBounds.minZ) / 2 * cellSize
2197
2309
  ],
2198
- onClick: handleGroundClick,
2310
+ onClick: !editable ? handleGroundClick : void 0,
2311
+ onPointerMove: editable ? handleEditGroundPointerMove : void 0,
2199
2312
  children: [
2200
2313
  /* @__PURE__ */ jsx(
2201
2314
  "planeGeometry",
@@ -2215,7 +2328,7 @@ var Canvas3DHost = forwardRef(
2215
2328
  OrbitControls,
2216
2329
  {
2217
2330
  ref: controlsRef,
2218
- enabled: controlsEnabled && cameraMode !== "follow" && cameraMode !== "chase",
2331
+ enabled: controlsEnabled && !editable && cameraMode !== "follow" && cameraMode !== "chase",
2219
2332
  target: cameraTarget,
2220
2333
  enableDamping: true,
2221
2334
  dampingFactor: 0.05,
@@ -2094,6 +2094,183 @@ var JAZARI_COLORS = {
2094
2094
  darkBg: "#1a1a2e"
2095
2095
  };
2096
2096
 
2097
+ // lib/editorMotions.ts
2098
+ function clamp(value, min, max) {
2099
+ return Math.max(min, Math.min(max, value));
2100
+ }
2101
+ function computeLines(text) {
2102
+ const lines = [];
2103
+ let start = 0;
2104
+ for (let i = 0; i <= text.length; i++) {
2105
+ if (i === text.length || text[i] === "\n") {
2106
+ lines.push({ start, end: i });
2107
+ start = i + 1;
2108
+ }
2109
+ }
2110
+ return lines;
2111
+ }
2112
+ function lineIndexAt(lines, pos) {
2113
+ for (let i = 0; i < lines.length; i++) {
2114
+ if (pos <= lines[i].end) return i;
2115
+ }
2116
+ return lines.length - 1;
2117
+ }
2118
+ function findWords(text) {
2119
+ const words = [];
2120
+ const re = /\w+|\S+/g;
2121
+ let m;
2122
+ while ((m = re.exec(text)) !== null) {
2123
+ words.push({ start: m.index, end: m.index + m[0].length });
2124
+ }
2125
+ return words;
2126
+ }
2127
+ function nextWordStart(text, pos) {
2128
+ for (const w of findWords(text)) {
2129
+ if (w.start > pos) return w.start;
2130
+ }
2131
+ return text.length;
2132
+ }
2133
+ function prevWordStart(text, pos) {
2134
+ let result = 0;
2135
+ for (const w of findWords(text)) {
2136
+ if (w.start < pos) result = w.start;
2137
+ else break;
2138
+ }
2139
+ return result;
2140
+ }
2141
+ function nextWordEnd(text, pos) {
2142
+ for (const w of findWords(text)) {
2143
+ const lastChar = w.end - 1;
2144
+ if (lastChar > pos) return lastChar;
2145
+ }
2146
+ return text.length > 0 ? text.length - 1 : 0;
2147
+ }
2148
+ function firstNonBlank(text, line) {
2149
+ let i = line.start;
2150
+ while (i < line.end && (text[i] === " " || text[i] === " ")) i++;
2151
+ return i;
2152
+ }
2153
+ function nextParagraphBoundary(lines, fromLineIdx, textLength) {
2154
+ for (let i = fromLineIdx + 1; i < lines.length; i++) {
2155
+ if (lines[i].start === lines[i].end) return lines[i].start;
2156
+ }
2157
+ return textLength;
2158
+ }
2159
+ function prevParagraphBoundary(lines, fromLineIdx) {
2160
+ for (let i = fromLineIdx - 1; i >= 0; i--) {
2161
+ if (lines[i].start === lines[i].end) return lines[i].start;
2162
+ }
2163
+ return 0;
2164
+ }
2165
+ function applyMotion(text, caret, motion, count) {
2166
+ const n = Math.max(1, count);
2167
+ const lines = computeLines(text);
2168
+ const lineIdx = lineIndexAt(lines, caret);
2169
+ const line = lines[lineIdx];
2170
+ switch (motion) {
2171
+ case "left":
2172
+ return clamp(caret - n, line.start, line.end);
2173
+ case "right":
2174
+ return clamp(caret + n, line.start, line.end);
2175
+ case "up": {
2176
+ const col = caret - line.start;
2177
+ const targetIdx = clamp(lineIdx - n, 0, lines.length - 1);
2178
+ const target = lines[targetIdx];
2179
+ return clamp(target.start + col, target.start, target.end);
2180
+ }
2181
+ case "down": {
2182
+ const col = caret - line.start;
2183
+ const targetIdx = clamp(lineIdx + n, 0, lines.length - 1);
2184
+ const target = lines[targetIdx];
2185
+ return clamp(target.start + col, target.start, target.end);
2186
+ }
2187
+ case "word-forward": {
2188
+ let pos = caret;
2189
+ for (let i = 0; i < n; i++) pos = nextWordStart(text, pos);
2190
+ return pos;
2191
+ }
2192
+ case "word-back": {
2193
+ let pos = caret;
2194
+ for (let i = 0; i < n; i++) pos = prevWordStart(text, pos);
2195
+ return pos;
2196
+ }
2197
+ case "word-end": {
2198
+ let pos = caret;
2199
+ for (let i = 0; i < n; i++) pos = nextWordEnd(text, pos);
2200
+ return pos;
2201
+ }
2202
+ case "line-start":
2203
+ return line.start;
2204
+ case "line-end":
2205
+ return line.end > line.start ? line.end - 1 : line.start;
2206
+ case "first-nonblank":
2207
+ return firstNonBlank(text, line);
2208
+ case "doc-start":
2209
+ return 0;
2210
+ case "doc-end":
2211
+ return text.length;
2212
+ case "paragraph-forward": {
2213
+ let pos = caret;
2214
+ for (let i = 0; i < n; i++) {
2215
+ pos = nextParagraphBoundary(lines, lineIndexAt(lines, pos), text.length);
2216
+ }
2217
+ return pos;
2218
+ }
2219
+ case "paragraph-back": {
2220
+ let pos = caret;
2221
+ for (let i = 0; i < n; i++) {
2222
+ pos = prevParagraphBoundary(lines, lineIndexAt(lines, pos));
2223
+ }
2224
+ return pos;
2225
+ }
2226
+ case "line":
2227
+ case "selection":
2228
+ return caret;
2229
+ default: {
2230
+ const _exhaustive = motion;
2231
+ return _exhaustive;
2232
+ }
2233
+ }
2234
+ }
2235
+ function motionRange(text, caret, motion, count, selection) {
2236
+ if (motion === "selection") {
2237
+ if (!selection) return [caret, caret];
2238
+ return [Math.min(selection[0], selection[1]), Math.max(selection[0], selection[1])];
2239
+ }
2240
+ const lines = computeLines(text);
2241
+ if (motion === "line") {
2242
+ const n = Math.max(1, count);
2243
+ const startIdx = lineIndexAt(lines, caret);
2244
+ const endIdx = clamp(startIdx + n - 1, 0, lines.length - 1);
2245
+ const start2 = lines[startIdx].start;
2246
+ const rawEnd = lines[endIdx].end;
2247
+ const end2 = rawEnd < text.length ? rawEnd + 1 : rawEnd;
2248
+ return [start2, end2];
2249
+ }
2250
+ const newCaret = applyMotion(text, caret, motion, count);
2251
+ let start = Math.min(caret, newCaret);
2252
+ let end = Math.max(caret, newCaret);
2253
+ if (motion === "word-end" || motion === "line-end") {
2254
+ end = Math.min(Math.max(start, newCaret) + 1, text.length);
2255
+ } else if (motion === "word-forward" && newCaret > caret) {
2256
+ const startLine = lineIndexAt(lines, caret);
2257
+ const endLine = lineIndexAt(lines, newCaret);
2258
+ if (endLine !== startLine) {
2259
+ end = lines[startLine].end;
2260
+ }
2261
+ }
2262
+ return [start, end];
2263
+ }
2264
+ function applyOperator(text, range, operator, register) {
2265
+ const start = clamp(range[0], 0, text.length);
2266
+ const end = clamp(range[1], start, text.length);
2267
+ const removed = text.slice(start, end);
2268
+ if (operator === "yank") {
2269
+ return { text, caret: start, register: removed };
2270
+ }
2271
+ return { text: text.slice(0, start) + text.slice(end), caret: start, register: removed };
2272
+ }
2273
+
2097
2274
  Object.defineProperty(exports, "PERF_NAMESPACE", {
2098
2275
  enumerable: true,
2099
2276
  get: function () { return ui.PERF_NAMESPACE; }
@@ -2126,6 +2303,8 @@ exports.ApiError = ApiError;
2126
2303
  exports.DEFAULT_CONFIG = DEFAULT_CONFIG;
2127
2304
  exports.JAZARI_COLORS = JAZARI_COLORS;
2128
2305
  exports.apiClient = apiClient;
2306
+ exports.applyMotion = applyMotion;
2307
+ exports.applyOperator = applyOperator;
2129
2308
  exports.arrowheadPath = arrowheadPath;
2130
2309
  exports.bindCanvasCapture = bindCanvasCapture;
2131
2310
  exports.bindEventBus = bindEventBus;
@@ -2200,6 +2379,7 @@ exports.logEventFired = logEventFired;
2200
2379
  exports.logInfo = logInfo;
2201
2380
  exports.logStateChange = logStateChange;
2202
2381
  exports.logWarning = logWarning;
2382
+ exports.motionRange = motionRange;
2203
2383
  exports.onDebugToggle = onDebugToggle;
2204
2384
  exports.parseContentSegments = parseContentSegments;
2205
2385
  exports.parseLessonSegments = parseLessonSegments;
@@ -1,4 +1,4 @@
1
- export { C as ContentSegment, D as DEFAULT_CONFIG, a as DomEntityBox, b as DomLayoutData, c as DomOutputsBox, d as DomStateNode, e as DomTransitionLabel, f as DomTransitionPath, E as EntityDefinition, L as LessonSegment, R as RenderOptions, S as StateDefinition, g as StateMachineDefinition, T as TraitSnapshotGetter, h as TransitionDefinition, V as VisualizerConfig, i as bindCanvasCapture, j as bindEventBus, k as bindLastDrawables, l as bindTraitStateGetter, m as clearVerification, n as cn, o as extractOutputsFromTransitions, p as extractStateMachine, q as formatGuard, r as getAllChecks, s as getBridgeHealth, t as getEffectSummary, u as getSnapshot, v as getSummary, w as getTraitSnapshots, x as getTransitions, y as getTransitionsForTrait, z as parseContentSegments, A as parseLessonSegments, B as parseMarkdownWithCodeBlocks, F as recordServerResponse, G as recordTransition, H as registerCheck, I as registerTraitSnapshot, J as renderStateMachineToDomData, K as renderStateMachineToSvg, M as subscribeToVerification, N as updateAssetStatus, O as updateBridgeHealth, P as updateCheck, Q as waitForTransition } from '../cn-DJSBBm5W.cjs';
1
+ export { C as ContentSegment, D as DEFAULT_CONFIG, a as DomEntityBox, b as DomLayoutData, c as DomOutputsBox, d as DomStateNode, e as DomTransitionLabel, f as DomTransitionPath, E as EditorMotion, g as EditorOperator, h as EntityDefinition, L as LessonSegment, R as RenderOptions, S as StateDefinition, i as StateMachineDefinition, T as TraitSnapshotGetter, j as TransitionDefinition, V as VisualizerConfig, k as applyMotion, l as applyOperator, m as bindCanvasCapture, n as bindEventBus, o as bindLastDrawables, p as bindTraitStateGetter, q as clearVerification, r as cn, s as extractOutputsFromTransitions, t as extractStateMachine, u as formatGuard, v as getAllChecks, w as getBridgeHealth, x as getEffectSummary, y as getSnapshot, z as getSummary, A as getTraitSnapshots, B as getTransitions, F as getTransitionsForTrait, G as motionRange, H as parseContentSegments, I as parseLessonSegments, J as parseMarkdownWithCodeBlocks, K as recordServerResponse, M as recordTransition, N as registerCheck, O as registerTraitSnapshot, P as renderStateMachineToDomData, Q as renderStateMachineToSvg, U as subscribeToVerification, W as updateAssetStatus, X as updateBridgeHealth, Y as updateCheck, Z as waitForTransition } from '../cn-CCjFspAo.cjs';
2
2
  import { FieldValue, EntityRow, EventPayload } from '@almadar/core';
3
3
  export { AssetLoadStatus, BridgeHealth, CheckStatus, EffectTrace, EventLogEntry, OrbitalVerificationAPI, ServerResponseTrace, TraitStateSnapshot, TransitionTrace, VerificationCheck, VerificationSnapshot, VerificationSummary } from '@almadar/core';
4
4
  export { p as profilerOnRender, u as usePerfBuffer } from '../perf-DaVdsbU0.cjs';
@@ -1,4 +1,4 @@
1
- export { C as ContentSegment, D as DEFAULT_CONFIG, a as DomEntityBox, b as DomLayoutData, c as DomOutputsBox, d as DomStateNode, e as DomTransitionLabel, f as DomTransitionPath, E as EntityDefinition, L as LessonSegment, R as RenderOptions, S as StateDefinition, g as StateMachineDefinition, T as TraitSnapshotGetter, h as TransitionDefinition, V as VisualizerConfig, i as bindCanvasCapture, j as bindEventBus, k as bindLastDrawables, l as bindTraitStateGetter, m as clearVerification, n as cn, o as extractOutputsFromTransitions, p as extractStateMachine, q as formatGuard, r as getAllChecks, s as getBridgeHealth, t as getEffectSummary, u as getSnapshot, v as getSummary, w as getTraitSnapshots, x as getTransitions, y as getTransitionsForTrait, z as parseContentSegments, A as parseLessonSegments, B as parseMarkdownWithCodeBlocks, F as recordServerResponse, G as recordTransition, H as registerCheck, I as registerTraitSnapshot, J as renderStateMachineToDomData, K as renderStateMachineToSvg, M as subscribeToVerification, N as updateAssetStatus, O as updateBridgeHealth, P as updateCheck, Q as waitForTransition } from '../cn-BbhJq_nr.js';
1
+ export { C as ContentSegment, D as DEFAULT_CONFIG, a as DomEntityBox, b as DomLayoutData, c as DomOutputsBox, d as DomStateNode, e as DomTransitionLabel, f as DomTransitionPath, E as EditorMotion, g as EditorOperator, h as EntityDefinition, L as LessonSegment, R as RenderOptions, S as StateDefinition, i as StateMachineDefinition, T as TraitSnapshotGetter, j as TransitionDefinition, V as VisualizerConfig, k as applyMotion, l as applyOperator, m as bindCanvasCapture, n as bindEventBus, o as bindLastDrawables, p as bindTraitStateGetter, q as clearVerification, r as cn, s as extractOutputsFromTransitions, t as extractStateMachine, u as formatGuard, v as getAllChecks, w as getBridgeHealth, x as getEffectSummary, y as getSnapshot, z as getSummary, A as getTraitSnapshots, B as getTransitions, F as getTransitionsForTrait, G as motionRange, H as parseContentSegments, I as parseLessonSegments, J as parseMarkdownWithCodeBlocks, K as recordServerResponse, M as recordTransition, N as registerCheck, O as registerTraitSnapshot, P as renderStateMachineToDomData, Q as renderStateMachineToSvg, U as subscribeToVerification, W as updateAssetStatus, X as updateBridgeHealth, Y as updateCheck, Z as waitForTransition } from '../cn-sgpqpN0U.js';
2
2
  import { FieldValue, EntityRow, EventPayload } from '@almadar/core';
3
3
  export { AssetLoadStatus, BridgeHealth, CheckStatus, EffectTrace, EventLogEntry, OrbitalVerificationAPI, ServerResponseTrace, TraitStateSnapshot, TransitionTrace, VerificationCheck, VerificationSnapshot, VerificationSummary } from '@almadar/core';
4
4
  export { p as profilerOnRender, u as usePerfBuffer } from '../perf-DaVdsbU0.js';
package/dist/lib/index.js CHANGED
@@ -2093,4 +2093,181 @@ var JAZARI_COLORS = {
2093
2093
  darkBg: "#1a1a2e"
2094
2094
  };
2095
2095
 
2096
- export { ApiError, DEFAULT_CONFIG, JAZARI_COLORS, apiClient, arrowheadPath, bindCanvasCapture, bindEventBus, bindLastDrawables, bindTraitStateGetter, brainIconPath, clearDebugEvents, clearEntityProvider, clearGuardHistory, clearTicks, clearTraits, clearVerification, cn, compareCellValues, computeJazariLayout, createCommandSendPump, createTickSendRelay, debug, debugCollision, debugError, debugGameState, debugGroup, debugGroupEnd, debugInput, debugPhysics, debugTable, debugTime, debugTimeEnd, debugWarn, eightPointedStarPath, extractOutputsFromTransitions, extractStateMachine, formatDate, formatDateTime, formatGuard, formatNestedFieldLabel, formatTime, formatValue, gearTeethPath, getAllChecks, getAllTicks, getAllTraits, getBridgeHealth, getDebugEvents, getEffectSummary, getEntitiesByType, getEntityById, getEntitySnapshot, getEventsBySource, getEventsByType, getGuardEvaluationsForTrait, getGuardHistory, getNestedValue, getRecentEvents, getRecentGuardEvaluations, getSnapshot, getSummary, getTick, getTrait, getTraitSnapshots, getTransitions, getTransitionsForTrait, humanizeEnumValue, humanizeFieldName, initDebugShortcut, isDebugEnabled, lockIconPath, logDebugEvent, logEffectExecuted, logError, logEventFired, logInfo, logStateChange, logWarning, onDebugToggle, parseContentSegments, parseLessonSegments, parseMarkdownWithCodeBlocks, pipeIconPath, profilerOnRender, recordGuardEvaluation, recordServerResponse, recordTransition, registerCheck, registerTick, registerTrait, registerTraitSnapshot, renderStateMachineToDomData, renderStateMachineToSvg, resolveImageUrl, setDebugEnabled, setEntityProvider, setTickActive, sortRows, subscribeToDebugEvents, subscribeToGuardChanges, subscribeToTickChanges, subscribeToTraitChanges, subscribeToVerification, toggleDebug, unregisterTick, unregisterTrait, updateAssetStatus, updateBridgeHealth, updateCheck, updateGuardResult, updateTickExecution, updateTraitState, usePerfBuffer, waitForTransition };
2096
+ // lib/editorMotions.ts
2097
+ function clamp(value, min, max) {
2098
+ return Math.max(min, Math.min(max, value));
2099
+ }
2100
+ function computeLines(text) {
2101
+ const lines = [];
2102
+ let start = 0;
2103
+ for (let i = 0; i <= text.length; i++) {
2104
+ if (i === text.length || text[i] === "\n") {
2105
+ lines.push({ start, end: i });
2106
+ start = i + 1;
2107
+ }
2108
+ }
2109
+ return lines;
2110
+ }
2111
+ function lineIndexAt(lines, pos) {
2112
+ for (let i = 0; i < lines.length; i++) {
2113
+ if (pos <= lines[i].end) return i;
2114
+ }
2115
+ return lines.length - 1;
2116
+ }
2117
+ function findWords(text) {
2118
+ const words = [];
2119
+ const re = /\w+|\S+/g;
2120
+ let m;
2121
+ while ((m = re.exec(text)) !== null) {
2122
+ words.push({ start: m.index, end: m.index + m[0].length });
2123
+ }
2124
+ return words;
2125
+ }
2126
+ function nextWordStart(text, pos) {
2127
+ for (const w of findWords(text)) {
2128
+ if (w.start > pos) return w.start;
2129
+ }
2130
+ return text.length;
2131
+ }
2132
+ function prevWordStart(text, pos) {
2133
+ let result = 0;
2134
+ for (const w of findWords(text)) {
2135
+ if (w.start < pos) result = w.start;
2136
+ else break;
2137
+ }
2138
+ return result;
2139
+ }
2140
+ function nextWordEnd(text, pos) {
2141
+ for (const w of findWords(text)) {
2142
+ const lastChar = w.end - 1;
2143
+ if (lastChar > pos) return lastChar;
2144
+ }
2145
+ return text.length > 0 ? text.length - 1 : 0;
2146
+ }
2147
+ function firstNonBlank(text, line) {
2148
+ let i = line.start;
2149
+ while (i < line.end && (text[i] === " " || text[i] === " ")) i++;
2150
+ return i;
2151
+ }
2152
+ function nextParagraphBoundary(lines, fromLineIdx, textLength) {
2153
+ for (let i = fromLineIdx + 1; i < lines.length; i++) {
2154
+ if (lines[i].start === lines[i].end) return lines[i].start;
2155
+ }
2156
+ return textLength;
2157
+ }
2158
+ function prevParagraphBoundary(lines, fromLineIdx) {
2159
+ for (let i = fromLineIdx - 1; i >= 0; i--) {
2160
+ if (lines[i].start === lines[i].end) return lines[i].start;
2161
+ }
2162
+ return 0;
2163
+ }
2164
+ function applyMotion(text, caret, motion, count) {
2165
+ const n = Math.max(1, count);
2166
+ const lines = computeLines(text);
2167
+ const lineIdx = lineIndexAt(lines, caret);
2168
+ const line = lines[lineIdx];
2169
+ switch (motion) {
2170
+ case "left":
2171
+ return clamp(caret - n, line.start, line.end);
2172
+ case "right":
2173
+ return clamp(caret + n, line.start, line.end);
2174
+ case "up": {
2175
+ const col = caret - line.start;
2176
+ const targetIdx = clamp(lineIdx - n, 0, lines.length - 1);
2177
+ const target = lines[targetIdx];
2178
+ return clamp(target.start + col, target.start, target.end);
2179
+ }
2180
+ case "down": {
2181
+ const col = caret - line.start;
2182
+ const targetIdx = clamp(lineIdx + n, 0, lines.length - 1);
2183
+ const target = lines[targetIdx];
2184
+ return clamp(target.start + col, target.start, target.end);
2185
+ }
2186
+ case "word-forward": {
2187
+ let pos = caret;
2188
+ for (let i = 0; i < n; i++) pos = nextWordStart(text, pos);
2189
+ return pos;
2190
+ }
2191
+ case "word-back": {
2192
+ let pos = caret;
2193
+ for (let i = 0; i < n; i++) pos = prevWordStart(text, pos);
2194
+ return pos;
2195
+ }
2196
+ case "word-end": {
2197
+ let pos = caret;
2198
+ for (let i = 0; i < n; i++) pos = nextWordEnd(text, pos);
2199
+ return pos;
2200
+ }
2201
+ case "line-start":
2202
+ return line.start;
2203
+ case "line-end":
2204
+ return line.end > line.start ? line.end - 1 : line.start;
2205
+ case "first-nonblank":
2206
+ return firstNonBlank(text, line);
2207
+ case "doc-start":
2208
+ return 0;
2209
+ case "doc-end":
2210
+ return text.length;
2211
+ case "paragraph-forward": {
2212
+ let pos = caret;
2213
+ for (let i = 0; i < n; i++) {
2214
+ pos = nextParagraphBoundary(lines, lineIndexAt(lines, pos), text.length);
2215
+ }
2216
+ return pos;
2217
+ }
2218
+ case "paragraph-back": {
2219
+ let pos = caret;
2220
+ for (let i = 0; i < n; i++) {
2221
+ pos = prevParagraphBoundary(lines, lineIndexAt(lines, pos));
2222
+ }
2223
+ return pos;
2224
+ }
2225
+ case "line":
2226
+ case "selection":
2227
+ return caret;
2228
+ default: {
2229
+ const _exhaustive = motion;
2230
+ return _exhaustive;
2231
+ }
2232
+ }
2233
+ }
2234
+ function motionRange(text, caret, motion, count, selection) {
2235
+ if (motion === "selection") {
2236
+ if (!selection) return [caret, caret];
2237
+ return [Math.min(selection[0], selection[1]), Math.max(selection[0], selection[1])];
2238
+ }
2239
+ const lines = computeLines(text);
2240
+ if (motion === "line") {
2241
+ const n = Math.max(1, count);
2242
+ const startIdx = lineIndexAt(lines, caret);
2243
+ const endIdx = clamp(startIdx + n - 1, 0, lines.length - 1);
2244
+ const start2 = lines[startIdx].start;
2245
+ const rawEnd = lines[endIdx].end;
2246
+ const end2 = rawEnd < text.length ? rawEnd + 1 : rawEnd;
2247
+ return [start2, end2];
2248
+ }
2249
+ const newCaret = applyMotion(text, caret, motion, count);
2250
+ let start = Math.min(caret, newCaret);
2251
+ let end = Math.max(caret, newCaret);
2252
+ if (motion === "word-end" || motion === "line-end") {
2253
+ end = Math.min(Math.max(start, newCaret) + 1, text.length);
2254
+ } else if (motion === "word-forward" && newCaret > caret) {
2255
+ const startLine = lineIndexAt(lines, caret);
2256
+ const endLine = lineIndexAt(lines, newCaret);
2257
+ if (endLine !== startLine) {
2258
+ end = lines[startLine].end;
2259
+ }
2260
+ }
2261
+ return [start, end];
2262
+ }
2263
+ function applyOperator(text, range, operator, register) {
2264
+ const start = clamp(range[0], 0, text.length);
2265
+ const end = clamp(range[1], start, text.length);
2266
+ const removed = text.slice(start, end);
2267
+ if (operator === "yank") {
2268
+ return { text, caret: start, register: removed };
2269
+ }
2270
+ return { text: text.slice(0, start) + text.slice(end), caret: start, register: removed };
2271
+ }
2272
+
2273
+ export { ApiError, DEFAULT_CONFIG, JAZARI_COLORS, apiClient, applyMotion, applyOperator, arrowheadPath, bindCanvasCapture, bindEventBus, bindLastDrawables, bindTraitStateGetter, brainIconPath, clearDebugEvents, clearEntityProvider, clearGuardHistory, clearTicks, clearTraits, clearVerification, cn, compareCellValues, computeJazariLayout, createCommandSendPump, createTickSendRelay, debug, debugCollision, debugError, debugGameState, debugGroup, debugGroupEnd, debugInput, debugPhysics, debugTable, debugTime, debugTimeEnd, debugWarn, eightPointedStarPath, extractOutputsFromTransitions, extractStateMachine, formatDate, formatDateTime, formatGuard, formatNestedFieldLabel, formatTime, formatValue, gearTeethPath, getAllChecks, getAllTicks, getAllTraits, getBridgeHealth, getDebugEvents, getEffectSummary, getEntitiesByType, getEntityById, getEntitySnapshot, getEventsBySource, getEventsByType, getGuardEvaluationsForTrait, getGuardHistory, getNestedValue, getRecentEvents, getRecentGuardEvaluations, getSnapshot, getSummary, getTick, getTrait, getTraitSnapshots, getTransitions, getTransitionsForTrait, humanizeEnumValue, humanizeFieldName, initDebugShortcut, isDebugEnabled, lockIconPath, logDebugEvent, logEffectExecuted, logError, logEventFired, logInfo, logStateChange, logWarning, motionRange, onDebugToggle, parseContentSegments, parseLessonSegments, parseMarkdownWithCodeBlocks, pipeIconPath, profilerOnRender, recordGuardEvaluation, recordServerResponse, recordTransition, registerCheck, registerTick, registerTrait, registerTraitSnapshot, renderStateMachineToDomData, renderStateMachineToSvg, resolveImageUrl, setDebugEnabled, setEntityProvider, setTickActive, sortRows, subscribeToDebugEvents, subscribeToGuardChanges, subscribeToTickChanges, subscribeToTraitChanges, subscribeToVerification, toggleDebug, unregisterTick, unregisterTrait, updateAssetStatus, updateBridgeHealth, updateCheck, updateGuardResult, updateTickExecution, updateTraitState, usePerfBuffer, waitForTransition };
@@ -556,7 +556,8 @@ var en_default = {
556
556
  "richTextEditor.image": "Insert image",
557
557
  "richTextEditor.imagePrompt": "Image URL",
558
558
  "richTextEditor.placeholder": "Start writing\u2026",
559
- "form.imageUrlFallback": "\u2026or paste an image address"
559
+ "form.imageUrlFallback": "\u2026or paste an image address",
560
+ "mermaid.unrenderable": "This diagram could not be displayed. Its source is shown below."
560
561
  };
561
562
 
562
563
  // locales/ar.json
@@ -1115,7 +1116,8 @@ var ar_default = {
1115
1116
  "richTextEditor.image": "\u0625\u062F\u0631\u0627\u062C \u0635\u0648\u0631\u0629",
1116
1117
  "richTextEditor.imagePrompt": "\u0631\u0627\u0628\u0637 \u0627\u0644\u0635\u0648\u0631\u0629",
1117
1118
  "richTextEditor.placeholder": "\u0627\u0628\u062F\u0623 \u0627\u0644\u0643\u062A\u0627\u0628\u0629\u2026",
1118
- "form.imageUrlFallback": "\u2026\u0623\u0648 \u0627\u0644\u0635\u0642 \u0631\u0627\u0628\u0637 \u0627\u0644\u0635\u0648\u0631\u0629"
1119
+ "form.imageUrlFallback": "\u2026\u0623\u0648 \u0627\u0644\u0635\u0642 \u0631\u0627\u0628\u0637 \u0627\u0644\u0635\u0648\u0631\u0629",
1120
+ "mermaid.unrenderable": "\u062A\u0639\u0630\u0631 \u0639\u0631\u0636 \u0647\u0630\u0627 \u0627\u0644\u0645\u062E\u0637\u0637. \u064A\u0638\u0647\u0631 \u0645\u0635\u062F\u0631\u0647 \u0623\u062F\u0646\u0627\u0647."
1119
1121
  };
1120
1122
 
1121
1123
  // locales/sl.json
@@ -1674,7 +1676,8 @@ var sl_default = {
1674
1676
  "richTextEditor.image": "Vstavi sliko",
1675
1677
  "richTextEditor.imagePrompt": "URL slike",
1676
1678
  "richTextEditor.placeholder": "Za\u010Dnite pisati \u2026",
1677
- "form.imageUrlFallback": "\u2026ali prilepite naslov slike"
1679
+ "form.imageUrlFallback": "\u2026ali prilepite naslov slike",
1680
+ "mermaid.unrenderable": "Tega diagrama ni bilo mogo\u010De prikazati. Njegova izvorna koda je prikazana spodaj."
1678
1681
  };
1679
1682
 
1680
1683
  // locales/index.ts