Enhance table rendering by adding support for column alignment based on header d…
…efinitions. Update CHANGELOG for version 1.1.2 to reflect this new feature.
Showing
2 changed files
with
70 additions
and
12 deletions
| @@ -1013,19 +1013,50 @@ class TableMd extends BlockMd { | @@ -1013,19 +1013,50 @@ class TableMd extends BlockMd { | ||
| 1013 | .asMap(), | 1013 | .asMap(), |
| 1014 | ) | 1014 | ) |
| 1015 | .toList(); | 1015 | .toList(); |
| 1016 | - bool heading = RegExp( | ||
| 1017 | - r"^\|.*?\|\n\|-[-\\ |]*?-\|$", | ||
| 1018 | - multiLine: true, | ||
| 1019 | - ).hasMatch(text.trim()); | 1016 | + |
| 1017 | + // Check if table has a header and separator row | ||
| 1018 | + bool hasHeader = value.length >= 2; | ||
| 1019 | + List<TextAlign> columnAlignments = []; | ||
| 1020 | + | ||
| 1021 | + if (hasHeader) { | ||
| 1022 | + // Parse alignment from the separator row (second row) | ||
| 1023 | + var separatorRow = value[1]; | ||
| 1024 | + columnAlignments = List.generate(separatorRow.length, (index) { | ||
| 1025 | + String separator = separatorRow[index] ?? ""; | ||
| 1026 | + separator = separator.trim(); | ||
| 1027 | + | ||
| 1028 | + // Check for alignment indicators | ||
| 1029 | + bool hasLeftColon = separator.startsWith(':'); | ||
| 1030 | + bool hasRightColon = separator.endsWith(':'); | ||
| 1031 | + | ||
| 1032 | + if (hasLeftColon && hasRightColon) { | ||
| 1033 | + return TextAlign.center; | ||
| 1034 | + } else if (hasRightColon) { | ||
| 1035 | + return TextAlign.right; | ||
| 1036 | + } else if (hasLeftColon) { | ||
| 1037 | + return TextAlign.left; | ||
| 1038 | + } else { | ||
| 1039 | + return TextAlign.left; // Default alignment | ||
| 1040 | + } | ||
| 1041 | + }); | ||
| 1042 | + } | ||
| 1043 | + | ||
| 1020 | int maxCol = 0; | 1044 | int maxCol = 0; |
| 1021 | for (final each in value) { | 1045 | for (final each in value) { |
| 1022 | if (maxCol < each.keys.length) { | 1046 | if (maxCol < each.keys.length) { |
| 1023 | maxCol = each.keys.length; | 1047 | maxCol = each.keys.length; |
| 1024 | } | 1048 | } |
| 1025 | } | 1049 | } |
| 1050 | + | ||
| 1026 | if (maxCol == 0) { | 1051 | if (maxCol == 0) { |
| 1027 | return Text("", style: config.style); | 1052 | return Text("", style: config.style); |
| 1028 | } | 1053 | } |
| 1054 | + | ||
| 1055 | + // Ensure we have alignment for all columns | ||
| 1056 | + while (columnAlignments.length < maxCol) { | ||
| 1057 | + columnAlignments.add(TextAlign.left); | ||
| 1058 | + } | ||
| 1059 | + | ||
| 1029 | final controller = ScrollController(); | 1060 | final controller = ScrollController(); |
| 1030 | return Scrollbar( | 1061 | return Scrollbar( |
| 1031 | controller: controller, | 1062 | controller: controller, |
| @@ -1044,17 +1075,22 @@ class TableMd extends BlockMd { | @@ -1044,17 +1075,22 @@ class TableMd extends BlockMd { | ||
| 1044 | value | 1075 | value |
| 1045 | .asMap() | 1076 | .asMap() |
| 1046 | .entries | 1077 | .entries |
| 1078 | + .where((entry) { | ||
| 1079 | + // Skip the separator row (second row) from rendering | ||
| 1080 | + if (hasHeader && entry.key == 1) { | ||
| 1081 | + return false; | ||
| 1082 | + } | ||
| 1083 | + return true; | ||
| 1084 | + }) | ||
| 1047 | .map<TableRow>( | 1085 | .map<TableRow>( |
| 1048 | (entry) => TableRow( | 1086 | (entry) => TableRow( |
| 1049 | decoration: | 1087 | decoration: |
| 1050 | - (heading) | 1088 | + (hasHeader && entry.key == 0) |
| 1051 | ? BoxDecoration( | 1089 | ? BoxDecoration( |
| 1052 | color: | 1090 | color: |
| 1053 | - (entry.key == 0) | ||
| 1054 | - ? Theme.of( | 1091 | + Theme.of( |
| 1055 | context, | 1092 | context, |
| 1056 | - ).colorScheme.surfaceContainerHighest | ||
| 1057 | - : null, | 1093 | + ).colorScheme.surfaceContainerHighest, |
| 1058 | ) | 1094 | ) |
| 1059 | : null, | 1095 | : null, |
| 1060 | children: List.generate(maxCol, (index) { | 1096 | children: List.generate(maxCol, (index) { |
| @@ -1065,8 +1101,8 @@ class TableMd extends BlockMd { | @@ -1065,8 +1101,8 @@ class TableMd extends BlockMd { | ||
| 1065 | return const SizedBox(); | 1101 | return const SizedBox(); |
| 1066 | } | 1102 | } |
| 1067 | 1103 | ||
| 1068 | - return Center( | ||
| 1069 | - child: Padding( | 1104 | + // Apply alignment based on column alignment |
| 1105 | + Widget content = Padding( | ||
| 1070 | padding: const EdgeInsets.symmetric( | 1106 | padding: const EdgeInsets.symmetric( |
| 1071 | horizontal: 8, | 1107 | horizontal: 8, |
| 1072 | vertical: 4, | 1108 | vertical: 4, |
| @@ -1077,8 +1113,29 @@ class TableMd extends BlockMd { | @@ -1077,8 +1113,29 @@ class TableMd extends BlockMd { | ||
| 1077 | false, | 1113 | false, |
| 1078 | config: config, | 1114 | config: config, |
| 1079 | ), | 1115 | ), |
| 1080 | - ), | ||
| 1081 | ); | 1116 | ); |
| 1117 | + | ||
| 1118 | + // Wrap with alignment widget | ||
| 1119 | + switch (columnAlignments[index]) { | ||
| 1120 | + case TextAlign.center: | ||
| 1121 | + content = Center(child: content); | ||
| 1122 | + break; | ||
| 1123 | + case TextAlign.right: | ||
| 1124 | + content = Align( | ||
| 1125 | + alignment: Alignment.centerRight, | ||
| 1126 | + child: content, | ||
| 1127 | + ); | ||
| 1128 | + break; | ||
| 1129 | + case TextAlign.left: | ||
| 1130 | + default: | ||
| 1131 | + content = Align( | ||
| 1132 | + alignment: Alignment.centerLeft, | ||
| 1133 | + child: content, | ||
| 1134 | + ); | ||
| 1135 | + break; | ||
| 1136 | + } | ||
| 1137 | + | ||
| 1138 | + return content; | ||
| 1082 | }), | 1139 | }), |
| 1083 | ), | 1140 | ), |
| 1084 | ) | 1141 | ) |
-
Please register or login to post a comment