@almadar/ui 6.8.0 → 6.10.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 (33) hide show
  1. package/dist/{EntityBindingContext-Bn3ePJQC.d.cts → EntityBindingContext-Y4zXyNJZ.d.cts} +14 -2
  2. package/dist/{EntityBindingContext-Bn3ePJQC.d.ts → EntityBindingContext-Y4zXyNJZ.d.ts} +14 -2
  3. package/dist/avl/index.cjs +531 -48
  4. package/dist/avl/index.js +531 -48
  5. package/dist/{cn-sgpqpN0U.d.ts → cn-C7fvp9gH.d.ts} +37 -10
  6. package/dist/{cn-CCjFspAo.d.cts → cn-DnLYahyL.d.cts} +37 -10
  7. package/dist/components/index.cjs +557 -47
  8. package/dist/components/index.d.cts +6 -4
  9. package/dist/components/index.d.ts +6 -4
  10. package/dist/components/index.js +556 -48
  11. package/dist/hooks/index.cjs +30 -1
  12. package/dist/hooks/index.d.cts +2 -2
  13. package/dist/hooks/index.d.ts +2 -2
  14. package/dist/hooks/index.js +29 -2
  15. package/dist/lib/drawable/three/index.cjs +21 -2
  16. package/dist/lib/drawable/three/index.js +21 -2
  17. package/dist/lib/index.cjs +238 -9
  18. package/dist/lib/index.d.cts +1 -1
  19. package/dist/lib/index.d.ts +1 -1
  20. package/dist/lib/index.js +234 -10
  21. package/dist/marketing/index.cjs +12 -3
  22. package/dist/marketing/index.js +12 -3
  23. package/dist/providers/index.cjs +556 -56
  24. package/dist/providers/index.d.cts +1 -1
  25. package/dist/providers/index.d.ts +1 -1
  26. package/dist/providers/index.js +556 -56
  27. package/dist/runtime/index.cjs +545 -52
  28. package/dist/runtime/index.d.cts +13 -6
  29. package/dist/runtime/index.d.ts +13 -6
  30. package/dist/runtime/index.js +545 -52
  31. package/dist/{useKeyboardRouter-D84cNWmA.d.ts → useKeyboardRouter-B1pIi9jo.d.ts} +11 -1
  32. package/dist/{useKeyboardRouter-DQEE_9mq.d.cts → useKeyboardRouter-CVn8lfiX.d.cts} +11 -1
  33. package/package.json +3 -3
@@ -1141,7 +1141,7 @@ var init_Button = __esm({
1141
1141
  secondary: [
1142
1142
  "bg-transparent text-accent",
1143
1143
  "border border-accent",
1144
- "hover:bg-accent hover:text-white hover:border-accent",
1144
+ "hover:bg-accent hover:text-accent-foreground hover:border-accent",
1145
1145
  "active:scale-[var(--active-scale)]"
1146
1146
  ].join(" "),
1147
1147
  ghost: [
@@ -1481,8 +1481,17 @@ var init_Typography = __esm({
1481
1481
  weight && weightStyles[weight],
1482
1482
  size && typographySizeStyles[size],
1483
1483
  align && `text-${align}`,
1484
- truncate && "truncate overflow-hidden text-ellipsis",
1485
- overflow && overflowStyles2[overflow],
1484
+ // `min-w-0` rides along with truncate/wrap/clamp: a flex or grid
1485
+ // item's default `min-width: auto` refuses to shrink below its
1486
+ // content's intrinsic width, so ellipsis/wrap silently does nothing
1487
+ // in the single most common placement (a row next to a fixed-width
1488
+ // control) unless the item can also shrink to zero. (Spelled out as
1489
+ // just "truncate", not "truncate overflow-hidden text-ellipsis" —
1490
+ // tailwind-merge treats those as the same conflict group and drops
1491
+ // "truncate" as the earlier-declared class, silently losing its
1492
+ // `white-space: nowrap`.)
1493
+ truncate && "truncate min-w-0",
1494
+ overflow && cn(overflowStyles2[overflow], overflow !== "visible" && "min-w-0"),
1486
1495
  className
1487
1496
  ),
1488
1497
  style
@@ -9966,6 +9975,10 @@ var init_paintDispatch = __esm({
9966
9975
  });
9967
9976
 
9968
9977
  // lib/drawable/hitTest.ts
9978
+ function shapeDrawnItem(n) {
9979
+ if (n.shape !== "rect") return { pos: n.position, id: n.id };
9980
+ return { pos: n.position, id: n.id, anchor: n.anchor, width: n.width, height: n.height, rotation: n.rotate };
9981
+ }
9969
9982
  function collectDrawnItems(nodes) {
9970
9983
  const out = [];
9971
9984
  for (const n of nodes) {
@@ -9974,6 +9987,8 @@ function collectDrawnItems(nodes) {
9974
9987
  if (isValidScenePos(n.position)) out.push({ pos: n.position, id: n.id, anchor: n.anchor, width: n.width, height: n.height, rotation: n.rotation });
9975
9988
  break;
9976
9989
  case "draw-shape":
9990
+ if (isValidScenePos(n.position)) out.push(shapeDrawnItem(n));
9991
+ break;
9977
9992
  case "draw-text":
9978
9993
  case "draw-group":
9979
9994
  case "draw-mesh":
@@ -9985,6 +10000,10 @@ function collectDrawnItems(nodes) {
9985
10000
  }
9986
10001
  break;
9987
10002
  case "draw-shape-layer":
10003
+ for (const it of n.items) {
10004
+ if (isValidScenePos(it.position)) out.push(shapeDrawnItem(it));
10005
+ }
10006
+ break;
9988
10007
  case "draw-text-layer":
9989
10008
  for (const it of n.items) {
9990
10009
  if (isValidScenePos(it.position)) out.push({ pos: it.position, id: it.id });
@@ -17490,6 +17509,12 @@ var init_EmptyState = __esm({
17490
17509
  });
17491
17510
 
17492
17511
  // lib/editorMotions.ts
17512
+ function isEditorMotion(value) {
17513
+ return EDITOR_MOTION_SET.has(value);
17514
+ }
17515
+ function isEditorOperator(value) {
17516
+ return EDITOR_OPERATOR_SET.has(value);
17517
+ }
17493
17518
  function clamp(value, min, max) {
17494
17519
  return Math.max(min, Math.min(max, value));
17495
17520
  }
@@ -17557,6 +17582,30 @@ function prevParagraphBoundary(lines, fromLineIdx) {
17557
17582
  }
17558
17583
  return 0;
17559
17584
  }
17585
+ function matchBracket(text, pos) {
17586
+ const ch = text[pos];
17587
+ const partner = ch !== void 0 ? BRACKET_PARTNER[ch] : void 0;
17588
+ if (partner === void 0) return null;
17589
+ let depth = 1;
17590
+ if (OPEN_BRACKETS.has(ch)) {
17591
+ for (let i = pos + 1; i < text.length; i++) {
17592
+ if (text[i] === ch) depth++;
17593
+ else if (text[i] === partner) {
17594
+ depth--;
17595
+ if (depth === 0) return i;
17596
+ }
17597
+ }
17598
+ } else {
17599
+ for (let i = pos - 1; i >= 0; i--) {
17600
+ if (text[i] === ch) depth++;
17601
+ else if (text[i] === partner) {
17602
+ depth--;
17603
+ if (depth === 0) return i;
17604
+ }
17605
+ }
17606
+ }
17607
+ return null;
17608
+ }
17560
17609
  function applyMotion(text, caret, motion, count) {
17561
17610
  const n = Math.max(1, count);
17562
17611
  const lines = computeLines(text);
@@ -17618,6 +17667,20 @@ function applyMotion(text, caret, motion, count) {
17618
17667
  }
17619
17668
  return pos;
17620
17669
  }
17670
+ case "match-bracket": {
17671
+ const chAtCaret = text[caret];
17672
+ if (chAtCaret !== void 0 && BRACKET_PARTNER[chAtCaret] !== void 0) {
17673
+ const target = matchBracket(text, caret);
17674
+ return target === null ? caret : target;
17675
+ }
17676
+ for (let i = caret; i < line.end; i++) {
17677
+ if (BRACKET_PARTNER[text[i]] !== void 0) {
17678
+ const target = matchBracket(text, i);
17679
+ return target === null ? caret : target;
17680
+ }
17681
+ }
17682
+ return caret;
17683
+ }
17621
17684
  case "line":
17622
17685
  case "selection":
17623
17686
  return caret;
@@ -17645,8 +17708,8 @@ function motionRange(text, caret, motion, count, selection) {
17645
17708
  const newCaret = applyMotion(text, caret, motion, count);
17646
17709
  let start = Math.min(caret, newCaret);
17647
17710
  let end = Math.max(caret, newCaret);
17648
- if (motion === "word-end" || motion === "line-end") {
17649
- end = Math.min(Math.max(start, newCaret) + 1, text.length);
17711
+ if ((motion === "word-end" || motion === "line-end" || motion === "match-bracket") && newCaret !== caret) {
17712
+ end = Math.min(Math.max(caret, newCaret) + 1, text.length);
17650
17713
  } else if (motion === "word-forward" && newCaret > caret) {
17651
17714
  const startLine = lineIndexAt(lines, caret);
17652
17715
  const endLine = lineIndexAt(lines, newCaret);
@@ -17656,17 +17719,198 @@ function motionRange(text, caret, motion, count, selection) {
17656
17719
  }
17657
17720
  return [start, end];
17658
17721
  }
17659
- function applyOperator(text, range, operator, register) {
17660
- const start = clamp(range[0], 0, text.length);
17661
- const end = clamp(range[1], start, text.length);
17662
- const removed = text.slice(start, end);
17663
- if (operator === "yank") {
17664
- return { text, caret: start, register: removed };
17722
+ function toggleCase(s) {
17723
+ return s.replace(/[a-zA-Z]/g, (c) => c === c.toUpperCase() ? c.toLowerCase() : c.toUpperCase());
17724
+ }
17725
+ function applyJoin(text, caret, count, register, registerLinewise) {
17726
+ const lines = computeLines(text);
17727
+ const startIdx = lineIndexAt(lines, caret);
17728
+ const n = Math.max(2, count);
17729
+ const endIdx = clamp(startIdx + n - 1, 0, lines.length - 1);
17730
+ if (endIdx <= startIdx) {
17731
+ return { text, caret, register, registerLinewise };
17732
+ }
17733
+ const joinCaret = lines[startIdx].end;
17734
+ let joined = text.slice(lines[startIdx].start, lines[startIdx].end);
17735
+ for (let i = startIdx + 1; i <= endIdx; i++) {
17736
+ const raw = text.slice(lines[i].start, lines[i].end);
17737
+ joined += " " + raw.replace(/^[ \t]+/, "");
17738
+ }
17739
+ const newText = text.slice(0, lines[startIdx].start) + joined + text.slice(lines[endIdx].end);
17740
+ return { text: newText, caret: joinCaret, register, registerLinewise };
17741
+ }
17742
+ function applyIndent(text, start, end, operator, register, registerLinewise) {
17743
+ const lines = computeLines(text);
17744
+ const startLineIdx = lineIndexAt(lines, start);
17745
+ const lastTouchedPos = end > start ? end - 1 : start;
17746
+ const endLineIdx = lineIndexAt(lines, lastTouchedPos);
17747
+ let result = text;
17748
+ for (let i = endLineIdx; i >= startLineIdx; i--) {
17749
+ const lineStart = lines[i].start;
17750
+ if (operator === "indent") {
17751
+ result = result.slice(0, lineStart) + INDENT_UNIT + result.slice(lineStart);
17752
+ } else if (result[lineStart] === " ") {
17753
+ result = result.slice(0, lineStart) + result.slice(lineStart + 1);
17754
+ } else {
17755
+ let removeCount = 0;
17756
+ while (removeCount < INDENT_UNIT.length && result[lineStart + removeCount] === " ") removeCount++;
17757
+ result = result.slice(0, lineStart) + result.slice(lineStart + removeCount);
17758
+ }
17759
+ }
17760
+ const newLines = computeLines(result);
17761
+ const caret = firstNonBlank(result, newLines[startLineIdx]);
17762
+ return { text: result, caret, register, registerLinewise };
17763
+ }
17764
+ function applyPut(text, caret, operator, register, registerLinewise, count) {
17765
+ if (register.length === 0) {
17766
+ return { text, caret, register, registerLinewise };
17767
+ }
17768
+ const content = register.repeat(count);
17769
+ const lines = computeLines(text);
17770
+ const line = lines[lineIndexAt(lines, caret)];
17771
+ if (registerLinewise) {
17772
+ if (operator === "put-before") {
17773
+ const insertPos3 = line.start;
17774
+ return {
17775
+ text: text.slice(0, insertPos3) + content + text.slice(insertPos3),
17776
+ caret: insertPos3,
17777
+ register,
17778
+ registerLinewise
17779
+ };
17780
+ }
17781
+ const nextLineIdx = lineIndexAt(lines, caret) + 1;
17782
+ if (nextLineIdx < lines.length) {
17783
+ const insertPos3 = lines[nextLineIdx].start;
17784
+ return {
17785
+ text: text.slice(0, insertPos3) + content + text.slice(insertPos3),
17786
+ caret: insertPos3,
17787
+ register,
17788
+ registerLinewise
17789
+ };
17790
+ }
17791
+ const insertPos2 = text.length;
17792
+ return {
17793
+ text: text.slice(0, insertPos2) + "\n" + content,
17794
+ caret: insertPos2 + 1,
17795
+ register,
17796
+ registerLinewise
17797
+ };
17798
+ }
17799
+ const insertPos = operator === "put-before" ? clamp(caret, 0, text.length) : clamp(caret + 1, line.start, line.end);
17800
+ return {
17801
+ text: text.slice(0, insertPos) + content + text.slice(insertPos),
17802
+ caret: insertPos + content.length - 1,
17803
+ register,
17804
+ registerLinewise
17805
+ };
17806
+ }
17807
+ function applyOperator(input) {
17808
+ const { text, caret, operator, motion, register, registerLinewise } = input;
17809
+ const count = Math.max(1, input.count);
17810
+ const start = clamp(input.range[0], 0, text.length);
17811
+ const end = clamp(input.range[1], start, text.length);
17812
+ switch (operator) {
17813
+ case "yank":
17814
+ return { text, caret: start, register: text.slice(start, end), registerLinewise: motion === "line" };
17815
+ case "delete":
17816
+ case "replace": {
17817
+ const removed = text.slice(start, end);
17818
+ return {
17819
+ text: text.slice(0, start) + text.slice(end),
17820
+ caret: start,
17821
+ register: removed,
17822
+ registerLinewise: motion === "line"
17823
+ };
17824
+ }
17825
+ case "change": {
17826
+ if (motion === "line") {
17827
+ const hasTrailingNewline = end > start && text[end - 1] === "\n";
17828
+ const removeEnd = hasTrailingNewline ? end - 1 : end;
17829
+ const removed2 = text.slice(start, removeEnd);
17830
+ return {
17831
+ text: text.slice(0, start) + text.slice(removeEnd),
17832
+ caret: start,
17833
+ register: removed2,
17834
+ registerLinewise: true
17835
+ };
17836
+ }
17837
+ const removed = text.slice(start, end);
17838
+ return {
17839
+ text: text.slice(0, start) + text.slice(end),
17840
+ caret: start,
17841
+ register: removed,
17842
+ registerLinewise: false
17843
+ };
17844
+ }
17845
+ case "put":
17846
+ case "put-before":
17847
+ return applyPut(text, caret, operator, register, registerLinewise, count);
17848
+ case "join":
17849
+ return applyJoin(text, caret, count, register, registerLinewise);
17850
+ case "toggle-case": {
17851
+ const toggled = toggleCase(text.slice(start, end));
17852
+ return { text: text.slice(0, start) + toggled + text.slice(end), caret: end, register, registerLinewise };
17853
+ }
17854
+ case "indent":
17855
+ case "dedent":
17856
+ return applyIndent(text, start, end, operator, register, registerLinewise);
17857
+ case "undo":
17858
+ case "redo":
17859
+ return { text, caret, register, registerLinewise };
17860
+ default: {
17861
+ const _exhaustive = operator;
17862
+ return _exhaustive;
17863
+ }
17665
17864
  }
17666
- return { text: text.slice(0, start) + text.slice(end), caret: start, register: removed };
17667
17865
  }
17866
+ var EDITOR_MOTIONS, EDITOR_OPERATORS, EDITOR_MOTION_SET, EDITOR_OPERATOR_SET, INDENT_UNIT, BRACKET_PARTNER, OPEN_BRACKETS;
17668
17867
  var init_editorMotions = __esm({
17669
17868
  "lib/editorMotions.ts"() {
17869
+ EDITOR_MOTIONS = [
17870
+ "left",
17871
+ "right",
17872
+ "up",
17873
+ "down",
17874
+ "word-forward",
17875
+ "word-back",
17876
+ "word-end",
17877
+ "line-start",
17878
+ "line-end",
17879
+ "first-nonblank",
17880
+ "doc-start",
17881
+ "doc-end",
17882
+ "paragraph-forward",
17883
+ "paragraph-back",
17884
+ "line",
17885
+ "selection",
17886
+ "match-bracket"
17887
+ ];
17888
+ EDITOR_OPERATORS = [
17889
+ "delete",
17890
+ "yank",
17891
+ "change",
17892
+ "put",
17893
+ "put-before",
17894
+ "undo",
17895
+ "redo",
17896
+ "join",
17897
+ "toggle-case",
17898
+ "indent",
17899
+ "dedent",
17900
+ "replace"
17901
+ ];
17902
+ EDITOR_MOTION_SET = new Set(EDITOR_MOTIONS);
17903
+ EDITOR_OPERATOR_SET = new Set(EDITOR_OPERATORS);
17904
+ INDENT_UNIT = " ";
17905
+ BRACKET_PARTNER = {
17906
+ "(": ")",
17907
+ ")": "(",
17908
+ "[": "]",
17909
+ "]": "[",
17910
+ "{": "}",
17911
+ "}": "{"
17912
+ };
17913
+ OPEN_BRACKETS = /* @__PURE__ */ new Set(["(", "[", "{"]);
17670
17914
  }
17671
17915
  });
17672
17916
  function isMotionPayload(payload) {
@@ -17681,14 +17925,103 @@ function isInsertTextPayload(payload) {
17681
17925
  function isSetModePayload(payload) {
17682
17926
  return !!payload && typeof payload.editorId === "string" && typeof payload.mode === "string" && typeof payload.caret === "string";
17683
17927
  }
17928
+ function typedDelta(prev, next) {
17929
+ const maxPrefix = Math.min(prev.length, next.length);
17930
+ let prefixLen = 0;
17931
+ while (prefixLen < maxPrefix && prev[prefixLen] === next[prefixLen]) prefixLen++;
17932
+ const maxSuffix = Math.min(prev.length - prefixLen, next.length - prefixLen);
17933
+ let suffixLen = 0;
17934
+ while (suffixLen < maxSuffix && prev[prev.length - 1 - suffixLen] === next[next.length - 1 - suffixLen]) {
17935
+ suffixLen++;
17936
+ }
17937
+ const removed = prev.slice(prefixLen, prev.length - suffixLen);
17938
+ const inserted = next.slice(prefixLen, next.length - suffixLen);
17939
+ return removed + inserted;
17940
+ }
17684
17941
  function useEditorCapabilities(args) {
17685
17942
  const [caretMode, setCaretMode] = useState("bar");
17686
17943
  const registerRef = useRef("");
17944
+ const registerLinewiseRef = useRef(false);
17945
+ const pastRef = useRef([]);
17946
+ const futureRef = useRef([]);
17947
+ const openTypingStepRef = useRef(false);
17948
+ const insertSessionOpenRef = useRef(false);
17949
+ const closeOpenTypingStep = useCallback(() => {
17950
+ openTypingStepRef.current = false;
17951
+ }, []);
17952
+ const pushHistoryStep = useCallback(
17953
+ (text, caret) => {
17954
+ closeOpenTypingStep();
17955
+ pastRef.current.push({ text, caret });
17956
+ futureRef.current = [];
17957
+ },
17958
+ [closeOpenTypingStep]
17959
+ );
17960
+ const recordKeystroke = useCallback(
17961
+ (prevText, prevCaret, nextText) => {
17962
+ if (!openTypingStepRef.current) {
17963
+ pastRef.current.push({ text: prevText, caret: prevCaret });
17964
+ futureRef.current = [];
17965
+ openTypingStepRef.current = true;
17966
+ }
17967
+ if (!insertSessionOpenRef.current && /\s/.test(typedDelta(prevText, nextText))) {
17968
+ openTypingStepRef.current = false;
17969
+ }
17970
+ },
17971
+ []
17972
+ );
17973
+ const performUndo = useCallback(
17974
+ (count) => {
17975
+ const ta = args.textareaRef.current;
17976
+ if (!ta) return;
17977
+ closeOpenTypingStep();
17978
+ let moved = false;
17979
+ for (let i = 0; i < Math.max(1, count) && pastRef.current.length > 0; i++) {
17980
+ const prev = pastRef.current.pop();
17981
+ futureRef.current.push({ text: ta.value, caret: ta.selectionStart });
17982
+ ta.value = prev.text;
17983
+ ta.setSelectionRange(prev.caret, prev.caret);
17984
+ moved = true;
17985
+ }
17986
+ if (moved) args.applyChange(ta.value, "capability");
17987
+ },
17988
+ [args, closeOpenTypingStep]
17989
+ );
17990
+ const performRedo = useCallback(
17991
+ (count) => {
17992
+ const ta = args.textareaRef.current;
17993
+ if (!ta) return;
17994
+ closeOpenTypingStep();
17995
+ let moved = false;
17996
+ for (let i = 0; i < Math.max(1, count) && futureRef.current.length > 0; i++) {
17997
+ const next = futureRef.current.pop();
17998
+ pastRef.current.push({ text: ta.value, caret: ta.selectionStart });
17999
+ ta.value = next.text;
18000
+ ta.setSelectionRange(next.caret, next.caret);
18001
+ moved = true;
18002
+ }
18003
+ if (moved) args.applyChange(ta.value, "capability");
18004
+ },
18005
+ [args, closeOpenTypingStep]
18006
+ );
18007
+ const undo = useCallback(() => performUndo(1), [performUndo]);
18008
+ const redo = useCallback(() => performRedo(1), [performRedo]);
18009
+ const wasFocusedRef = useRef(args.focused);
18010
+ useEffect(() => {
18011
+ if (wasFocusedRef.current && !args.focused) {
18012
+ setCaretMode("bar");
18013
+ }
18014
+ wasFocusedRef.current = args.focused;
18015
+ }, [args.focused]);
17687
18016
  useEventListener(`UI:${args.events.onMotion}`, (evt) => {
17688
18017
  if (!args.editorId || !isMotionPayload(evt.payload) || evt.payload.editorId !== args.editorId) return;
18018
+ const { motion, count } = evt.payload;
18019
+ if (!isEditorMotion(motion)) {
18020
+ console.warn(`useEditorCapabilities: ignoring MOTION with unknown motion "${motion}"`);
18021
+ return;
18022
+ }
17689
18023
  const ta = args.textareaRef.current;
17690
18024
  if (!ta) return;
17691
- const { motion, count } = evt.payload;
17692
18025
  const newCaret = applyMotion(ta.value, ta.selectionStart, motion, count);
17693
18026
  if (ta.selectionStart !== ta.selectionEnd) {
17694
18027
  ta.setSelectionRange(ta.selectionStart, newCaret);
@@ -17698,32 +18031,63 @@ function useEditorCapabilities(args) {
17698
18031
  });
17699
18032
  useEventListener(`UI:${args.events.onOperate}`, (evt) => {
17700
18033
  if (!args.editorId || !isOperatePayload(evt.payload) || evt.payload.editorId !== args.editorId) return;
18034
+ const { operator, motion, count } = evt.payload;
18035
+ if (!isEditorOperator(operator)) {
18036
+ console.warn(`useEditorCapabilities: ignoring OPERATE with unknown operator "${operator}"`);
18037
+ return;
18038
+ }
18039
+ if (!isEditorMotion(motion)) {
18040
+ console.warn(`useEditorCapabilities: ignoring OPERATE with unknown motion "${motion}"`);
18041
+ return;
18042
+ }
17701
18043
  const ta = args.textareaRef.current;
17702
18044
  if (!ta) return;
17703
- const { operator, motion, count } = evt.payload;
18045
+ if (operator === "undo") {
18046
+ performUndo(count);
18047
+ return;
18048
+ }
18049
+ if (operator === "redo") {
18050
+ performRedo(count);
18051
+ return;
18052
+ }
18053
+ pushHistoryStep(ta.value, ta.selectionStart);
17704
18054
  const selection = motion === "selection" ? [ta.selectionStart, ta.selectionEnd] : void 0;
17705
18055
  const range = motionRange(ta.value, ta.selectionStart, motion, count, selection);
17706
- const result = applyOperator(ta.value, range, operator, registerRef.current);
18056
+ const result = applyOperator({
18057
+ text: ta.value,
18058
+ caret: ta.selectionStart,
18059
+ range,
18060
+ operator,
18061
+ motion,
18062
+ count,
18063
+ register: registerRef.current,
18064
+ registerLinewise: registerLinewiseRef.current
18065
+ });
17707
18066
  registerRef.current = result.register;
18067
+ registerLinewiseRef.current = result.registerLinewise;
17708
18068
  if (operator === "yank") {
17709
- ta.setSelectionRange(range[0], range[0]);
18069
+ ta.setSelectionRange(result.caret, result.caret);
17710
18070
  } else {
17711
- ta.setRangeText("", range[0], range[1], "end");
18071
+ ta.value = result.text;
18072
+ ta.setSelectionRange(result.caret, result.caret);
17712
18073
  }
17713
- args.applyChange(ta.value);
18074
+ args.applyChange(ta.value, "capability");
17714
18075
  });
17715
18076
  useEventListener(`UI:${args.events.onInsertText}`, (evt) => {
17716
18077
  if (!args.editorId || !isInsertTextPayload(evt.payload) || evt.payload.editorId !== args.editorId) return;
17717
18078
  const ta = args.textareaRef.current;
17718
18079
  if (!ta) return;
18080
+ pushHistoryStep(ta.value, ta.selectionStart);
17719
18081
  ta.setRangeText(evt.payload.text, ta.selectionStart, ta.selectionEnd, "end");
17720
- args.applyChange(ta.value);
18082
+ args.applyChange(ta.value, "capability");
17721
18083
  });
17722
18084
  useEventListener(`UI:${args.events.onSetMode}`, (evt) => {
17723
18085
  if (!args.editorId || !isSetModePayload(evt.payload) || evt.payload.editorId !== args.editorId) return;
18086
+ closeOpenTypingStep();
18087
+ insertSessionOpenRef.current = evt.payload.mode === "INSERT";
17724
18088
  setCaretMode(evt.payload.caret);
17725
18089
  });
17726
- return { caretMode };
18090
+ return { caretMode, recordKeystroke, undo, redo };
17727
18091
  }
17728
18092
  var init_useEditorCapabilities = __esm({
17729
18093
  "components/core/molecules/markdown/useEditorCapabilities.ts"() {
@@ -18139,9 +18503,23 @@ var init_CodeBlock = __esm({
18139
18503
  "paragraph-forward",
18140
18504
  "paragraph-back",
18141
18505
  "line",
18142
- "selection"
18506
+ "selection",
18507
+ "match-bracket"
18143
18508
  ],
18144
- operators = ["delete", "yank", "change"]
18509
+ operators = [
18510
+ "delete",
18511
+ "yank",
18512
+ "change",
18513
+ "put",
18514
+ "put-before",
18515
+ "undo",
18516
+ "redo",
18517
+ "join",
18518
+ "toggle-case",
18519
+ "indent",
18520
+ "dedent",
18521
+ "replace"
18522
+ ]
18145
18523
  }) => {
18146
18524
  const code = typeof rawCode === "string" ? rawCode : String(rawCode ?? "");
18147
18525
  const activeStyle = resolveHighlightStyle(language);
@@ -18175,6 +18553,12 @@ var init_CodeBlock = __esm({
18175
18553
  const lastPropCodeRef = useRef(code);
18176
18554
  const editableTextareaRef = useRef(null);
18177
18555
  const editableOverlayRef = useRef(null);
18556
+ const [isFocused, setIsFocused] = useState(false);
18557
+ const prevCaretRef = useRef(0);
18558
+ const [caretIndex, setCaretIndex] = useState(0);
18559
+ const caretMirrorRef = useRef(null);
18560
+ const caretMarkerRef = useRef(null);
18561
+ const [caretGeometry, setCaretGeometry] = useState(null);
18178
18562
  useEffect(() => {
18179
18563
  if (code !== lastPropCodeRef.current) {
18180
18564
  lastPropCodeRef.current = code;
@@ -18190,23 +18574,77 @@ var init_CodeBlock = __esm({
18190
18574
  ov.scrollLeft = ta.scrollLeft;
18191
18575
  }
18192
18576
  }, []);
18193
- const handleEditableChange = useCallback((v) => {
18577
+ const handleEditableChange = useCallback((v, _origin) => {
18194
18578
  lastPropCodeRef.current = v;
18195
18579
  setEditableValue(v);
18580
+ const ta = editableTextareaRef.current;
18581
+ if (ta) setCaretIndex(ta.selectionStart);
18196
18582
  onChange?.(v);
18197
18583
  }, [onChange]);
18198
- const { caretMode } = useEditorCapabilities({
18584
+ const { caretMode, recordKeystroke, undo, redo } = useEditorCapabilities({
18199
18585
  editorId: editable ? editorId : void 0,
18200
18586
  textareaRef: editableTextareaRef,
18201
18587
  events: { onMotion, onOperate, onInsertText, onSetMode },
18588
+ focused: isFocused,
18202
18589
  applyChange: handleEditableChange
18203
18590
  });
18204
- const [caretIndex, setCaretIndex] = useState(0);
18205
- const caretRowCol = useMemo(() => {
18206
- const before = editableValue.slice(0, Math.min(caretIndex, editableValue.length));
18207
- const lines = before.split("\n");
18208
- return { row: lines.length - 1, col: lines[lines.length - 1].length };
18209
- }, [editableValue, caretIndex]);
18591
+ const handleEditableKeyDown = useCallback(
18592
+ (e) => {
18593
+ const ta = editableTextareaRef.current;
18594
+ if (ta) prevCaretRef.current = ta.selectionStart;
18595
+ const mod = e.metaKey || e.ctrlKey;
18596
+ if (!mod) return;
18597
+ const key = e.key.toLowerCase();
18598
+ if (key === "z" && !e.shiftKey) {
18599
+ e.preventDefault();
18600
+ undo();
18601
+ } else if (key === "z" && e.shiftKey || key === "y") {
18602
+ e.preventDefault();
18603
+ redo();
18604
+ }
18605
+ },
18606
+ [undo, redo]
18607
+ );
18608
+ const showBlockCaret = isFocused && caretMode !== "bar";
18609
+ useLayoutEffect(() => {
18610
+ if (!showBlockCaret) return;
18611
+ const ta = editableTextareaRef.current;
18612
+ const mirror = caretMirrorRef.current;
18613
+ const marker = caretMarkerRef.current;
18614
+ if (!ta || !mirror || !marker) return;
18615
+ const computed = window.getComputedStyle(ta);
18616
+ const MIRRORED_PROPS = [
18617
+ "font-family",
18618
+ "font-size",
18619
+ "font-weight",
18620
+ "font-style",
18621
+ "letter-spacing",
18622
+ "line-height",
18623
+ "padding-top",
18624
+ "padding-right",
18625
+ "padding-bottom",
18626
+ "padding-left",
18627
+ "border-top-width",
18628
+ "border-right-width",
18629
+ "border-bottom-width",
18630
+ "border-left-width",
18631
+ "box-sizing",
18632
+ "width",
18633
+ "white-space",
18634
+ "word-break",
18635
+ "overflow-wrap",
18636
+ "tab-size"
18637
+ ];
18638
+ for (const prop of MIRRORED_PROPS) {
18639
+ mirror.style.setProperty(prop, computed.getPropertyValue(prop));
18640
+ }
18641
+ const lineHeight = parseFloat(computed.getPropertyValue("line-height"));
18642
+ setCaretGeometry({
18643
+ top: marker.offsetTop,
18644
+ left: marker.offsetLeft,
18645
+ lineHeight: Number.isFinite(lineHeight) ? lineHeight : 0
18646
+ });
18647
+ }, [showBlockCaret, editableValue, caretIndex]);
18210
18648
  const errorLineProps = useMemo(() => buildLineProps(errorLines), [errorLines]);
18211
18649
  const viewerLineProps = useMemo(
18212
18650
  () => buildLineProps(errorLines, "px-4 py-0.5 hover:bg-muted/50"),
@@ -18730,11 +19168,24 @@ var init_CodeBlock = __esm({
18730
19168
  {
18731
19169
  ref: editableTextareaRef,
18732
19170
  defaultValue: code,
18733
- onChange: (e) => handleEditableChange(e.target.value),
19171
+ onChange: (e) => {
19172
+ const next = e.target.value;
19173
+ recordKeystroke(editableValue, prevCaretRef.current, next);
19174
+ handleEditableChange(next, "keystroke");
19175
+ },
18734
19176
  onScroll: handleEditableScroll,
18735
19177
  onSelect: (e) => setCaretIndex(e.currentTarget.selectionStart),
18736
- onFocus: editorId ? () => eventBus.emit(`UI:${onEditorFocus}`, { editorId }) : void 0,
18737
- onBlur: editorId ? () => eventBus.emit(`UI:${onEditorBlur}`, { editorId }) : void 0,
19178
+ onKeyUp: (e) => setCaretIndex(e.currentTarget.selectionStart),
19179
+ onClick: (e) => setCaretIndex(e.currentTarget.selectionStart),
19180
+ onKeyDown: handleEditableKeyDown,
19181
+ onFocus: () => {
19182
+ setIsFocused(true);
19183
+ if (editorId) eventBus.emit(`UI:${onEditorFocus}`, { editorId });
19184
+ },
19185
+ onBlur: () => {
19186
+ setIsFocused(false);
19187
+ if (editorId) eventBus.emit(`UI:${onEditorBlur}`, { editorId });
19188
+ },
18738
19189
  spellCheck: false,
18739
19190
  style: {
18740
19191
  position: "absolute",
@@ -18761,16 +19212,39 @@ var init_CodeBlock = __esm({
18761
19212
  },
18762
19213
  editableTextareaKey
18763
19214
  ),
18764
- caretMode !== "bar" && /* @__PURE__ */ jsx(
19215
+ showBlockCaret && /* @__PURE__ */ jsxs(
19216
+ "div",
19217
+ {
19218
+ ref: caretMirrorRef,
19219
+ "aria-hidden": true,
19220
+ "data-testid": "editor-caret-mirror",
19221
+ style: {
19222
+ position: "absolute",
19223
+ top: 0,
19224
+ left: 0,
19225
+ padding: "1rem",
19226
+ margin: 0,
19227
+ border: "none",
19228
+ visibility: "hidden",
19229
+ pointerEvents: "none"
19230
+ },
19231
+ children: [
19232
+ editableValue.slice(0, caretIndex),
19233
+ /* @__PURE__ */ jsx("span", { ref: caretMarkerRef, "data-testid": "editor-caret-marker", children: "\u200B" })
19234
+ ]
19235
+ }
19236
+ ),
19237
+ showBlockCaret && caretGeometry && /* @__PURE__ */ jsx(
18765
19238
  "span",
18766
19239
  {
18767
19240
  "aria-hidden": true,
19241
+ "data-testid": "editor-caret",
18768
19242
  style: {
18769
19243
  position: "absolute",
18770
- top: `calc(1rem + ${caretRowCol.row * 19.5}px)`,
18771
- left: `calc(1rem + ${caretRowCol.col}ch)`,
19244
+ top: caretGeometry.top,
19245
+ left: caretGeometry.left,
18772
19246
  width: "1ch",
18773
- height: caretMode === "block" ? "19.5px" : "2px",
19247
+ height: caretMode === "block" ? caretGeometry.lineHeight || "1.2em" : "2px",
18774
19248
  backgroundColor: caretMode === "block" ? "rgba(230, 230, 230, 0.5)" : void 0,
18775
19249
  borderBottom: caretMode === "underline" ? "2px solid #e6e6e6" : void 0,
18776
19250
  pointerEvents: "none"
@@ -26512,6 +26986,7 @@ function SubMenu({
26512
26986
  item.onClick?.();
26513
26987
  },
26514
26988
  "aria-disabled": item.disabled || void 0,
26989
+ title: item.title,
26515
26990
  "data-testid": item.event ? `action-${item.event}` : void 0,
26516
26991
  className: cn(
26517
26992
  "w-full flex items-center gap-3 px-4 py-2 text-start",
@@ -26560,6 +27035,7 @@ function MenuItemRow({
26560
27035
  as: "button",
26561
27036
  onClick: () => onItemClick({ ...item, id: itemId }, itemId),
26562
27037
  "aria-disabled": item.disabled || void 0,
27038
+ title: item.title,
26563
27039
  onMouseEnter: (e) => {
26564
27040
  if (hasSubMenu) openSubMenu(itemId, e.currentTarget);
26565
27041
  },
@@ -33606,13 +34082,13 @@ var init_MapView = __esm({
33606
34082
  shadowSize: [41, 41]
33607
34083
  });
33608
34084
  L.Marker.prototype.options.icon = defaultIcon;
33609
- const { useEffect: useEffect69, useRef: useRef69, useCallback: useCallback100, useState: useState103 } = React89__default;
34085
+ const { useEffect: useEffect70, useRef: useRef69, useCallback: useCallback101, useState: useState103 } = React89__default;
33610
34086
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
33611
34087
  const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
33612
34088
  function MapUpdater({ centerLat, centerLng, zoom }) {
33613
34089
  const map = useMap();
33614
34090
  const prevRef = useRef69({ centerLat, centerLng, zoom });
33615
- useEffect69(() => {
34091
+ useEffect70(() => {
33616
34092
  const prev = prevRef.current;
33617
34093
  if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
33618
34094
  map.setView([centerLat, centerLng], zoom);
@@ -33623,7 +34099,7 @@ var init_MapView = __esm({
33623
34099
  }
33624
34100
  function MapClickHandler({ onMapClick }) {
33625
34101
  const map = useMap();
33626
- useEffect69(() => {
34102
+ useEffect70(() => {
33627
34103
  if (!onMapClick) return;
33628
34104
  const handler = (e) => {
33629
34105
  onMapClick(e.latlng.lat, e.latlng.lng);
@@ -33652,7 +34128,7 @@ var init_MapView = __esm({
33652
34128
  }) {
33653
34129
  const eventBus = useEventBus2();
33654
34130
  const [clickedPosition, setClickedPosition] = useState103(null);
33655
- const handleMapClick = useCallback100((lat, lng) => {
34131
+ const handleMapClick = useCallback101((lat, lng) => {
33656
34132
  if (showClickedPin) {
33657
34133
  setClickedPosition({ lat, lng });
33658
34134
  }
@@ -33661,7 +34137,7 @@ var init_MapView = __esm({
33661
34137
  eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
33662
34138
  }
33663
34139
  }, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
33664
- const handleMarkerClick = useCallback100((marker) => {
34140
+ const handleMarkerClick = useCallback101((marker) => {
33665
34141
  onMarkerClick?.(marker);
33666
34142
  if (markerClickEvent) {
33667
34143
  eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
@@ -43408,7 +43884,10 @@ var init_FloatingToolbar = __esm({
43408
43884
  positionClasses = {
43409
43885
  "bottom-center": "bottom-6 left-1/2 -translate-x-1/2",
43410
43886
  "bottom-left": "bottom-6 left-6",
43411
- "bottom-right": "bottom-6 right-6"
43887
+ "bottom-right": "bottom-6 right-6",
43888
+ "top-center": "top-6 left-1/2 -translate-x-1/2",
43889
+ "top-left": "top-6 left-6",
43890
+ "top-right": "top-6 right-6"
43412
43891
  };
43413
43892
  FloatingToolbar = ({
43414
43893
  items,
@@ -51050,6 +51529,7 @@ var init_component_registry_generated = __esm({
51050
51529
  "TrendIndicator": TrendIndicator,
51051
51530
  "TypewriterText": TypewriterText,
51052
51531
  "Typography": Typography,
51532
+ "UISlotComponent": UISlotComponent,
51053
51533
  "UISlotRenderer": UISlotRenderer,
51054
51534
  "UploadDropZone": UploadDropZone,
51055
51535
  "VStack": VStack,
@@ -51355,6 +51835,7 @@ function UISlotComponentInner({
51355
51835
  const contained = useContext(SlotContainedContext);
51356
51836
  const schemaCtx = useEntitySchemaOptional();
51357
51837
  const rawContent = slots[slot];
51838
+ const regionClassName = fallback !== void 0 ? cn("contents", className) : className;
51358
51839
  const binding = useEntityBindingSnapshot(rawContent?.sourceTrait);
51359
51840
  const content = useMemo(() => {
51360
51841
  if (!rawContent) return rawContent;
@@ -51403,7 +51884,7 @@ function UISlotComponentInner({
51403
51884
  Box,
51404
51885
  {
51405
51886
  id: `slot-${slot}`,
51406
- className: cn("ui-slot", `ui-slot-${slot}`, className),
51887
+ className: cn("ui-slot", `ui-slot-${slot}`, regionClassName),
51407
51888
  "data-testid": `ui-slot-${slot}`,
51408
51889
  "data-slot-mode": "fallback",
51409
51890
  children: fallback
@@ -51438,7 +51919,7 @@ function UISlotComponentInner({
51438
51919
  Box,
51439
51920
  {
51440
51921
  id: `slot-${slot}-fallback`,
51441
- className: cn("ui-slot", `ui-slot-${slot}-fallback`, className),
51922
+ className: cn("ui-slot", `ui-slot-${slot}-fallback`, regionClassName),
51442
51923
  "data-testid": `ui-slot-${slot}-fallback`,
51443
51924
  "data-slot-mode": "append",
51444
51925
  children: fallback
@@ -51470,7 +51951,7 @@ function UISlotComponentInner({
51470
51951
  Box,
51471
51952
  {
51472
51953
  id: `slot-${slot}`,
51473
- className: cn("ui-slot", `ui-slot-${slot}`, className),
51954
+ className: cn("ui-slot", `ui-slot-${slot}`, regionClassName),
51474
51955
  "data-pattern": content.pattern,
51475
51956
  "data-source-trait": content.sourceTrait,
51476
51957
  "data-testid": `ui-slot-${slot}`,
@@ -53391,13 +53872,19 @@ function deriveEventsUrl(serverUrl) {
53391
53872
  const apiRoot = trimmed.replace(/\/[^/]*$/, "");
53392
53873
  return `${apiRoot}/events`;
53393
53874
  }
53394
- function createHttpTransport(serverUrl) {
53875
+ async function authHeaders(getAccessToken) {
53876
+ const headers = { "Content-Type": "application/json" };
53877
+ const token = getAccessToken ? await getAccessToken() : void 0;
53878
+ if (token) headers.Authorization = `Bearer ${token}`;
53879
+ return headers;
53880
+ }
53881
+ function createHttpTransport(serverUrl, getAccessToken) {
53395
53882
  return {
53396
53883
  register: async (schema) => {
53397
53884
  try {
53398
53885
  const res = await fetch(`${serverUrl}/register`, {
53399
53886
  method: "POST",
53400
- headers: { "Content-Type": "application/json" },
53887
+ headers: await authHeaders(getAccessToken),
53401
53888
  body: JSON.stringify({ schema })
53402
53889
  });
53403
53890
  const result = await res.json();
@@ -53413,7 +53900,7 @@ function createHttpTransport(serverUrl) {
53413
53900
  },
53414
53901
  unregister: async () => {
53415
53902
  try {
53416
- await fetch(`${serverUrl}/unregister`, { method: "DELETE" });
53903
+ await fetch(`${serverUrl}/unregister`, { method: "DELETE", headers: await authHeaders(getAccessToken) });
53417
53904
  } catch {
53418
53905
  }
53419
53906
  },
@@ -53421,7 +53908,7 @@ function createHttpTransport(serverUrl) {
53421
53908
  const body = { event, payload, clientId, tick, sourceTrait };
53422
53909
  const res = await fetch(`${serverUrl}/${orbitalName}/events`, {
53423
53910
  method: "POST",
53424
- headers: { "Content-Type": "application/json" },
53911
+ headers: await authHeaders(getAccessToken),
53425
53912
  body: JSON.stringify(body)
53426
53913
  });
53427
53914
  return res.json();
@@ -53441,6 +53928,7 @@ function ServerBridgeProvider({
53441
53928
  schema,
53442
53929
  serverUrl,
53443
53930
  transport: customTransport,
53931
+ getAccessToken,
53444
53932
  children
53445
53933
  }) {
53446
53934
  if (!serverUrl && !customTransport) {
@@ -53452,8 +53940,8 @@ function ServerBridgeProvider({
53452
53940
  const eventBus = useEventBus();
53453
53941
  const [connected, setConnected] = useState(false);
53454
53942
  const transport = useMemo(
53455
- () => customTransport ?? createHttpTransport(serverUrl),
53456
- [serverUrl, customTransport]
53943
+ () => customTransport ?? createHttpTransport(serverUrl, getAccessToken),
53944
+ [serverUrl, customTransport, getAccessToken]
53457
53945
  );
53458
53946
  const registerSchema = useCallback(
53459
53947
  async () => transport.register(schema),
@@ -53590,16 +54078,28 @@ function ServerBridgeProvider({
53590
54078
  useEffect(() => {
53591
54079
  if (!serverUrl) return;
53592
54080
  if (typeof EventSource === "undefined") return;
53593
- const url = `${deriveEventsUrl(serverUrl)}?clientId=${encodeURIComponent(getTabClientId())}`;
53594
- return acquirePushChannel(url, (parsed) => {
54081
+ let release;
54082
+ let cancelled = false;
54083
+ const subscribe = (parsed) => {
53595
54084
  serverBridgeLog.debug("push:received", {
53596
54085
  event: parsed.event,
53597
54086
  sourceOrbital: parsed.source?.orbital,
53598
54087
  sourceTrait: parsed.source?.trait
53599
54088
  });
53600
54089
  reEmitServerEvent(eventBus, parsed, "push");
53601
- });
53602
- }, [serverUrl, eventBus]);
54090
+ };
54091
+ void (async () => {
54092
+ const token = getAccessToken ? await getAccessToken() : void 0;
54093
+ if (cancelled) return;
54094
+ const params = new URLSearchParams({ clientId: getTabClientId() });
54095
+ if (token) params.set("access_token", token);
54096
+ release = acquirePushChannel(`${deriveEventsUrl(serverUrl)}?${params.toString()}`, subscribe);
54097
+ })();
54098
+ return () => {
54099
+ cancelled = true;
54100
+ release?.();
54101
+ };
54102
+ }, [serverUrl, eventBus, getAccessToken]);
53603
54103
  return /* @__PURE__ */ jsx(ServerBridgeContext.Provider, { value: { connected, sendEvent }, children });
53604
54104
  }
53605
54105
  var log13 = createLogger("almadar:ui:trait-provider");