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
|
@@ -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
|
|
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:
|
|
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$
|
|
701
|
-
let leadingSpaces$
|
|
702
|
-
let position$4 = Types.Position.make(row$1, baseCol$1 + leadingSpaces$
|
|
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
|
-
//
|
|
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,
|
|
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:
|
|
1207
|
+
align: rowAlign,
|
|
1129
1208
|
}))
|
|
1130
1209
|
} else if segments->Array.length === 1 {
|
|
1131
1210
|
// Single segment - check if it's a special element
|