flet-box 1.1.2 → 1.1.3
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/AGENTS_FOR_CODE_GEN.md +284 -0
- package/CONTRIBUTING.md +238 -0
- package/README.md +2 -2
- package/bin/cli.js +88 -1
- package/bin/commands/auditFix.js +181 -27
- package/bin/commands/checkApi.js +14 -3
- package/bin/commands/checkStructure.js +368 -0
- package/bin/commands/checkSyntax.js +293 -0
- package/bin/commands/checkUi.js +666 -14
- package/bin/commands/create.js +14 -0
- package/bin/commands/createBundle.js +2 -2
- package/bin/commands/metrics.js +448 -0
- package/bin/commands/release.js +18 -0
- package/bin/commands/report.js +849 -0
- package/bin/commands/tools.js +76 -0
- package/bin/commands/unpack.js +39 -11
- package/bin/commands/verify.js +879 -0
- package/bin/mcp.js +280 -0
- package/bin/utils/contract.js +27 -0
- package/bin/utils/dtsProps.js +5 -1
- package/bin/utils/migrationGuide.js +146 -0
- package/bin/utils/moduleExports.js +9 -5
- package/bin/utils/templates.js +225 -18
- package/bin/utils/toolkit.js +191 -0
- package/docs/README.md +5 -1
- package/docs/arquitectura.md +1 -1
- package/docs/cli/README.md +168 -2
- package/docs/guides/README.md +6 -0
- package/docs/guides/accessibility.md +2 -1
- package/docs/guides/ai-toolkit.md +166 -0
- package/docs/guides/compatibility.md +1 -1
- package/docs/guides/migration.md +92 -0
- package/docs/guides/minification-and-protection.md +2 -1
- package/docs/guides/mobile-and-platforms.md +1 -1
- package/docs/guides/online-updates.md +2 -0
- package/docs/server/deployment.md +1 -1
- package/docs/tools/styling.md +2 -2
- package/docs/tools/theme.md +139 -4
- package/docs/widget/Accordion.md +74 -8
- package/docs/widget/AdMob.md +68 -3
- package/docs/widget/AdSense.md +67 -2
- package/docs/widget/AlertDialog.md +1 -1
- package/docs/widget/AnimatedBox.md +80 -39
- package/docs/widget/AnimatedText.md +74 -18
- package/docs/widget/Audio.md +73 -14
- package/docs/widget/Avatar.md +69 -4
- package/docs/widget/Badge.md +68 -3
- package/docs/widget/BottomSheet.md +2 -2
- package/docs/widget/Button.md +69 -3
- package/docs/widget/Card.md +69 -4
- package/docs/widget/Carousel.md +67 -2
- package/docs/widget/Chart.md +67 -2
- package/docs/widget/Checkbox.md +74 -8
- package/docs/widget/Chip.md +68 -3
- package/docs/widget/CircularBar.md +74 -15
- package/docs/widget/CircularChart.md +71 -10
- package/docs/widget/CodeViewer.md +67 -2
- package/docs/widget/Column.md +68 -3
- package/docs/widget/Container.md +68 -3
- package/docs/widget/DataTable.md +67 -2
- package/docs/widget/Divider.md +67 -2
- package/docs/widget/DraggBox.md +67 -2
- package/docs/widget/Dropdown.md +76 -10
- package/docs/widget/DroppBox.md +67 -2
- package/docs/widget/FloatingActionButton.md +68 -3
- package/docs/widget/GridView.md +67 -2
- package/docs/widget/Icon.md +71 -5
- package/docs/widget/Image.md +68 -3
- package/docs/widget/Input.md +68 -3
- package/docs/widget/Inspector.md +2 -2
- package/docs/widget/InstallButton.md +73 -13
- package/docs/widget/ListTile.md +69 -3
- package/docs/widget/ListView.md +67 -2
- package/docs/widget/Maps.md +68 -3
- package/docs/widget/Markdown.md +74 -15
- package/docs/widget/MatrixRain.md +72 -11
- package/docs/widget/Menu.md +209 -0
- package/docs/widget/Modal.md +3 -3
- package/docs/widget/Pagination.md +68 -3
- package/docs/widget/ParallaxBox.md +72 -12
- package/docs/widget/ProgressBar.md +69 -4
- package/docs/widget/QRCode.md +67 -2
- package/docs/widget/README.md +54 -50
- package/docs/widget/Radio.md +76 -10
- package/docs/widget/Rating.md +70 -6
- package/docs/widget/Row.md +68 -3
- package/docs/widget/Skeleton.md +68 -3
- package/docs/widget/Slider.md +75 -9
- package/docs/widget/SnackBar.md +2 -2
- package/docs/widget/Stack.md +68 -3
- package/docs/widget/Stepper.md +68 -3
- package/docs/widget/Switch.md +74 -8
- package/docs/widget/Text.md +71 -4
- package/docs/widget/ThemePicker.md +197 -0
- package/docs/widget/Tooltip.md +72 -7
- package/docs/widget/TreeView.md +70 -10
- package/docs/widget/Video.md +71 -10
- package/package.json +10 -3
- package/skills/fletbox-design/SKILL.md +89 -5
- package/skills/fletbox-motion/SKILL.md +1 -1
- package/skills/fletbox-rules/SKILL.md +56 -4
- package/src/core/runApp.js +12 -0
- package/src/index.d.ts +374 -101
- package/src/index.js +9 -0
- package/src/navigations/AdaptiveScaffold.js +2 -2
- package/src/navigations/BottomNavigation.js +1 -1
- package/src/navigations/Scaffold.js +18 -6
- package/src/tools/useState.js +11 -4
- package/src/utils/colors.js +275 -0
- package/src/utils/errorBoundary.js +288 -0
- package/src/utils/index.js +10 -2
- package/src/utils/stackPosition.js +39 -24
- package/src/utils/syntaxHighlight.js +4 -1
- package/src/utils/themes.js +279 -3
- package/src/widget-factory/addChildren.js +17 -10
- package/src/widget-factory/assignProps.js +18 -6
- package/src/widget-factory/createWidget.js +7 -0
- package/src/widget-factory/deprecations.js +77 -0
- package/src/widget-factory/translateProps.js +11 -1
- package/src/widget-factory/warnings.js +1 -27
- package/src/widget-factory/widgetFactory.js +59 -17
- package/src/widgets/Accordion.js +21 -7
- package/src/widgets/Badge.js +11 -2
- package/src/widgets/Button.js +15 -3
- package/src/widgets/Carousel.js +12 -4
- package/src/widgets/Chart.js +7 -2
- package/src/widgets/Checkbox.js +1 -2
- package/src/widgets/Chip.js +24 -10
- package/src/widgets/CircularBar.js +9 -3
- package/src/widgets/CircularChart.js +5 -3
- package/src/widgets/Container.js +6 -0
- package/src/widgets/Divider.js +3 -1
- package/src/widgets/DraggBox.js +9 -0
- package/src/widgets/Dropdown.js +3 -3
- package/src/widgets/DroppBox.js +5 -0
- package/src/widgets/FloatingActionButton.js +1 -1
- package/src/widgets/Icon.js +5 -1
- package/src/widgets/InstallButton.js +4 -2
- package/src/widgets/Markdown.js +171 -103
- package/src/widgets/Menu.js +340 -0
- package/src/widgets/Modal.js +7 -1
- package/src/widgets/Pagination.js +10 -5
- package/src/widgets/ProgressBar.js +5 -4
- package/src/widgets/QRCode.js +4 -0
- package/src/widgets/Radio.js +1 -2
- package/src/widgets/Rating.js +9 -0
- package/src/widgets/Slider.js +4 -1
- package/src/widgets/SnackBar.js +2 -2
- package/src/widgets/Switch.js +1 -2
- package/src/widgets/Text.js +9 -5
- package/src/widgets/ThemePicker.js +234 -0
- package/src/widgets/TreeView.js +2 -1
- package/src/widgets/index.js +2 -0
- package/docs/CONTRIBUTING.md +0 -156
package/bin/commands/checkUi.js
CHANGED
|
@@ -613,12 +613,14 @@ const lineOf = (offsets, index) => {
|
|
|
613
613
|
const isLargeText = (props) => {
|
|
614
614
|
let size = null;
|
|
615
615
|
for (const key of ["fontSize", "size"]) {
|
|
616
|
-
const
|
|
616
|
+
const entry = props.get(key);
|
|
617
|
+
const numbers = numbersIn(entry?.resolved ?? entry?.value ?? "");
|
|
617
618
|
if (numbers.length === 1) size = numbers[0].number;
|
|
618
619
|
}
|
|
619
620
|
if (size === null) return false;
|
|
620
621
|
if (size >= LARGE_TEXT_SIZE) return true;
|
|
621
|
-
|
|
622
|
+
const weightEntry = props.get("weight");
|
|
623
|
+
return size >= 18 && /bold|['"]?(600|700)['"]?/.test(weightEntry?.resolved ?? weightEntry?.value ?? "");
|
|
622
624
|
};
|
|
623
625
|
|
|
624
626
|
/** The props that paint the plate a label sits on, in the order they win. */
|
|
@@ -636,10 +638,11 @@ const fillOf = (props, tokens) => {
|
|
|
636
638
|
for (const key of FILL_KEYS) {
|
|
637
639
|
const entry = props.get(key);
|
|
638
640
|
if (!entry) continue;
|
|
641
|
+
const value = entry.resolved ?? entry.value;
|
|
639
642
|
const resolved =
|
|
640
643
|
key === "gradient"
|
|
641
|
-
? gradientStop(
|
|
642
|
-
: resolveColor(
|
|
644
|
+
? gradientStop(value, tokens)
|
|
645
|
+
: resolveColor(value, tokens);
|
|
643
646
|
if (resolved) return resolved;
|
|
644
647
|
}
|
|
645
648
|
return null;
|
|
@@ -739,10 +742,10 @@ const checkContrast = (widget, props, scopeProps, ctx, line) => {
|
|
|
739
742
|
/** The theme whose answer is hardest to read, plus the numbers to print. */
|
|
740
743
|
let worst = null;
|
|
741
744
|
for (const theme of themes) {
|
|
742
|
-
const fg = resolveColor(fgEntry.value, theme.tokens);
|
|
745
|
+
const fg = resolveColor(fgEntry.resolved ?? fgEntry.value, theme.tokens);
|
|
743
746
|
if (!fg) continue;
|
|
744
747
|
if (accent) {
|
|
745
|
-
const bg = resolveColor(accent.value, theme.tokens);
|
|
748
|
+
const bg = resolveColor(accent.resolved ?? accent.value, theme.tokens);
|
|
746
749
|
if (!bg) continue;
|
|
747
750
|
const ratio = ctx.contrast(fg, bg);
|
|
748
751
|
if (!worst || ratio < worst.ratio) worst = { ratio, fg, bg, theme: theme.name };
|
|
@@ -897,10 +900,651 @@ export const functionBodies = (code) => {
|
|
|
897
900
|
return bodies;
|
|
898
901
|
};
|
|
899
902
|
|
|
903
|
+
// --------------------------------------------------------------------------- //
|
|
904
|
+
// Const resolution for the clean-UI pass. A value written as an identifier that
|
|
905
|
+
// names a module-level or block-level `const` is resolved to the literal it
|
|
906
|
+
// stands for, so `padding: PAD` where `const PAD = 13;` is still reported as an
|
|
907
|
+
// off-scale spacing. Bindings that are not a simple const (parameters, catch
|
|
908
|
+
// variables, loop variables, `let`/`var`, destructuring) shadow the name and
|
|
909
|
+
// make it unresolvable, so a runtime value is never mistaken for a literal.
|
|
910
|
+
// --------------------------------------------------------------------------- //
|
|
911
|
+
|
|
912
|
+
const matchingBracket = (code, i) => {
|
|
913
|
+
const open = code[i];
|
|
914
|
+
const close = open === "{" ? "}" : open === "(" ? ")" : open === "[" ? "]" : null;
|
|
915
|
+
if (!close) return -1;
|
|
916
|
+
let depth = 0;
|
|
917
|
+
let str = false;
|
|
918
|
+
let quote = "";
|
|
919
|
+
for (let j = i; j < code.length; j++) {
|
|
920
|
+
const ch = code[j];
|
|
921
|
+
if (str) {
|
|
922
|
+
if (ch === "\\\\") {
|
|
923
|
+
j++;
|
|
924
|
+
continue;
|
|
925
|
+
}
|
|
926
|
+
if (ch === quote) str = false;
|
|
927
|
+
continue;
|
|
928
|
+
}
|
|
929
|
+
if (isQuote(ch)) {
|
|
930
|
+
str = true;
|
|
931
|
+
quote = ch;
|
|
932
|
+
continue;
|
|
933
|
+
}
|
|
934
|
+
if (ch === open) depth++;
|
|
935
|
+
else if (ch === close) {
|
|
936
|
+
depth--;
|
|
937
|
+
if (depth === 0) return j;
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
return -1;
|
|
941
|
+
};
|
|
942
|
+
|
|
943
|
+
const splitTopLevel = (s, sep) => {
|
|
944
|
+
const out = [];
|
|
945
|
+
let depth = 0;
|
|
946
|
+
let str = false;
|
|
947
|
+
let quote = "";
|
|
948
|
+
let cur = "";
|
|
949
|
+
for (let i = 0; i < s.length; i++) {
|
|
950
|
+
const ch = s[i];
|
|
951
|
+
if (str) {
|
|
952
|
+
cur += ch;
|
|
953
|
+
if (ch === "\\\\") {
|
|
954
|
+
cur += s[++i] ?? "";
|
|
955
|
+
continue;
|
|
956
|
+
}
|
|
957
|
+
if (ch === quote) str = false;
|
|
958
|
+
continue;
|
|
959
|
+
}
|
|
960
|
+
if (isQuote(ch)) {
|
|
961
|
+
str = true;
|
|
962
|
+
quote = ch;
|
|
963
|
+
cur += ch;
|
|
964
|
+
continue;
|
|
965
|
+
}
|
|
966
|
+
if (ch === "{" || ch === "(" || ch === "[") {
|
|
967
|
+
depth++;
|
|
968
|
+
cur += ch;
|
|
969
|
+
continue;
|
|
970
|
+
}
|
|
971
|
+
if (ch === "}" || ch === ")" || ch === "]") {
|
|
972
|
+
depth--;
|
|
973
|
+
cur += ch;
|
|
974
|
+
continue;
|
|
975
|
+
}
|
|
976
|
+
if (depth === 0 && ch === sep) {
|
|
977
|
+
out.push(cur);
|
|
978
|
+
cur = "";
|
|
979
|
+
continue;
|
|
980
|
+
}
|
|
981
|
+
cur += ch;
|
|
982
|
+
}
|
|
983
|
+
if (cur.trim() !== "") out.push(cur);
|
|
984
|
+
return out;
|
|
985
|
+
};
|
|
986
|
+
|
|
987
|
+
const findTopLevelEquals = (s) => {
|
|
988
|
+
let depth = 0;
|
|
989
|
+
let str = false;
|
|
990
|
+
let quote = "";
|
|
991
|
+
for (let i = 0; i < s.length; i++) {
|
|
992
|
+
const ch = s[i];
|
|
993
|
+
if (str) {
|
|
994
|
+
if (ch === "\\\\") {
|
|
995
|
+
i++;
|
|
996
|
+
continue;
|
|
997
|
+
}
|
|
998
|
+
if (ch === quote) str = false;
|
|
999
|
+
continue;
|
|
1000
|
+
}
|
|
1001
|
+
if (isQuote(ch)) {
|
|
1002
|
+
str = true;
|
|
1003
|
+
quote = ch;
|
|
1004
|
+
continue;
|
|
1005
|
+
}
|
|
1006
|
+
if (ch === "{" || ch === "(" || ch === "[") {
|
|
1007
|
+
depth++;
|
|
1008
|
+
continue;
|
|
1009
|
+
}
|
|
1010
|
+
if (ch === "}" || ch === ")" || ch === "]") {
|
|
1011
|
+
depth--;
|
|
1012
|
+
continue;
|
|
1013
|
+
}
|
|
1014
|
+
if (depth === 0 && ch === "=" && s[i + 1] !== "=" && s[i - 1] !== "=" && s[i + 1] !== ">") {
|
|
1015
|
+
return i;
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
return -1;
|
|
1019
|
+
};
|
|
1020
|
+
|
|
1021
|
+
const findTopLevelColon = (s) => {
|
|
1022
|
+
let depth = 0;
|
|
1023
|
+
let str = false;
|
|
1024
|
+
let quote = "";
|
|
1025
|
+
for (let i = 0; i < s.length; i++) {
|
|
1026
|
+
const ch = s[i];
|
|
1027
|
+
if (str) {
|
|
1028
|
+
if (ch === "\\\\") {
|
|
1029
|
+
i++;
|
|
1030
|
+
continue;
|
|
1031
|
+
}
|
|
1032
|
+
if (ch === quote) str = false;
|
|
1033
|
+
continue;
|
|
1034
|
+
}
|
|
1035
|
+
if (isQuote(ch)) {
|
|
1036
|
+
str = true;
|
|
1037
|
+
quote = ch;
|
|
1038
|
+
continue;
|
|
1039
|
+
}
|
|
1040
|
+
if (ch === "{" || ch === "(" || ch === "[") {
|
|
1041
|
+
depth++;
|
|
1042
|
+
continue;
|
|
1043
|
+
}
|
|
1044
|
+
if (ch === "}" || ch === ")" || ch === "]") {
|
|
1045
|
+
depth--;
|
|
1046
|
+
continue;
|
|
1047
|
+
}
|
|
1048
|
+
if (depth === 0 && ch === ":") return i;
|
|
1049
|
+
}
|
|
1050
|
+
return -1;
|
|
1051
|
+
};
|
|
1052
|
+
|
|
1053
|
+
const extractBindingNames = (pattern) => {
|
|
1054
|
+
const p = pattern.trim();
|
|
1055
|
+
if (!p) return [];
|
|
1056
|
+
if (/^[A-Za-z_$][\w$]*$/.test(p)) return [p];
|
|
1057
|
+
if (p.startsWith("{") && p.endsWith("}")) {
|
|
1058
|
+
const inner = p.slice(1, -1);
|
|
1059
|
+
const parts = splitTopLevel(inner, ",");
|
|
1060
|
+
const names = [];
|
|
1061
|
+
for (const part of parts) {
|
|
1062
|
+
let pp = part.trim();
|
|
1063
|
+
if (!pp) continue;
|
|
1064
|
+
if (pp.startsWith("...")) pp = pp.slice(3).trim();
|
|
1065
|
+
const colon = findTopLevelColon(pp);
|
|
1066
|
+
if (colon !== -1) {
|
|
1067
|
+
const valuePart = pp.slice(colon + 1).trim();
|
|
1068
|
+
const eq = findTopLevelEquals(valuePart);
|
|
1069
|
+
const target = eq !== -1 ? valuePart.slice(0, eq).trim() : valuePart;
|
|
1070
|
+
names.push(...extractBindingNames(target));
|
|
1071
|
+
} else {
|
|
1072
|
+
const eq = findTopLevelEquals(pp);
|
|
1073
|
+
const target = eq !== -1 ? pp.slice(0, eq).trim() : pp;
|
|
1074
|
+
names.push(...extractBindingNames(target));
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
return names;
|
|
1078
|
+
}
|
|
1079
|
+
if (p.startsWith("[") && p.endsWith("]")) {
|
|
1080
|
+
const inner = p.slice(1, -1);
|
|
1081
|
+
const parts = splitTopLevel(inner, ",");
|
|
1082
|
+
const names = [];
|
|
1083
|
+
for (const part of parts) {
|
|
1084
|
+
let pp = part.trim();
|
|
1085
|
+
if (!pp) continue;
|
|
1086
|
+
if (pp.startsWith("...")) pp = pp.slice(3).trim();
|
|
1087
|
+
const eq = findTopLevelEquals(pp);
|
|
1088
|
+
const target = eq !== -1 ? pp.slice(0, eq).trim() : pp;
|
|
1089
|
+
names.push(...extractBindingNames(target));
|
|
1090
|
+
}
|
|
1091
|
+
return names;
|
|
1092
|
+
}
|
|
1093
|
+
return [];
|
|
1094
|
+
};
|
|
1095
|
+
|
|
1096
|
+
const parseParamNames = (s) => {
|
|
1097
|
+
const parts = splitTopLevel(s, ",");
|
|
1098
|
+
const names = [];
|
|
1099
|
+
for (const part of parts) {
|
|
1100
|
+
let pp = part.trim();
|
|
1101
|
+
if (!pp) continue;
|
|
1102
|
+
const eq = findTopLevelEquals(pp);
|
|
1103
|
+
if (eq !== -1) pp = pp.slice(0, eq).trim();
|
|
1104
|
+
if (pp.startsWith("...")) pp = pp.slice(3).trim();
|
|
1105
|
+
names.push(...extractBindingNames(pp));
|
|
1106
|
+
}
|
|
1107
|
+
return names;
|
|
1108
|
+
};
|
|
1109
|
+
|
|
1110
|
+
const extractBindingNamesFromFor = (s) => {
|
|
1111
|
+
let main = s;
|
|
1112
|
+
const ofMatch = /\s+(?:of|in)\s+/.exec(s);
|
|
1113
|
+
if (ofMatch) main = s.slice(0, ofMatch.index);
|
|
1114
|
+
const parts = splitTopLevel(main, ",");
|
|
1115
|
+
const names = [];
|
|
1116
|
+
for (const part of parts) {
|
|
1117
|
+
let pp = part.trim();
|
|
1118
|
+
const eq = findTopLevelEquals(pp);
|
|
1119
|
+
if (eq !== -1) pp = pp.slice(0, eq).trim();
|
|
1120
|
+
names.push(...extractBindingNames(pp));
|
|
1121
|
+
}
|
|
1122
|
+
return names;
|
|
1123
|
+
};
|
|
1124
|
+
|
|
1125
|
+
export const paramsBeforeBrace = (code, brace) => {
|
|
1126
|
+
let i = brace - 1;
|
|
1127
|
+
while (i >= 0 && /\s/.test(code[i])) i--;
|
|
1128
|
+
let arrow = false;
|
|
1129
|
+
if (i >= 1 && code[i] === ">" && code[i - 1] === "=") {
|
|
1130
|
+
arrow = true;
|
|
1131
|
+
i -= 2;
|
|
1132
|
+
}
|
|
1133
|
+
while (i >= 0 && /\s/.test(code[i])) i--;
|
|
1134
|
+
if (i < 0 || code[i] !== ")") return null;
|
|
1135
|
+
const closeIdx = i;
|
|
1136
|
+
let depth = 0;
|
|
1137
|
+
let start = -1;
|
|
1138
|
+
for (let j = closeIdx; j >= 0; j--) {
|
|
1139
|
+
const ch = code[j];
|
|
1140
|
+
if (ch === ")") depth++;
|
|
1141
|
+
else if (ch === "(") {
|
|
1142
|
+
depth--;
|
|
1143
|
+
if (depth === 0) {
|
|
1144
|
+
start = j;
|
|
1145
|
+
break;
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
if (start === -1) return null;
|
|
1150
|
+
let k = start - 1;
|
|
1151
|
+
let _d = 0;
|
|
1152
|
+
while (k >= 0) {
|
|
1153
|
+
const ch = code[k];
|
|
1154
|
+
if (ch === ")" || ch === "]") _d++;
|
|
1155
|
+
else if (ch === "(" || ch === "[") {
|
|
1156
|
+
if (_d === 0) break;
|
|
1157
|
+
_d--;
|
|
1158
|
+
} else if (_d === 0 && (ch === ";" || ch === "{" || ch === "}" || ch === "\n")) {
|
|
1159
|
+
break;
|
|
1160
|
+
}
|
|
1161
|
+
k--;
|
|
1162
|
+
}
|
|
1163
|
+
const before = code.slice(k + 1, start).trim();
|
|
1164
|
+
let kind = null;
|
|
1165
|
+
if (/\bcatch$/.test(before)) kind = "catch";
|
|
1166
|
+
else if (/\bfor$/.test(before)) kind = "for";
|
|
1167
|
+
else if (/\bfunction\b/.test(before)) kind = "function";
|
|
1168
|
+
else if (before.endsWith("=>")) kind = "function";
|
|
1169
|
+
else if (/[A-Za-z_$][\w$]*\s*$/.test(before) && !/\b(if|for|while|switch|with|do|else|try|catch)$/.test(before)) kind = "function";
|
|
1170
|
+
else if (arrow) kind = "function";
|
|
1171
|
+
if (!kind) return null;
|
|
1172
|
+
|
|
1173
|
+
const paramText = code.slice(start + 1, closeIdx);
|
|
1174
|
+
if (kind === "for") {
|
|
1175
|
+
const names = extractBindingNamesFromFor(paramText);
|
|
1176
|
+
return names.length ? names : null;
|
|
1177
|
+
}
|
|
1178
|
+
return parseParamNames(paramText);
|
|
1179
|
+
};
|
|
1180
|
+
|
|
1181
|
+
export const arrowParams = (code, arrowIdx) => {
|
|
1182
|
+
let i = arrowIdx - 1;
|
|
1183
|
+
while (i >= 0 && /\s/.test(code[i])) i--;
|
|
1184
|
+
if (i < 0) return null;
|
|
1185
|
+
if (/[A-Za-z_$]/.test(code[i])) {
|
|
1186
|
+
const m = /[A-Za-z_$][\w$]*$/.exec(code.slice(0, i + 1));
|
|
1187
|
+
if (m) return [m[0]];
|
|
1188
|
+
return null;
|
|
1189
|
+
}
|
|
1190
|
+
if (code[i] !== ")") return null;
|
|
1191
|
+
const closeIdx = i;
|
|
1192
|
+
let depth = 0;
|
|
1193
|
+
let start = -1;
|
|
1194
|
+
for (let j = closeIdx; j >= 0; j--) {
|
|
1195
|
+
const ch = code[j];
|
|
1196
|
+
if (ch === ")") depth++;
|
|
1197
|
+
else if (ch === "(") {
|
|
1198
|
+
depth--;
|
|
1199
|
+
if (depth === 0) {
|
|
1200
|
+
start = j;
|
|
1201
|
+
break;
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
if (start === -1) return null;
|
|
1206
|
+
return parseParamNames(code.slice(start + 1, closeIdx));
|
|
1207
|
+
};
|
|
1208
|
+
|
|
1209
|
+
const exprExtent = (code, j, hi) => {
|
|
1210
|
+
let depth = 0;
|
|
1211
|
+
let str = false;
|
|
1212
|
+
let quote = "";
|
|
1213
|
+
let i = j;
|
|
1214
|
+
while (i < hi) {
|
|
1215
|
+
const ch = code[i];
|
|
1216
|
+
if (str) {
|
|
1217
|
+
if (ch === "\\\\") {
|
|
1218
|
+
i += 2;
|
|
1219
|
+
continue;
|
|
1220
|
+
}
|
|
1221
|
+
if (ch === quote) str = false;
|
|
1222
|
+
i++;
|
|
1223
|
+
continue;
|
|
1224
|
+
}
|
|
1225
|
+
if (isQuote(ch)) {
|
|
1226
|
+
str = true;
|
|
1227
|
+
quote = ch;
|
|
1228
|
+
i++;
|
|
1229
|
+
continue;
|
|
1230
|
+
}
|
|
1231
|
+
if (ch === "{" || ch === "(" || ch === "[") {
|
|
1232
|
+
depth++;
|
|
1233
|
+
i++;
|
|
1234
|
+
continue;
|
|
1235
|
+
}
|
|
1236
|
+
if (ch === "}" || ch === ")" || ch === "]") {
|
|
1237
|
+
if (depth === 0) break;
|
|
1238
|
+
depth--;
|
|
1239
|
+
i++;
|
|
1240
|
+
continue;
|
|
1241
|
+
}
|
|
1242
|
+
if (depth === 0 && (ch === ";" || ch === ",")) break;
|
|
1243
|
+
if (depth === 0 && ch === "\n") {
|
|
1244
|
+
const soFar = code.slice(j, i).trimEnd();
|
|
1245
|
+
const last = soFar[soFar.length - 1];
|
|
1246
|
+
if (last && /[+\-*/%&|^,(:[{]/.test(last)) {
|
|
1247
|
+
i++;
|
|
1248
|
+
continue;
|
|
1249
|
+
}
|
|
1250
|
+
break;
|
|
1251
|
+
}
|
|
1252
|
+
i++;
|
|
1253
|
+
}
|
|
1254
|
+
return i;
|
|
1255
|
+
};
|
|
1256
|
+
|
|
1257
|
+
const isConstKeyword = (code, i) => {
|
|
1258
|
+
if (i > 0 && /[A-Za-z0-9_$]/.test(code[i - 1])) return false;
|
|
1259
|
+
if (!code.startsWith("const", i)) return false;
|
|
1260
|
+
const after = code[i + 5];
|
|
1261
|
+
if (after && /[A-Za-z0-9_$]/.test(after)) return false;
|
|
1262
|
+
return true;
|
|
1263
|
+
};
|
|
1264
|
+
|
|
1265
|
+
const isLetOrVarKeyword = (code, i) => {
|
|
1266
|
+
for (const kw of ["let", "var"]) {
|
|
1267
|
+
if (!code.startsWith(kw, i)) continue;
|
|
1268
|
+
if (i > 0 && /[A-Za-z0-9_$]/.test(code[i - 1])) continue;
|
|
1269
|
+
const after = code[i + kw.length];
|
|
1270
|
+
if (after && /[A-Za-z0-9_$]/.test(after)) continue;
|
|
1271
|
+
return kw;
|
|
1272
|
+
}
|
|
1273
|
+
return null;
|
|
1274
|
+
};
|
|
1275
|
+
|
|
1276
|
+
const parseConstDecl = (code, start, hi, kind) => {
|
|
1277
|
+
const kw = kind === "const" ? "const" : kind;
|
|
1278
|
+
let i = start + kw.length;
|
|
1279
|
+
const decls = [];
|
|
1280
|
+
const parseOne = () => {
|
|
1281
|
+
while (i < hi && /\s/.test(code[i])) i++;
|
|
1282
|
+
if (i >= hi) return false;
|
|
1283
|
+
if (code[i] === ";" || code[i] === "}" || code[i] === "\n") {
|
|
1284
|
+
if (code[i] === ";") i++;
|
|
1285
|
+
return false;
|
|
1286
|
+
}
|
|
1287
|
+
const patStart = i;
|
|
1288
|
+
let pattern;
|
|
1289
|
+
if (code[i] === "{" || code[i] === "[") {
|
|
1290
|
+
const close = matchingBracket(code, i);
|
|
1291
|
+
if (close === -1 || close >= hi) return false;
|
|
1292
|
+
pattern = code.slice(i, close + 1);
|
|
1293
|
+
i = close + 1;
|
|
1294
|
+
} else {
|
|
1295
|
+
const m = /^[A-Za-z_$][\w$]*/.exec(code.slice(i));
|
|
1296
|
+
if (!m) return false;
|
|
1297
|
+
pattern = m[0];
|
|
1298
|
+
i += m[0].length;
|
|
1299
|
+
}
|
|
1300
|
+
while (i < hi && /\s/.test(code[i])) i++;
|
|
1301
|
+
let init = null;
|
|
1302
|
+
let initStart = null;
|
|
1303
|
+
if (i < hi && code[i] === "=" && code[i + 1] !== "=" && code[i + 1] !== ">") {
|
|
1304
|
+
i++;
|
|
1305
|
+
while (i < hi && /\s/.test(code[i])) i++;
|
|
1306
|
+
initStart = i;
|
|
1307
|
+
let depth = 0;
|
|
1308
|
+
let str = false;
|
|
1309
|
+
let quote = "";
|
|
1310
|
+
while (i < hi) {
|
|
1311
|
+
const ch = code[i];
|
|
1312
|
+
if (str) {
|
|
1313
|
+
if (ch === "\\\\") {
|
|
1314
|
+
i += 2;
|
|
1315
|
+
continue;
|
|
1316
|
+
}
|
|
1317
|
+
if (ch === quote) str = false;
|
|
1318
|
+
i++;
|
|
1319
|
+
continue;
|
|
1320
|
+
}
|
|
1321
|
+
if (isQuote(ch)) {
|
|
1322
|
+
str = true;
|
|
1323
|
+
quote = ch;
|
|
1324
|
+
i++;
|
|
1325
|
+
continue;
|
|
1326
|
+
}
|
|
1327
|
+
if (ch === "{" || ch === "(" || ch === "[") {
|
|
1328
|
+
depth++;
|
|
1329
|
+
i++;
|
|
1330
|
+
continue;
|
|
1331
|
+
}
|
|
1332
|
+
if (ch === "}" || ch === ")" || ch === "]") {
|
|
1333
|
+
if (depth === 0) break;
|
|
1334
|
+
depth--;
|
|
1335
|
+
i++;
|
|
1336
|
+
continue;
|
|
1337
|
+
}
|
|
1338
|
+
if (depth === 0 && (ch === "," || ch === ";")) break;
|
|
1339
|
+
if (depth === 0 && ch === "\n") {
|
|
1340
|
+
const soFar = code.slice(initStart, i).trimEnd();
|
|
1341
|
+
const last = soFar[soFar.length - 1];
|
|
1342
|
+
if (!last || !/[+\-*/%&|^,(:[{]/.test(last)) break;
|
|
1343
|
+
}
|
|
1344
|
+
i++;
|
|
1345
|
+
}
|
|
1346
|
+
init = code.slice(initStart, i).trim();
|
|
1347
|
+
}
|
|
1348
|
+
decls.push({ pattern, name: /^[A-Za-z_$][\w$]*$/.test(pattern) ? pattern : null, init, declOffset: patStart, kind, initStart, initEnd: init !== null ? i : null });
|
|
1349
|
+
while (i < hi && /\s/.test(code[i])) i++;
|
|
1350
|
+
if (i < hi && code[i] === ",") {
|
|
1351
|
+
i++;
|
|
1352
|
+
return true;
|
|
1353
|
+
}
|
|
1354
|
+
return false;
|
|
1355
|
+
};
|
|
1356
|
+
let more = true;
|
|
1357
|
+
while (more && i < hi) {
|
|
1358
|
+
more = parseOne();
|
|
1359
|
+
}
|
|
1360
|
+
return { decls, endOffset: i };
|
|
1361
|
+
};
|
|
1362
|
+
|
|
1363
|
+
export const processRange = (code, lo, hi, parent, params) => {
|
|
1364
|
+
const scope = {
|
|
1365
|
+
parent,
|
|
1366
|
+
lo,
|
|
1367
|
+
hi,
|
|
1368
|
+
bindings: new Map(),
|
|
1369
|
+
children: [],
|
|
1370
|
+
};
|
|
1371
|
+
for (const p of params || []) {
|
|
1372
|
+
if (/^[A-Za-z_$][\w$]*$/.test(p)) {
|
|
1373
|
+
scope.bindings.set(p, { kind: "param", init: null, declOffset: lo });
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
let i = lo;
|
|
1377
|
+
let parenDepth = 0;
|
|
1378
|
+
while (i < hi) {
|
|
1379
|
+
if (isQuote(code[i])) {
|
|
1380
|
+
i = skipString(code, i);
|
|
1381
|
+
continue;
|
|
1382
|
+
}
|
|
1383
|
+
if (parenDepth > 0) {
|
|
1384
|
+
if (code[i] === "(") parenDepth++;
|
|
1385
|
+
else if (code[i] === ")") parenDepth--;
|
|
1386
|
+
i++;
|
|
1387
|
+
continue;
|
|
1388
|
+
}
|
|
1389
|
+
if (code[i] === "(") {
|
|
1390
|
+
parenDepth++;
|
|
1391
|
+
i++;
|
|
1392
|
+
continue;
|
|
1393
|
+
}
|
|
1394
|
+
if (code[i] === "{") {
|
|
1395
|
+
const close = matchingBracket(code, i);
|
|
1396
|
+
if (close === -1 || close >= hi) {
|
|
1397
|
+
i++;
|
|
1398
|
+
continue;
|
|
1399
|
+
}
|
|
1400
|
+
let childParams = null;
|
|
1401
|
+
const pb = paramsBeforeBrace(code, i);
|
|
1402
|
+
if (pb) childParams = pb;
|
|
1403
|
+
const child = processRange(code, i + 1, close, scope, childParams);
|
|
1404
|
+
scope.children.push(child);
|
|
1405
|
+
i = close + 1;
|
|
1406
|
+
continue;
|
|
1407
|
+
}
|
|
1408
|
+
if (code[i] === "=" && code[i + 1] === ">") {
|
|
1409
|
+
const ps = arrowParams(code, i);
|
|
1410
|
+
let j = i + 2;
|
|
1411
|
+
while (j < hi && /\s/.test(code[j])) j++;
|
|
1412
|
+
if (j < hi && code[j] !== "{") {
|
|
1413
|
+
const bodyEnd = exprExtent(code, j, hi);
|
|
1414
|
+
const child = processRange(code, j, bodyEnd, scope, ps || []);
|
|
1415
|
+
scope.children.push(child);
|
|
1416
|
+
i = bodyEnd;
|
|
1417
|
+
continue;
|
|
1418
|
+
}
|
|
1419
|
+
i += 2;
|
|
1420
|
+
continue;
|
|
1421
|
+
}
|
|
1422
|
+
const letKw = isLetOrVarKeyword(code, i);
|
|
1423
|
+
if (letKw) {
|
|
1424
|
+
const kind = letKw;
|
|
1425
|
+
const parsed = parseConstDecl(code, i, hi, kind);
|
|
1426
|
+
for (const d of parsed.decls) {
|
|
1427
|
+
const names = d.name ? [d.name] : extractBindingNames(d.pattern);
|
|
1428
|
+
for (const n of names) {
|
|
1429
|
+
scope.bindings.set(n, { kind, init: null, declOffset: d.declOffset });
|
|
1430
|
+
}
|
|
1431
|
+
if (d.initStart !== null && d.initEnd !== null && d.initEnd > d.initStart) {
|
|
1432
|
+
const child = processRange(code, d.initStart, d.initEnd, scope, []);
|
|
1433
|
+
scope.children.push(child);
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
1436
|
+
i = parsed.endOffset;
|
|
1437
|
+
continue;
|
|
1438
|
+
}
|
|
1439
|
+
if (isConstKeyword(code, i)) {
|
|
1440
|
+
const parsed = parseConstDecl(code, i, hi, "const");
|
|
1441
|
+
for (const d of parsed.decls) {
|
|
1442
|
+
if (d.name) {
|
|
1443
|
+
scope.bindings.set(d.name, { kind: "const", init: d.init, declOffset: d.declOffset });
|
|
1444
|
+
} else {
|
|
1445
|
+
const names = extractBindingNames(d.pattern);
|
|
1446
|
+
for (const n of names) {
|
|
1447
|
+
scope.bindings.set(n, { kind: "other", init: null, declOffset: d.declOffset });
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1450
|
+
if (d.initStart !== null && d.initEnd !== null && d.initEnd > d.initStart) {
|
|
1451
|
+
const child = processRange(code, d.initStart, d.initEnd, scope, []);
|
|
1452
|
+
scope.children.push(child);
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
1455
|
+
i = parsed.endOffset;
|
|
1456
|
+
continue;
|
|
1457
|
+
}
|
|
1458
|
+
i++;
|
|
1459
|
+
}
|
|
1460
|
+
return scope;
|
|
1461
|
+
};
|
|
1462
|
+
|
|
1463
|
+
export const scopeAt = (root, offset) => {
|
|
1464
|
+
let cur = root;
|
|
1465
|
+
let changed = true;
|
|
1466
|
+
while (changed) {
|
|
1467
|
+
changed = false;
|
|
1468
|
+
for (const child of cur.children) {
|
|
1469
|
+
if (offset >= child.lo && offset < child.hi) {
|
|
1470
|
+
cur = child;
|
|
1471
|
+
changed = true;
|
|
1472
|
+
break;
|
|
1473
|
+
}
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1476
|
+
return cur;
|
|
1477
|
+
};
|
|
1478
|
+
|
|
1479
|
+
const resolveExpr = (text, scope, pos, visited) => {
|
|
1480
|
+
const t = text.trim();
|
|
1481
|
+
if (!t) return text;
|
|
1482
|
+
if (isQuote(t[0])) {
|
|
1483
|
+
const end = skipString(t, 0);
|
|
1484
|
+
if (end === t.length) return text;
|
|
1485
|
+
}
|
|
1486
|
+
if (/^-?\d+(?:\.\d+)?$/.test(t)) return text;
|
|
1487
|
+
if (/^colors\.[A-Za-z_$][\w$]*$/.test(t)) return text;
|
|
1488
|
+
if (/^[A-Za-z_$][\w$]*$/.test(t)) {
|
|
1489
|
+
const r = resolveIdent(t, scope, pos, visited || new Set());
|
|
1490
|
+
return r === null ? text : r;
|
|
1491
|
+
}
|
|
1492
|
+
let out = "";
|
|
1493
|
+
let i = 0;
|
|
1494
|
+
const v = visited || new Set();
|
|
1495
|
+
while (i < t.length) {
|
|
1496
|
+
const ch = t[i];
|
|
1497
|
+
if (isQuote(ch)) {
|
|
1498
|
+
const end = skipString(t, i);
|
|
1499
|
+
out += t.slice(i, end);
|
|
1500
|
+
i = end;
|
|
1501
|
+
continue;
|
|
1502
|
+
}
|
|
1503
|
+
if (/[A-Za-z_$]/.test(ch)) {
|
|
1504
|
+
const m = /^[A-Za-z_$][\w$]*/.exec(t.slice(i));
|
|
1505
|
+
const ident = m[0];
|
|
1506
|
+
const before = i > 0 ? t[i - 1] : "";
|
|
1507
|
+
const after = t[i + ident.length] || "";
|
|
1508
|
+
if (before !== "." && after !== ".") {
|
|
1509
|
+
const r = resolveIdent(ident, scope, pos, v);
|
|
1510
|
+
out += r === null ? ident : r;
|
|
1511
|
+
} else {
|
|
1512
|
+
out += ident;
|
|
1513
|
+
}
|
|
1514
|
+
i += ident.length;
|
|
1515
|
+
continue;
|
|
1516
|
+
}
|
|
1517
|
+
out += ch;
|
|
1518
|
+
i++;
|
|
1519
|
+
}
|
|
1520
|
+
return out;
|
|
1521
|
+
};
|
|
1522
|
+
|
|
1523
|
+
const resolveIdent = (name, scope, pos, visited) => {
|
|
1524
|
+
let cur = scope;
|
|
1525
|
+
while (cur) {
|
|
1526
|
+
const b = cur.bindings.get(name);
|
|
1527
|
+
if (b) {
|
|
1528
|
+
if (b.declOffset > pos) return null;
|
|
1529
|
+
if (b.kind !== "const") return null;
|
|
1530
|
+
if (b.init == null) return null;
|
|
1531
|
+
const key = name + "@" + (cur.lo || 0);
|
|
1532
|
+
if (visited.has(key)) return null;
|
|
1533
|
+
visited.add(key);
|
|
1534
|
+
const resolved = resolveExpr(b.init, cur, b.declOffset, visited);
|
|
1535
|
+
visited.delete(key);
|
|
1536
|
+
return resolved === null ? b.init : resolved;
|
|
1537
|
+
}
|
|
1538
|
+
cur = cur.parent;
|
|
1539
|
+
}
|
|
1540
|
+
return null;
|
|
1541
|
+
};
|
|
1542
|
+
|
|
900
1543
|
const checkFile = (file, ctx) => {
|
|
901
1544
|
const findings = [];
|
|
902
1545
|
const src = fs.readFileSync(file, "utf8");
|
|
903
1546
|
const code = blankComments(src);
|
|
1547
|
+
const rootScope = processRange(code, 0, code.length, null, []);
|
|
904
1548
|
const offsets = lineOffsets(src);
|
|
905
1549
|
const tokenFile = isTokenFile(file);
|
|
906
1550
|
const push = (line, codeName, message, detail) =>
|
|
@@ -914,7 +1558,15 @@ const checkFile = (file, ctx) => {
|
|
|
914
1558
|
const calls = findCalls(code).map((call) => {
|
|
915
1559
|
const props = new Map();
|
|
916
1560
|
for (const entry of entriesOf(code, call.open, call.close)) {
|
|
917
|
-
if (!props.has(entry.key))
|
|
1561
|
+
if (!props.has(entry.key)) {
|
|
1562
|
+
entry.resolved = resolveExpr(
|
|
1563
|
+
entry.value,
|
|
1564
|
+
scopeAt(rootScope, entry.valueStart),
|
|
1565
|
+
entry.valueStart,
|
|
1566
|
+
new Set(),
|
|
1567
|
+
);
|
|
1568
|
+
props.set(entry.key, entry);
|
|
1569
|
+
}
|
|
918
1570
|
}
|
|
919
1571
|
return { ...call, props };
|
|
920
1572
|
});
|
|
@@ -959,7 +1611,7 @@ const checkFile = (file, ctx) => {
|
|
|
959
1611
|
for (const key of TEXT_KEYS) {
|
|
960
1612
|
const entry = call.props.get(key);
|
|
961
1613
|
if (!entry) continue;
|
|
962
|
-
const match = /^['"`]([\s\S]*)['"`]$/.exec(entry.value.trim());
|
|
1614
|
+
const match = /^['"`]([\s\S]*)['"`]$/.exec((entry.resolved ?? entry.value).trim());
|
|
963
1615
|
return match ? match[1] : null;
|
|
964
1616
|
}
|
|
965
1617
|
return null;
|
|
@@ -1018,11 +1670,11 @@ const checkFile = (file, ctx) => {
|
|
|
1018
1670
|
if (SKIP_VALUE_KEYS.has(key)) continue;
|
|
1019
1671
|
const kind = ctx.propKinds.get(key);
|
|
1020
1672
|
const valueLine = lineOf(offsets, entry.valueStart);
|
|
1021
|
-
const measured = measuredNumbers(entry.value);
|
|
1673
|
+
const measured = measuredNumbers(entry.resolved ?? entry.value);
|
|
1022
1674
|
const numbers = measured.numbers;
|
|
1023
1675
|
|
|
1024
1676
|
if (kind === "color" || COLOR_FALLBACK_KEYS.has(key)) {
|
|
1025
|
-
const literal = colorLiteralIn(entry.value);
|
|
1677
|
+
const literal = colorLiteralIn(entry.resolved ?? entry.value);
|
|
1026
1678
|
if (literal && !tokenFile) {
|
|
1027
1679
|
push(
|
|
1028
1680
|
valueLine,
|
|
@@ -1030,7 +1682,7 @@ const checkFile = (file, ctx) => {
|
|
|
1030
1682
|
`${call.name} sets \`${key}\` to the literal ${literal}.`,
|
|
1031
1683
|
"Color comes from a token (`colors.text`, `colors.primary`). A typed hex is the first sign a screen drifted from the rest; if a token is missing, add it to src/database/themes.js.",
|
|
1032
1684
|
);
|
|
1033
|
-
} else if (/colors\.[A-Za-z0-9_]+\s*\+\s*['"][0-9a-fA-F]{2}['"]/.test(entry.value)) {
|
|
1685
|
+
} else if (/colors\.[A-Za-z0-9_]+\s*\+\s*['"][0-9a-fA-F]{2}['"]/.test(entry.resolved ?? entry.value)) {
|
|
1034
1686
|
push(
|
|
1035
1687
|
valueLine,
|
|
1036
1688
|
"HAND_MIXED_COLOR",
|
|
@@ -1093,9 +1745,9 @@ const checkFile = (file, ctx) => {
|
|
|
1093
1745
|
// is 40x40 and legal, while `size: 16` alone is the glyph and nothing else.
|
|
1094
1746
|
// A padding this pass cannot resolve makes the target unmeasured.
|
|
1095
1747
|
const padded = props.has("paddingVertical")
|
|
1096
|
-
? measuredNumbers(props.get("paddingVertical").value)
|
|
1748
|
+
? measuredNumbers(props.get("paddingVertical").resolved ?? props.get("paddingVertical").value)
|
|
1097
1749
|
: props.has("padding")
|
|
1098
|
-
? measuredNumbers(props.get("padding").value)
|
|
1750
|
+
? measuredNumbers(props.get("padding").resolved ?? props.get("padding").value)
|
|
1099
1751
|
: { measured: true, numbers: [0] };
|
|
1100
1752
|
const vertical = padded.measured ? Math.abs(padded.numbers[0] ?? 0) : null;
|
|
1101
1753
|
for (const n of numbers) {
|
|
@@ -1116,7 +1768,7 @@ const checkFile = (file, ctx) => {
|
|
|
1116
1768
|
if (
|
|
1117
1769
|
tappable &&
|
|
1118
1770
|
key === "size" &&
|
|
1119
|
-
/(['"])small\1/.test(entry.value) &&
|
|
1771
|
+
/(['"])small\1/.test(entry.resolved ?? entry.value) &&
|
|
1120
1772
|
!props.has("height") &&
|
|
1121
1773
|
!props.has("minHeight")
|
|
1122
1774
|
) {
|