wyreframe 0.7.6 → 0.7.7

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wyreframe",
3
- "version": "0.7.6",
3
+ "version": "0.7.7",
4
4
  "description": "ASCII wireframe + interaction DSL to HTML converter with scene transitions",
5
5
  "author": "wickedev",
6
6
  "repository": {
@@ -577,6 +577,40 @@ function stripSectionBorders(line) {
577
577
  }
578
578
  }
579
579
 
580
+ function getSegmentWidth(segment) {
581
+ switch (segment.TAG) {
582
+ case "ButtonSegment" :
583
+ return segment._0.length + 4 | 0;
584
+ case "TextSegment" :
585
+ case "LinkSegment" :
586
+ return segment._0.length;
587
+ }
588
+ }
589
+
590
+ function getSegmentOffset(segment) {
591
+ return segment._1;
592
+ }
593
+
594
+ function calculateRowAlignment(segments, baseCol, row, bounds) {
595
+ let match = segments[0];
596
+ let match$1 = segments[segments.length - 1 | 0];
597
+ if (match === undefined) {
598
+ return "Left";
599
+ }
600
+ if (match$1 === undefined) {
601
+ return "Left";
602
+ }
603
+ let firstOffset = getSegmentOffset(match);
604
+ let startCol = baseCol + firstOffset | 0;
605
+ let lastOffset = getSegmentOffset(match$1);
606
+ let lastWidth = getSegmentWidth(match$1);
607
+ let endCol = (baseCol + lastOffset | 0) + lastWidth | 0;
608
+ let rowWidth = endCol - startCol | 0;
609
+ let virtualContent = "x".repeat(rowWidth);
610
+ let position = Types.Position.make(row, startCol);
611
+ return AlignmentCalc.calculate(virtualContent, position, bounds);
612
+ }
613
+
580
614
  function segmentToElement(segment, basePosition, baseCol, bounds) {
581
615
  switch (segment.TAG) {
582
616
  case "TextSegment" :
@@ -667,39 +701,43 @@ function parseContentLine(line, lineIndex, contentStartRow, box, registry) {
667
701
  let basePosition = Types.Position.make(row$1, baseCol$1);
668
702
  let segments = splitInlineSegments(trimmed);
669
703
  if (segments.length > 1) {
670
- let rowChildren = segments.map(segment => segmentToElement(segment, basePosition, baseCol$1, box.bounds));
704
+ let trimmedStart = line.trimStart();
705
+ let leadingSpaces = line.length - trimmedStart.length | 0;
706
+ let actualBaseCol = baseCol$1 + leadingSpaces | 0;
707
+ let rowChildren = segments.map(segment => segmentToElement(segment, basePosition, actualBaseCol, box.bounds));
708
+ let rowAlign = calculateRowAlignment(segments, actualBaseCol, row$1, box.bounds);
671
709
  return {
672
710
  TAG: "Row",
673
711
  children: rowChildren,
674
- align: "Left"
712
+ align: rowAlign
675
713
  };
676
714
  }
677
715
  if (segments.length === 1) {
678
- let trimmedStart = line.trimStart();
679
- let leadingSpaces = line.length - trimmedStart.length | 0;
716
+ let trimmedStart$1 = line.trimStart();
717
+ let leadingSpaces$1 = line.length - trimmedStart$1.length | 0;
680
718
  let match = segments[0];
681
719
  if (match !== undefined) {
682
720
  switch (match.TAG) {
683
721
  case "TextSegment" :
684
722
  break;
685
723
  case "ButtonSegment" :
686
- let actualCol = (baseCol$1 + leadingSpaces | 0) + match._1 | 0;
724
+ let actualCol = (baseCol$1 + leadingSpaces$1 | 0) + match._1 | 0;
687
725
  let position$1 = Types.Position.make(row$1, actualCol);
688
726
  let buttonContent = "[ " + match._0 + " ]";
689
727
  return ParserRegistry.parse(registry, buttonContent, position$1, box.bounds);
690
728
  case "LinkSegment" :
691
- let actualCol$1 = (baseCol$1 + leadingSpaces | 0) + match._1 | 0;
729
+ let actualCol$1 = (baseCol$1 + leadingSpaces$1 | 0) + match._1 | 0;
692
730
  let position$2 = Types.Position.make(row$1, actualCol$1);
693
731
  let linkContent = "\"" + match._0 + "\"";
694
732
  return ParserRegistry.parse(registry, linkContent, position$2, box.bounds);
695
733
  }
696
734
  }
697
- let position$3 = Types.Position.make(row$1, baseCol$1 + leadingSpaces | 0);
735
+ let position$3 = Types.Position.make(row$1, baseCol$1 + leadingSpaces$1 | 0);
698
736
  return ParserRegistry.parse(registry, trimmed, position$3, box.bounds);
699
737
  }
700
- let trimmedStart$1 = line.trimStart();
701
- let leadingSpaces$1 = line.length - trimmedStart$1.length | 0;
702
- let position$4 = Types.Position.make(row$1, baseCol$1 + leadingSpaces$1 | 0);
738
+ let trimmedStart$2 = line.trimStart();
739
+ let leadingSpaces$2 = line.length - trimmedStart$2.length | 0;
740
+ let position$4 = Types.Position.make(row$1, baseCol$1 + leadingSpaces$2 | 0);
703
741
  return ParserRegistry.parse(registry, trimmed, position$4, box.bounds);
704
742
  }
705
743
 
@@ -1003,6 +1041,9 @@ export {
1003
1041
  extractSectionName,
1004
1042
  isSectionFooter,
1005
1043
  stripSectionBorders,
1044
+ getSegmentWidth,
1045
+ getSegmentOffset,
1046
+ calculateRowAlignment,
1006
1047
  segmentToElement,
1007
1048
  isNoiseText,
1008
1049
  parseContentLine,
@@ -955,6 +955,76 @@ let stripSectionBorders = (line: string): string => {
955
955
  *
956
956
  * Requirements: REQ-15 (Element parsing and AST generation)
957
957
  */
958
+ /**
959
+ * Get the visual width of an inline segment.
960
+ * - ButtonSegment: "[ text ]" = text length + 4
961
+ * - LinkSegment: just the text length
962
+ * - TextSegment: just the text length
963
+ */
964
+ let getSegmentWidth = (segment: inlineSegment): int => {
965
+ switch segment {
966
+ | TextSegment(text, _) => String.length(text)
967
+ | ButtonSegment(text, _) => String.length(text) + 4 // "[ " + text + " ]"
968
+ | LinkSegment(text, _) => String.length(text)
969
+ }
970
+ }
971
+
972
+ /**
973
+ * Get the column offset of an inline segment.
974
+ */
975
+ let getSegmentOffset = (segment: inlineSegment): int => {
976
+ switch segment {
977
+ | TextSegment(_, offset) => offset
978
+ | ButtonSegment(_, offset) => offset
979
+ | LinkSegment(_, offset) => offset
980
+ }
981
+ }
982
+
983
+ /**
984
+ * Calculate the alignment for a Row element based on the combined span
985
+ * of all its segments within the container bounds.
986
+ *
987
+ * Algorithm:
988
+ * 1. Find the start position of the first segment
989
+ * 2. Find the end position of the last segment (offset + width)
990
+ * 3. Calculate the total content span
991
+ * 4. Use AlignmentCalc to determine alignment based on left/right space
992
+ *
993
+ * @param segments - Array of inline segments in the row
994
+ * @param baseCol - The base column (left border + 1)
995
+ * @param row - The row number in the grid
996
+ * @param bounds - The container bounds
997
+ * @returns The calculated alignment for the Row
998
+ */
999
+ let calculateRowAlignment = (
1000
+ segments: array<inlineSegment>,
1001
+ baseCol: int,
1002
+ row: int,
1003
+ bounds: Bounds.t,
1004
+ ): Types.alignment => {
1005
+ switch (segments->Array.get(0), segments->Array.get(Array.length(segments) - 1)) {
1006
+ | (Some(firstSegment), Some(lastSegment)) => {
1007
+ // Calculate the start position (first segment's offset)
1008
+ let firstOffset = getSegmentOffset(firstSegment)
1009
+ let startCol = baseCol + firstOffset
1010
+
1011
+ // Calculate the end position (last segment's offset + width)
1012
+ let lastOffset = getSegmentOffset(lastSegment)
1013
+ let lastWidth = getSegmentWidth(lastSegment)
1014
+ let endCol = baseCol + lastOffset + lastWidth
1015
+
1016
+ // Create a virtual content string with length equal to the row span
1017
+ let rowWidth = endCol - startCol
1018
+ let virtualContent = String.repeat("x", rowWidth)
1019
+
1020
+ // Use AlignmentCalc to calculate alignment based on position
1021
+ let position = Position.make(row, startCol)
1022
+ AlignmentCalc.calculate(virtualContent, position, bounds)
1023
+ }
1024
+ | _ => Left // Fallback to Left if no segments
1025
+ }
1026
+ }
1027
+
958
1028
  /**
959
1029
  * Convert inline segment to element.
960
1030
  * Creates appropriate element type based on segment variant.
@@ -1119,13 +1189,22 @@ let parseContentLine = (
1119
1189
 
1120
1190
  if segments->Array.length > 1 {
1121
1191
  // Multiple segments - create a Row with all elements
1122
- // Each segment has its own column offset for correct alignment calculation
1192
+ // Issue #21: Account for leading spaces in the original line for correct alignment
1193
+ let leadingSpaces = {
1194
+ let original = line
1195
+ let trimmedStart = original->String.trimStart
1196
+ original->String.length - trimmedStart->String.length
1197
+ }
1198
+ // Calculate actual column including leading spaces
1199
+ let actualBaseCol = baseCol + leadingSpaces
1123
1200
  let rowChildren = segments->Array.map(segment => {
1124
- segmentToElement(segment, basePosition, baseCol, box.bounds)
1201
+ segmentToElement(segment, basePosition, actualBaseCol, box.bounds)
1125
1202
  })
1203
+ // Issue #21: Calculate Row alignment based on combined segment positions
1204
+ let rowAlign = calculateRowAlignment(segments, actualBaseCol, row, box.bounds)
1126
1205
  Some(Row({
1127
1206
  children: rowChildren,
1128
- align: Left,
1207
+ align: rowAlign,
1129
1208
  }))
1130
1209
  } else if segments->Array.length === 1 {
1131
1210
  // Single segment - check if it's a special element