@kbach/react-native 1.0.0-beta.19 → 1.0.0-beta.20
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/README.md +30 -8
- package/dist/jsx-dev-runtime.js +229 -153
- package/dist/jsx-dev-runtime.web.mjs +1 -1
- package/dist/jsx-runtime.js +229 -153
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -184,14 +184,36 @@ constant `px`/`rem` length (or a bare number). This works because native has
|
|
|
184
184
|
no CSS engine to evaluate a real `calc()` string at paint time, so the only
|
|
185
185
|
way to support it at all is to compute the answer ourselves.
|
|
186
186
|
|
|
187
|
-
A **
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
187
|
+
A **viewport-relative** expression (`calc(10vw+8px)`) can't be reduced this
|
|
188
|
+
way — no such unit exists on native at all. It already works fine on web
|
|
189
|
+
(real CSS); on native the declaration is dropped and a `console.warn`
|
|
190
|
+
explains why (dev builds only).
|
|
191
|
+
|
|
192
|
+
**Percentage-relative width/height** (`calc(100%-3rem)`, `calc(50%+16px)`)
|
|
193
|
+
IS supported, differently: since native has no way to know "100% of what"
|
|
194
|
+
ahead of time, this measures the element's own real layout instead —
|
|
195
|
+
|
|
196
|
+
```tsx
|
|
197
|
+
<View className="w-[calc(100%_-_3rem)]" />
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Renders once at a plain `100%` (a real RN percentage, resolved correctly by
|
|
201
|
+
RN's own layout engine against the parent) purely to trigger a layout
|
|
202
|
+
event, then immediately corrects to the actual computed number once
|
|
203
|
+
measured — a genuine one-frame measure-then-snap, not instant math like the
|
|
204
|
+
constant-only case above, and it keeps re-measuring on every layout (screen
|
|
205
|
+
rotation, parent resize, ...) rather than freezing after the first value.
|
|
206
|
+
Scoped to exactly one percentage term plus one constant term on `width`/
|
|
207
|
+
`height` only — `calc(50%-50%)`, other properties, or anything with `*`/`/`
|
|
208
|
+
falls through to the same drop-and-warn behavior as before.
|
|
209
|
+
|
|
210
|
+
**Arbitrary values can't contain literal spaces** — this is a pre-existing
|
|
211
|
+
rule (real Tailwind has the same one), not specific to `calc()`: a space
|
|
212
|
+
inside `[...]` is indistinguishable from the whitespace that separates
|
|
213
|
+
class tokens in the first place, so `w-[calc(100% - 3rem)]` silently splits
|
|
214
|
+
into three broken tokens before `calc()` is ever even recognized. Write
|
|
215
|
+
`w-[calc(100%_-_3rem)]` (underscores) instead — this is exactly what the
|
|
216
|
+
unknown-class warning below is for: it'll tell you when this happens.
|
|
195
217
|
|
|
196
218
|
## Unknown-class warnings (typo detection)
|
|
197
219
|
|
package/dist/jsx-dev-runtime.js
CHANGED
|
@@ -32,6 +32,182 @@ var import_react_native = require("react-native");
|
|
|
32
32
|
var import_darkModeStore = require("./darkModeStore");
|
|
33
33
|
var import_dynamicTokens = require("./dynamicTokens");
|
|
34
34
|
var import_theme = require("./theme");
|
|
35
|
+
|
|
36
|
+
// src/jsEngine/calc.ts
|
|
37
|
+
function reduceConstantMath(raw) {
|
|
38
|
+
const trimmed = raw.trim();
|
|
39
|
+
const calc = stripCall(trimmed, "calc");
|
|
40
|
+
if (calc !== null) {
|
|
41
|
+
return new Evaluator(calc).parseExprToEnd();
|
|
42
|
+
}
|
|
43
|
+
const clamp = stripCall(trimmed, "clamp");
|
|
44
|
+
if (clamp !== null) {
|
|
45
|
+
const args = splitTopLevelCommas(clamp);
|
|
46
|
+
if (args.length !== 3) return null;
|
|
47
|
+
const [min2, preferred, max2] = args.map((a) => new Evaluator(a).parseExprToEnd());
|
|
48
|
+
if (min2 === null || preferred === null || max2 === null) return null;
|
|
49
|
+
return Math.max(min2, Math.min(preferred, max2));
|
|
50
|
+
}
|
|
51
|
+
const min = stripCall(trimmed, "min");
|
|
52
|
+
if (min !== null) {
|
|
53
|
+
const values = splitTopLevelCommas(min).map((a) => new Evaluator(a).parseExprToEnd());
|
|
54
|
+
return values.some((v) => v === null) ? null : Math.min(...values);
|
|
55
|
+
}
|
|
56
|
+
const max = stripCall(trimmed, "max");
|
|
57
|
+
if (max !== null) {
|
|
58
|
+
const values = splitTopLevelCommas(max).map((a) => new Evaluator(a).parseExprToEnd());
|
|
59
|
+
return values.some((v) => v === null) ? null : Math.max(...values);
|
|
60
|
+
}
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
function stripCall(raw, name) {
|
|
64
|
+
if (!raw.startsWith(name)) return null;
|
|
65
|
+
const afterName = raw.slice(name.length).trimStart();
|
|
66
|
+
if (!afterName.startsWith("(") || !afterName.endsWith(")")) return null;
|
|
67
|
+
return afterName.slice(1, -1);
|
|
68
|
+
}
|
|
69
|
+
function splitTopLevelCommas(s) {
|
|
70
|
+
const parts = [];
|
|
71
|
+
let depth = 0;
|
|
72
|
+
let start = 0;
|
|
73
|
+
for (let i = 0; i < s.length; i++) {
|
|
74
|
+
const ch = s[i];
|
|
75
|
+
if (ch === "(") depth++;
|
|
76
|
+
else if (ch === ")") depth--;
|
|
77
|
+
else if (ch === "," && depth === 0) {
|
|
78
|
+
parts.push(s.slice(start, i).trim());
|
|
79
|
+
start = i + 1;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
parts.push(s.slice(start).trim());
|
|
83
|
+
return parts;
|
|
84
|
+
}
|
|
85
|
+
var Evaluator = class {
|
|
86
|
+
constructor(s) {
|
|
87
|
+
this.pos = 0;
|
|
88
|
+
this.s = s;
|
|
89
|
+
}
|
|
90
|
+
parseExprToEnd() {
|
|
91
|
+
const value = this.expr();
|
|
92
|
+
if (value === null) return null;
|
|
93
|
+
this.skipWs();
|
|
94
|
+
return this.pos === this.s.length ? value : null;
|
|
95
|
+
}
|
|
96
|
+
skipWs() {
|
|
97
|
+
while (this.pos < this.s.length && /\s/.test(this.s[this.pos])) this.pos++;
|
|
98
|
+
}
|
|
99
|
+
peek() {
|
|
100
|
+
this.skipWs();
|
|
101
|
+
return this.s[this.pos];
|
|
102
|
+
}
|
|
103
|
+
expr() {
|
|
104
|
+
let value = this.term();
|
|
105
|
+
if (value === null) return null;
|
|
106
|
+
for (; ; ) {
|
|
107
|
+
const ch = this.peek();
|
|
108
|
+
if (ch === "+") {
|
|
109
|
+
this.pos++;
|
|
110
|
+
const rhs = this.term();
|
|
111
|
+
if (rhs === null) return null;
|
|
112
|
+
value += rhs;
|
|
113
|
+
} else if (ch === "-") {
|
|
114
|
+
this.pos++;
|
|
115
|
+
const rhs = this.term();
|
|
116
|
+
if (rhs === null) return null;
|
|
117
|
+
value -= rhs;
|
|
118
|
+
} else {
|
|
119
|
+
return value;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
term() {
|
|
124
|
+
let value = this.factor();
|
|
125
|
+
if (value === null) return null;
|
|
126
|
+
for (; ; ) {
|
|
127
|
+
const ch = this.peek();
|
|
128
|
+
if (ch === "*") {
|
|
129
|
+
this.pos++;
|
|
130
|
+
const rhs = this.factor();
|
|
131
|
+
if (rhs === null) return null;
|
|
132
|
+
value *= rhs;
|
|
133
|
+
} else if (ch === "/") {
|
|
134
|
+
this.pos++;
|
|
135
|
+
const divisor = this.factor();
|
|
136
|
+
if (divisor === null || divisor === 0) return null;
|
|
137
|
+
value /= divisor;
|
|
138
|
+
} else {
|
|
139
|
+
return value;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
factor() {
|
|
144
|
+
const ch = this.peek();
|
|
145
|
+
if (ch === void 0) return null;
|
|
146
|
+
if (ch === "(") {
|
|
147
|
+
this.pos++;
|
|
148
|
+
const value = this.expr();
|
|
149
|
+
if (value === null || this.peek() !== ")") return null;
|
|
150
|
+
this.pos++;
|
|
151
|
+
return value;
|
|
152
|
+
}
|
|
153
|
+
if (ch === "-") {
|
|
154
|
+
this.pos++;
|
|
155
|
+
const value = this.factor();
|
|
156
|
+
return value === null ? null : -value;
|
|
157
|
+
}
|
|
158
|
+
return this.numberWithUnit();
|
|
159
|
+
}
|
|
160
|
+
numberWithUnit() {
|
|
161
|
+
this.skipWs();
|
|
162
|
+
const start = this.pos;
|
|
163
|
+
while (this.pos < this.s.length && (/[0-9]/.test(this.s[this.pos]) || this.s[this.pos] === ".")) this.pos++;
|
|
164
|
+
if (this.pos === start) return null;
|
|
165
|
+
const n = Number(this.s.slice(start, this.pos));
|
|
166
|
+
if (!Number.isFinite(n)) return null;
|
|
167
|
+
const unitStart = this.pos;
|
|
168
|
+
while (this.pos < this.s.length && /[a-zA-Z]/.test(this.s[this.pos])) this.pos++;
|
|
169
|
+
const unit = this.s.slice(unitStart, this.pos);
|
|
170
|
+
switch (unit) {
|
|
171
|
+
case "":
|
|
172
|
+
return n;
|
|
173
|
+
case "px":
|
|
174
|
+
return n;
|
|
175
|
+
case "rem":
|
|
176
|
+
return n * 16;
|
|
177
|
+
default:
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
// src/layoutCalc.ts
|
|
184
|
+
var PERCENT_CALC_TOKEN_RE = /^(w|h)-\[calc\(([^)]+)\)\]$/;
|
|
185
|
+
function parsePercentRelativeCalc(token) {
|
|
186
|
+
const m = PERCENT_CALC_TOKEN_RE.exec(token);
|
|
187
|
+
if (!m) return null;
|
|
188
|
+
const property = m[1] === "w" ? "width" : "height";
|
|
189
|
+
const inner = m[2].replace(/_/g, " ").trim();
|
|
190
|
+
let mm = /^(-?[\d.]+)%\s*([+-])\s*(.+)$/.exec(inner);
|
|
191
|
+
if (mm) {
|
|
192
|
+
const percentCoefficient = Number(mm[1]);
|
|
193
|
+
const magnitude = reduceConstantMath(`calc(${mm[3].trim()})`);
|
|
194
|
+
if (!Number.isFinite(percentCoefficient) || magnitude === null) return null;
|
|
195
|
+
return { property, percentCoefficient, constantPx: mm[2] === "+" ? magnitude : -magnitude };
|
|
196
|
+
}
|
|
197
|
+
mm = /^(.+?)\s*([+-])\s*(-?[\d.]+)%$/.exec(inner);
|
|
198
|
+
if (mm) {
|
|
199
|
+
const constantPx = reduceConstantMath(`calc(${mm[1].trim()})`);
|
|
200
|
+
const percentMagnitude = Number(mm[3]);
|
|
201
|
+
if (constantPx === null || !Number.isFinite(percentMagnitude)) return null;
|
|
202
|
+
return { property, percentCoefficient: mm[2] === "+" ? percentMagnitude : -percentMagnitude, constantPx };
|
|
203
|
+
}
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
function resolvePercentRelativeCalc(basisPx, calc) {
|
|
207
|
+
return basisPx * calc.percentCoefficient / 100 + calc.constantPx;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// src/jsxRuntimeCore.ts
|
|
35
211
|
var DYNAMIC_TOKEN_MATCH_RE = /var\(--([a-zA-Z0-9-]+)\)/g;
|
|
36
212
|
function substituteDynamicTokens(classStrRaw) {
|
|
37
213
|
if (!classStrRaw.includes("var(--")) return classStrRaw;
|
|
@@ -40,11 +216,27 @@ function substituteDynamicTokens(classStrRaw) {
|
|
|
40
216
|
return value ?? whole;
|
|
41
217
|
});
|
|
42
218
|
}
|
|
219
|
+
var PERCENT_RELATIVE_CALC_HINT_RE = /[wh]-\[calc\([^)]*%[^)]*\)\]/;
|
|
220
|
+
function extractPercentRelativeCalcs(classStrRaw) {
|
|
221
|
+
const found = [];
|
|
222
|
+
for (const token of classStrRaw.split(/\s+/)) {
|
|
223
|
+
const parsed = parsePercentRelativeCalc(token);
|
|
224
|
+
if (parsed) found.push(parsed);
|
|
225
|
+
}
|
|
226
|
+
return found;
|
|
227
|
+
}
|
|
228
|
+
function stripPercentRelativeCalcTokens(classStrRaw) {
|
|
229
|
+
return classStrRaw.split(/\s+/).filter((token) => token && parsePercentRelativeCalc(token) === null).join(" ");
|
|
230
|
+
}
|
|
43
231
|
function makeElement(isStaticChildren, type, props, key) {
|
|
44
232
|
return (isStaticChildren ? import_jsx_runtime.jsxs : import_jsx_runtime.jsx)(type, props, key);
|
|
45
233
|
}
|
|
46
|
-
function resolvedStyleFor(resolveStyle2, classStrRaw, userStyle, pressed) {
|
|
47
|
-
const
|
|
234
|
+
function resolvedStyleFor(resolveStyle2, classStrRaw, userStyle, pressed, layoutOverrides) {
|
|
235
|
+
const cleaned = stripPercentRelativeCalcTokens(substituteDynamicTokens(classStrRaw));
|
|
236
|
+
const resolved = resolveStyle2(cleaned, pressed);
|
|
237
|
+
if (layoutOverrides) {
|
|
238
|
+
Object.assign(resolved, layoutOverrides);
|
|
239
|
+
}
|
|
48
240
|
if (userStyle === void 0) {
|
|
49
241
|
return resolved;
|
|
50
242
|
}
|
|
@@ -75,6 +267,14 @@ function dynamicTokenKeySuffix(classStrRaw) {
|
|
|
75
267
|
const values = matches.map((m) => (0, import_dynamicTokens.getDynamicToken)(m.slice("var(--".length, -1)) ?? "");
|
|
76
268
|
return `:kb-dt-${values.join("|")}`;
|
|
77
269
|
}
|
|
270
|
+
function percentCalcKeySuffix(percentCalcs, measuredBasis) {
|
|
271
|
+
if (percentCalcs.length === 0) return "";
|
|
272
|
+
const values = percentCalcs.map((calc) => {
|
|
273
|
+
const basis = measuredBasis?.[calc.property];
|
|
274
|
+
return basis === void 0 ? "pending" : resolvePercentRelativeCalc(basis, calc);
|
|
275
|
+
});
|
|
276
|
+
return `:kb-pc-${values.join("|")}`;
|
|
277
|
+
}
|
|
78
278
|
function ReactiveElement({
|
|
79
279
|
hostType,
|
|
80
280
|
hostRest,
|
|
@@ -87,10 +287,33 @@ function ReactiveElement({
|
|
|
87
287
|
(0, import_react.useSyncExternalStore)(import_darkModeStore.subscribeGlobalDarkMode, import_darkModeStore.getGlobalDarkMode);
|
|
88
288
|
(0, import_react.useSyncExternalStore)(import_dynamicTokens.subscribeDynamicTokens, import_dynamicTokens.getDynamicTokensVersion);
|
|
89
289
|
const { width } = (0, import_react_native.useWindowDimensions)();
|
|
90
|
-
const
|
|
91
|
-
const
|
|
290
|
+
const [measuredBasis, setMeasuredBasis] = (0, import_react.useState)(null);
|
|
291
|
+
const measure = (0, import_react.useCallback)((e) => {
|
|
292
|
+
const { width: w, height: h } = e.nativeEvent.layout;
|
|
293
|
+
setMeasuredBasis((prev) => prev && prev.width === w && prev.height === h ? prev : { width: w, height: h });
|
|
294
|
+
}, []);
|
|
295
|
+
const percentCalcs = extractPercentRelativeCalcs(classStrRaw);
|
|
296
|
+
let layoutOverrides;
|
|
297
|
+
let hostRestWithLayout = hostRest;
|
|
298
|
+
if (percentCalcs.length > 0) {
|
|
299
|
+
layoutOverrides = {};
|
|
300
|
+
for (const calc of percentCalcs) {
|
|
301
|
+
const basis = measuredBasis?.[calc.property];
|
|
302
|
+
layoutOverrides[calc.property] = basis === void 0 ? "100%" : resolvePercentRelativeCalc(basis, calc);
|
|
303
|
+
}
|
|
304
|
+
const userOnLayout = hostRest.onLayout;
|
|
305
|
+
hostRestWithLayout = {
|
|
306
|
+
...hostRest,
|
|
307
|
+
onLayout: userOnLayout ? (e) => {
|
|
308
|
+
measure(e);
|
|
309
|
+
userOnLayout(e);
|
|
310
|
+
} : measure
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
const finalStyle = hostType === import_react_native.Pressable ? (state) => resolvedStyleFor(resolveStyle2, classStrRaw, userStyle, state.pressed, layoutOverrides) : resolvedStyleFor(resolveStyle2, classStrRaw, userStyle, false, layoutOverrides);
|
|
314
|
+
const suffix = darkModeKeySuffix(classStrRaw) + breakpointKeySuffix(classStrRaw, width) + dynamicTokenKeySuffix(classStrRaw) + percentCalcKeySuffix(percentCalcs, measuredBasis);
|
|
92
315
|
const finalKey = suffix ? `${elementKey ?? ""}${suffix}` : elementKey;
|
|
93
|
-
return makeElement(isStaticChildren, hostType, { ...
|
|
316
|
+
return makeElement(isStaticChildren, hostType, { ...hostRestWithLayout, style: finalStyle }, finalKey);
|
|
94
317
|
}
|
|
95
318
|
function processElement(resolveStyle2, type, rawProps, key, isStaticChildren) {
|
|
96
319
|
if (type === null || typeof type === "symbol" || !rawProps) {
|
|
@@ -100,7 +323,7 @@ function processElement(resolveStyle2, type, rawProps, key, isStaticChildren) {
|
|
|
100
323
|
if (typeof classStrRaw !== "string") {
|
|
101
324
|
return makeElement(isStaticChildren, type, rawProps, key);
|
|
102
325
|
}
|
|
103
|
-
if (DARK_MODIFIER_RE.test(classStrRaw) || BREAKPOINT_MODIFIER_RE.test(classStrRaw) || classStrRaw.includes("var(--")) {
|
|
326
|
+
if (DARK_MODIFIER_RE.test(classStrRaw) || BREAKPOINT_MODIFIER_RE.test(classStrRaw) || classStrRaw.includes("var(--") || PERCENT_RELATIVE_CALC_HINT_RE.test(classStrRaw)) {
|
|
104
327
|
return (0, import_jsx_runtime.jsx)(
|
|
105
328
|
ReactiveElement,
|
|
106
329
|
{ hostType: type, hostRest: rest, classStrRaw, userStyle, resolveStyle: resolveStyle2, elementKey: key, isStaticChildren },
|
|
@@ -1231,153 +1454,6 @@ function resolveUtilityNative(parsed, theme) {
|
|
|
1231
1454
|
return resolveFlex(parsed, false) ?? resolve(parsed, theme) ?? resolve2(parsed, theme) ?? resolve3(parsed, theme) ?? resolveColorNative(parsed, theme) ?? resolveLeadingTrackingNative(parsed) ?? resolveTypographyNative(parsed) ?? nativeShadowDeclarations(parsed);
|
|
1232
1455
|
}
|
|
1233
1456
|
|
|
1234
|
-
// src/jsEngine/calc.ts
|
|
1235
|
-
function reduceConstantMath(raw) {
|
|
1236
|
-
const trimmed = raw.trim();
|
|
1237
|
-
const calc = stripCall(trimmed, "calc");
|
|
1238
|
-
if (calc !== null) {
|
|
1239
|
-
return new Evaluator(calc).parseExprToEnd();
|
|
1240
|
-
}
|
|
1241
|
-
const clamp = stripCall(trimmed, "clamp");
|
|
1242
|
-
if (clamp !== null) {
|
|
1243
|
-
const args = splitTopLevelCommas(clamp);
|
|
1244
|
-
if (args.length !== 3) return null;
|
|
1245
|
-
const [min2, preferred, max2] = args.map((a) => new Evaluator(a).parseExprToEnd());
|
|
1246
|
-
if (min2 === null || preferred === null || max2 === null) return null;
|
|
1247
|
-
return Math.max(min2, Math.min(preferred, max2));
|
|
1248
|
-
}
|
|
1249
|
-
const min = stripCall(trimmed, "min");
|
|
1250
|
-
if (min !== null) {
|
|
1251
|
-
const values = splitTopLevelCommas(min).map((a) => new Evaluator(a).parseExprToEnd());
|
|
1252
|
-
return values.some((v) => v === null) ? null : Math.min(...values);
|
|
1253
|
-
}
|
|
1254
|
-
const max = stripCall(trimmed, "max");
|
|
1255
|
-
if (max !== null) {
|
|
1256
|
-
const values = splitTopLevelCommas(max).map((a) => new Evaluator(a).parseExprToEnd());
|
|
1257
|
-
return values.some((v) => v === null) ? null : Math.max(...values);
|
|
1258
|
-
}
|
|
1259
|
-
return null;
|
|
1260
|
-
}
|
|
1261
|
-
function stripCall(raw, name) {
|
|
1262
|
-
if (!raw.startsWith(name)) return null;
|
|
1263
|
-
const afterName = raw.slice(name.length).trimStart();
|
|
1264
|
-
if (!afterName.startsWith("(") || !afterName.endsWith(")")) return null;
|
|
1265
|
-
return afterName.slice(1, -1);
|
|
1266
|
-
}
|
|
1267
|
-
function splitTopLevelCommas(s) {
|
|
1268
|
-
const parts = [];
|
|
1269
|
-
let depth = 0;
|
|
1270
|
-
let start = 0;
|
|
1271
|
-
for (let i = 0; i < s.length; i++) {
|
|
1272
|
-
const ch = s[i];
|
|
1273
|
-
if (ch === "(") depth++;
|
|
1274
|
-
else if (ch === ")") depth--;
|
|
1275
|
-
else if (ch === "," && depth === 0) {
|
|
1276
|
-
parts.push(s.slice(start, i).trim());
|
|
1277
|
-
start = i + 1;
|
|
1278
|
-
}
|
|
1279
|
-
}
|
|
1280
|
-
parts.push(s.slice(start).trim());
|
|
1281
|
-
return parts;
|
|
1282
|
-
}
|
|
1283
|
-
var Evaluator = class {
|
|
1284
|
-
constructor(s) {
|
|
1285
|
-
this.pos = 0;
|
|
1286
|
-
this.s = s;
|
|
1287
|
-
}
|
|
1288
|
-
parseExprToEnd() {
|
|
1289
|
-
const value = this.expr();
|
|
1290
|
-
if (value === null) return null;
|
|
1291
|
-
this.skipWs();
|
|
1292
|
-
return this.pos === this.s.length ? value : null;
|
|
1293
|
-
}
|
|
1294
|
-
skipWs() {
|
|
1295
|
-
while (this.pos < this.s.length && /\s/.test(this.s[this.pos])) this.pos++;
|
|
1296
|
-
}
|
|
1297
|
-
peek() {
|
|
1298
|
-
this.skipWs();
|
|
1299
|
-
return this.s[this.pos];
|
|
1300
|
-
}
|
|
1301
|
-
expr() {
|
|
1302
|
-
let value = this.term();
|
|
1303
|
-
if (value === null) return null;
|
|
1304
|
-
for (; ; ) {
|
|
1305
|
-
const ch = this.peek();
|
|
1306
|
-
if (ch === "+") {
|
|
1307
|
-
this.pos++;
|
|
1308
|
-
const rhs = this.term();
|
|
1309
|
-
if (rhs === null) return null;
|
|
1310
|
-
value += rhs;
|
|
1311
|
-
} else if (ch === "-") {
|
|
1312
|
-
this.pos++;
|
|
1313
|
-
const rhs = this.term();
|
|
1314
|
-
if (rhs === null) return null;
|
|
1315
|
-
value -= rhs;
|
|
1316
|
-
} else {
|
|
1317
|
-
return value;
|
|
1318
|
-
}
|
|
1319
|
-
}
|
|
1320
|
-
}
|
|
1321
|
-
term() {
|
|
1322
|
-
let value = this.factor();
|
|
1323
|
-
if (value === null) return null;
|
|
1324
|
-
for (; ; ) {
|
|
1325
|
-
const ch = this.peek();
|
|
1326
|
-
if (ch === "*") {
|
|
1327
|
-
this.pos++;
|
|
1328
|
-
const rhs = this.factor();
|
|
1329
|
-
if (rhs === null) return null;
|
|
1330
|
-
value *= rhs;
|
|
1331
|
-
} else if (ch === "/") {
|
|
1332
|
-
this.pos++;
|
|
1333
|
-
const divisor = this.factor();
|
|
1334
|
-
if (divisor === null || divisor === 0) return null;
|
|
1335
|
-
value /= divisor;
|
|
1336
|
-
} else {
|
|
1337
|
-
return value;
|
|
1338
|
-
}
|
|
1339
|
-
}
|
|
1340
|
-
}
|
|
1341
|
-
factor() {
|
|
1342
|
-
const ch = this.peek();
|
|
1343
|
-
if (ch === void 0) return null;
|
|
1344
|
-
if (ch === "(") {
|
|
1345
|
-
this.pos++;
|
|
1346
|
-
const value = this.expr();
|
|
1347
|
-
if (value === null || this.peek() !== ")") return null;
|
|
1348
|
-
this.pos++;
|
|
1349
|
-
return value;
|
|
1350
|
-
}
|
|
1351
|
-
if (ch === "-") {
|
|
1352
|
-
this.pos++;
|
|
1353
|
-
const value = this.factor();
|
|
1354
|
-
return value === null ? null : -value;
|
|
1355
|
-
}
|
|
1356
|
-
return this.numberWithUnit();
|
|
1357
|
-
}
|
|
1358
|
-
numberWithUnit() {
|
|
1359
|
-
this.skipWs();
|
|
1360
|
-
const start = this.pos;
|
|
1361
|
-
while (this.pos < this.s.length && (/[0-9]/.test(this.s[this.pos]) || this.s[this.pos] === ".")) this.pos++;
|
|
1362
|
-
if (this.pos === start) return null;
|
|
1363
|
-
const n = Number(this.s.slice(start, this.pos));
|
|
1364
|
-
if (!Number.isFinite(n)) return null;
|
|
1365
|
-
const unitStart = this.pos;
|
|
1366
|
-
while (this.pos < this.s.length && /[a-zA-Z]/.test(this.s[this.pos])) this.pos++;
|
|
1367
|
-
const unit = this.s.slice(unitStart, this.pos);
|
|
1368
|
-
switch (unit) {
|
|
1369
|
-
case "":
|
|
1370
|
-
return n;
|
|
1371
|
-
case "px":
|
|
1372
|
-
return n;
|
|
1373
|
-
case "rem":
|
|
1374
|
-
return n * 16;
|
|
1375
|
-
default:
|
|
1376
|
-
return null;
|
|
1377
|
-
}
|
|
1378
|
-
}
|
|
1379
|
-
};
|
|
1380
|
-
|
|
1381
1457
|
// src/jsEngine/resolveStyle.ts
|
|
1382
1458
|
var RESPONSIVE_BREAKPOINTS = /* @__PURE__ */ new Set(["sm", "md", "lg", "xl", "2xl"]);
|
|
1383
1459
|
function nativeModifierState(modifier, theme, colorScheme, pressed, width) {
|
|
@@ -8,7 +8,7 @@ import "./chunk-OGFB3OXS.mjs";
|
|
|
8
8
|
|
|
9
9
|
// src/jsxRuntimeCore.ts
|
|
10
10
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
11
|
-
import { Fragment as Fragment2, useSyncExternalStore } from "react";
|
|
11
|
+
import { Fragment as Fragment2, useCallback, useState, useSyncExternalStore } from "react";
|
|
12
12
|
import { Pressable, useWindowDimensions } from "react-native";
|
|
13
13
|
function createJsxDEV(jsx2, jsxs2) {
|
|
14
14
|
return function jsxDEV2(type, props, key, isStaticChildren, source, self) {
|
package/dist/jsx-runtime.js
CHANGED
|
@@ -33,6 +33,182 @@ var import_react_native = require("react-native");
|
|
|
33
33
|
var import_darkModeStore = require("./darkModeStore");
|
|
34
34
|
var import_dynamicTokens = require("./dynamicTokens");
|
|
35
35
|
var import_theme = require("./theme");
|
|
36
|
+
|
|
37
|
+
// src/jsEngine/calc.ts
|
|
38
|
+
function reduceConstantMath(raw) {
|
|
39
|
+
const trimmed = raw.trim();
|
|
40
|
+
const calc = stripCall(trimmed, "calc");
|
|
41
|
+
if (calc !== null) {
|
|
42
|
+
return new Evaluator(calc).parseExprToEnd();
|
|
43
|
+
}
|
|
44
|
+
const clamp = stripCall(trimmed, "clamp");
|
|
45
|
+
if (clamp !== null) {
|
|
46
|
+
const args = splitTopLevelCommas(clamp);
|
|
47
|
+
if (args.length !== 3) return null;
|
|
48
|
+
const [min2, preferred, max2] = args.map((a) => new Evaluator(a).parseExprToEnd());
|
|
49
|
+
if (min2 === null || preferred === null || max2 === null) return null;
|
|
50
|
+
return Math.max(min2, Math.min(preferred, max2));
|
|
51
|
+
}
|
|
52
|
+
const min = stripCall(trimmed, "min");
|
|
53
|
+
if (min !== null) {
|
|
54
|
+
const values = splitTopLevelCommas(min).map((a) => new Evaluator(a).parseExprToEnd());
|
|
55
|
+
return values.some((v) => v === null) ? null : Math.min(...values);
|
|
56
|
+
}
|
|
57
|
+
const max = stripCall(trimmed, "max");
|
|
58
|
+
if (max !== null) {
|
|
59
|
+
const values = splitTopLevelCommas(max).map((a) => new Evaluator(a).parseExprToEnd());
|
|
60
|
+
return values.some((v) => v === null) ? null : Math.max(...values);
|
|
61
|
+
}
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
function stripCall(raw, name) {
|
|
65
|
+
if (!raw.startsWith(name)) return null;
|
|
66
|
+
const afterName = raw.slice(name.length).trimStart();
|
|
67
|
+
if (!afterName.startsWith("(") || !afterName.endsWith(")")) return null;
|
|
68
|
+
return afterName.slice(1, -1);
|
|
69
|
+
}
|
|
70
|
+
function splitTopLevelCommas(s) {
|
|
71
|
+
const parts = [];
|
|
72
|
+
let depth = 0;
|
|
73
|
+
let start = 0;
|
|
74
|
+
for (let i = 0; i < s.length; i++) {
|
|
75
|
+
const ch = s[i];
|
|
76
|
+
if (ch === "(") depth++;
|
|
77
|
+
else if (ch === ")") depth--;
|
|
78
|
+
else if (ch === "," && depth === 0) {
|
|
79
|
+
parts.push(s.slice(start, i).trim());
|
|
80
|
+
start = i + 1;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
parts.push(s.slice(start).trim());
|
|
84
|
+
return parts;
|
|
85
|
+
}
|
|
86
|
+
var Evaluator = class {
|
|
87
|
+
constructor(s) {
|
|
88
|
+
this.pos = 0;
|
|
89
|
+
this.s = s;
|
|
90
|
+
}
|
|
91
|
+
parseExprToEnd() {
|
|
92
|
+
const value = this.expr();
|
|
93
|
+
if (value === null) return null;
|
|
94
|
+
this.skipWs();
|
|
95
|
+
return this.pos === this.s.length ? value : null;
|
|
96
|
+
}
|
|
97
|
+
skipWs() {
|
|
98
|
+
while (this.pos < this.s.length && /\s/.test(this.s[this.pos])) this.pos++;
|
|
99
|
+
}
|
|
100
|
+
peek() {
|
|
101
|
+
this.skipWs();
|
|
102
|
+
return this.s[this.pos];
|
|
103
|
+
}
|
|
104
|
+
expr() {
|
|
105
|
+
let value = this.term();
|
|
106
|
+
if (value === null) return null;
|
|
107
|
+
for (; ; ) {
|
|
108
|
+
const ch = this.peek();
|
|
109
|
+
if (ch === "+") {
|
|
110
|
+
this.pos++;
|
|
111
|
+
const rhs = this.term();
|
|
112
|
+
if (rhs === null) return null;
|
|
113
|
+
value += rhs;
|
|
114
|
+
} else if (ch === "-") {
|
|
115
|
+
this.pos++;
|
|
116
|
+
const rhs = this.term();
|
|
117
|
+
if (rhs === null) return null;
|
|
118
|
+
value -= rhs;
|
|
119
|
+
} else {
|
|
120
|
+
return value;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
term() {
|
|
125
|
+
let value = this.factor();
|
|
126
|
+
if (value === null) return null;
|
|
127
|
+
for (; ; ) {
|
|
128
|
+
const ch = this.peek();
|
|
129
|
+
if (ch === "*") {
|
|
130
|
+
this.pos++;
|
|
131
|
+
const rhs = this.factor();
|
|
132
|
+
if (rhs === null) return null;
|
|
133
|
+
value *= rhs;
|
|
134
|
+
} else if (ch === "/") {
|
|
135
|
+
this.pos++;
|
|
136
|
+
const divisor = this.factor();
|
|
137
|
+
if (divisor === null || divisor === 0) return null;
|
|
138
|
+
value /= divisor;
|
|
139
|
+
} else {
|
|
140
|
+
return value;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
factor() {
|
|
145
|
+
const ch = this.peek();
|
|
146
|
+
if (ch === void 0) return null;
|
|
147
|
+
if (ch === "(") {
|
|
148
|
+
this.pos++;
|
|
149
|
+
const value = this.expr();
|
|
150
|
+
if (value === null || this.peek() !== ")") return null;
|
|
151
|
+
this.pos++;
|
|
152
|
+
return value;
|
|
153
|
+
}
|
|
154
|
+
if (ch === "-") {
|
|
155
|
+
this.pos++;
|
|
156
|
+
const value = this.factor();
|
|
157
|
+
return value === null ? null : -value;
|
|
158
|
+
}
|
|
159
|
+
return this.numberWithUnit();
|
|
160
|
+
}
|
|
161
|
+
numberWithUnit() {
|
|
162
|
+
this.skipWs();
|
|
163
|
+
const start = this.pos;
|
|
164
|
+
while (this.pos < this.s.length && (/[0-9]/.test(this.s[this.pos]) || this.s[this.pos] === ".")) this.pos++;
|
|
165
|
+
if (this.pos === start) return null;
|
|
166
|
+
const n = Number(this.s.slice(start, this.pos));
|
|
167
|
+
if (!Number.isFinite(n)) return null;
|
|
168
|
+
const unitStart = this.pos;
|
|
169
|
+
while (this.pos < this.s.length && /[a-zA-Z]/.test(this.s[this.pos])) this.pos++;
|
|
170
|
+
const unit = this.s.slice(unitStart, this.pos);
|
|
171
|
+
switch (unit) {
|
|
172
|
+
case "":
|
|
173
|
+
return n;
|
|
174
|
+
case "px":
|
|
175
|
+
return n;
|
|
176
|
+
case "rem":
|
|
177
|
+
return n * 16;
|
|
178
|
+
default:
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
// src/layoutCalc.ts
|
|
185
|
+
var PERCENT_CALC_TOKEN_RE = /^(w|h)-\[calc\(([^)]+)\)\]$/;
|
|
186
|
+
function parsePercentRelativeCalc(token) {
|
|
187
|
+
const m = PERCENT_CALC_TOKEN_RE.exec(token);
|
|
188
|
+
if (!m) return null;
|
|
189
|
+
const property = m[1] === "w" ? "width" : "height";
|
|
190
|
+
const inner = m[2].replace(/_/g, " ").trim();
|
|
191
|
+
let mm = /^(-?[\d.]+)%\s*([+-])\s*(.+)$/.exec(inner);
|
|
192
|
+
if (mm) {
|
|
193
|
+
const percentCoefficient = Number(mm[1]);
|
|
194
|
+
const magnitude = reduceConstantMath(`calc(${mm[3].trim()})`);
|
|
195
|
+
if (!Number.isFinite(percentCoefficient) || magnitude === null) return null;
|
|
196
|
+
return { property, percentCoefficient, constantPx: mm[2] === "+" ? magnitude : -magnitude };
|
|
197
|
+
}
|
|
198
|
+
mm = /^(.+?)\s*([+-])\s*(-?[\d.]+)%$/.exec(inner);
|
|
199
|
+
if (mm) {
|
|
200
|
+
const constantPx = reduceConstantMath(`calc(${mm[1].trim()})`);
|
|
201
|
+
const percentMagnitude = Number(mm[3]);
|
|
202
|
+
if (constantPx === null || !Number.isFinite(percentMagnitude)) return null;
|
|
203
|
+
return { property, percentCoefficient: mm[2] === "+" ? percentMagnitude : -percentMagnitude, constantPx };
|
|
204
|
+
}
|
|
205
|
+
return null;
|
|
206
|
+
}
|
|
207
|
+
function resolvePercentRelativeCalc(basisPx, calc) {
|
|
208
|
+
return basisPx * calc.percentCoefficient / 100 + calc.constantPx;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// src/jsxRuntimeCore.ts
|
|
36
212
|
var DYNAMIC_TOKEN_MATCH_RE = /var\(--([a-zA-Z0-9-]+)\)/g;
|
|
37
213
|
function substituteDynamicTokens(classStrRaw) {
|
|
38
214
|
if (!classStrRaw.includes("var(--")) return classStrRaw;
|
|
@@ -41,11 +217,27 @@ function substituteDynamicTokens(classStrRaw) {
|
|
|
41
217
|
return value ?? whole;
|
|
42
218
|
});
|
|
43
219
|
}
|
|
220
|
+
var PERCENT_RELATIVE_CALC_HINT_RE = /[wh]-\[calc\([^)]*%[^)]*\)\]/;
|
|
221
|
+
function extractPercentRelativeCalcs(classStrRaw) {
|
|
222
|
+
const found = [];
|
|
223
|
+
for (const token of classStrRaw.split(/\s+/)) {
|
|
224
|
+
const parsed = parsePercentRelativeCalc(token);
|
|
225
|
+
if (parsed) found.push(parsed);
|
|
226
|
+
}
|
|
227
|
+
return found;
|
|
228
|
+
}
|
|
229
|
+
function stripPercentRelativeCalcTokens(classStrRaw) {
|
|
230
|
+
return classStrRaw.split(/\s+/).filter((token) => token && parsePercentRelativeCalc(token) === null).join(" ");
|
|
231
|
+
}
|
|
44
232
|
function makeElement(isStaticChildren, type, props, key) {
|
|
45
233
|
return (isStaticChildren ? import_jsx_runtime.jsxs : import_jsx_runtime.jsx)(type, props, key);
|
|
46
234
|
}
|
|
47
|
-
function resolvedStyleFor(resolveStyle2, classStrRaw, userStyle, pressed) {
|
|
48
|
-
const
|
|
235
|
+
function resolvedStyleFor(resolveStyle2, classStrRaw, userStyle, pressed, layoutOverrides) {
|
|
236
|
+
const cleaned = stripPercentRelativeCalcTokens(substituteDynamicTokens(classStrRaw));
|
|
237
|
+
const resolved = resolveStyle2(cleaned, pressed);
|
|
238
|
+
if (layoutOverrides) {
|
|
239
|
+
Object.assign(resolved, layoutOverrides);
|
|
240
|
+
}
|
|
49
241
|
if (userStyle === void 0) {
|
|
50
242
|
return resolved;
|
|
51
243
|
}
|
|
@@ -76,6 +268,14 @@ function dynamicTokenKeySuffix(classStrRaw) {
|
|
|
76
268
|
const values = matches.map((m) => (0, import_dynamicTokens.getDynamicToken)(m.slice("var(--".length, -1)) ?? "");
|
|
77
269
|
return `:kb-dt-${values.join("|")}`;
|
|
78
270
|
}
|
|
271
|
+
function percentCalcKeySuffix(percentCalcs, measuredBasis) {
|
|
272
|
+
if (percentCalcs.length === 0) return "";
|
|
273
|
+
const values = percentCalcs.map((calc) => {
|
|
274
|
+
const basis = measuredBasis?.[calc.property];
|
|
275
|
+
return basis === void 0 ? "pending" : resolvePercentRelativeCalc(basis, calc);
|
|
276
|
+
});
|
|
277
|
+
return `:kb-pc-${values.join("|")}`;
|
|
278
|
+
}
|
|
79
279
|
function ReactiveElement({
|
|
80
280
|
hostType,
|
|
81
281
|
hostRest,
|
|
@@ -88,10 +288,33 @@ function ReactiveElement({
|
|
|
88
288
|
(0, import_react.useSyncExternalStore)(import_darkModeStore.subscribeGlobalDarkMode, import_darkModeStore.getGlobalDarkMode);
|
|
89
289
|
(0, import_react.useSyncExternalStore)(import_dynamicTokens.subscribeDynamicTokens, import_dynamicTokens.getDynamicTokensVersion);
|
|
90
290
|
const { width } = (0, import_react_native.useWindowDimensions)();
|
|
91
|
-
const
|
|
92
|
-
const
|
|
291
|
+
const [measuredBasis, setMeasuredBasis] = (0, import_react.useState)(null);
|
|
292
|
+
const measure = (0, import_react.useCallback)((e) => {
|
|
293
|
+
const { width: w, height: h } = e.nativeEvent.layout;
|
|
294
|
+
setMeasuredBasis((prev) => prev && prev.width === w && prev.height === h ? prev : { width: w, height: h });
|
|
295
|
+
}, []);
|
|
296
|
+
const percentCalcs = extractPercentRelativeCalcs(classStrRaw);
|
|
297
|
+
let layoutOverrides;
|
|
298
|
+
let hostRestWithLayout = hostRest;
|
|
299
|
+
if (percentCalcs.length > 0) {
|
|
300
|
+
layoutOverrides = {};
|
|
301
|
+
for (const calc of percentCalcs) {
|
|
302
|
+
const basis = measuredBasis?.[calc.property];
|
|
303
|
+
layoutOverrides[calc.property] = basis === void 0 ? "100%" : resolvePercentRelativeCalc(basis, calc);
|
|
304
|
+
}
|
|
305
|
+
const userOnLayout = hostRest.onLayout;
|
|
306
|
+
hostRestWithLayout = {
|
|
307
|
+
...hostRest,
|
|
308
|
+
onLayout: userOnLayout ? (e) => {
|
|
309
|
+
measure(e);
|
|
310
|
+
userOnLayout(e);
|
|
311
|
+
} : measure
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
const finalStyle = hostType === import_react_native.Pressable ? (state) => resolvedStyleFor(resolveStyle2, classStrRaw, userStyle, state.pressed, layoutOverrides) : resolvedStyleFor(resolveStyle2, classStrRaw, userStyle, false, layoutOverrides);
|
|
315
|
+
const suffix = darkModeKeySuffix(classStrRaw) + breakpointKeySuffix(classStrRaw, width) + dynamicTokenKeySuffix(classStrRaw) + percentCalcKeySuffix(percentCalcs, measuredBasis);
|
|
93
316
|
const finalKey = suffix ? `${elementKey ?? ""}${suffix}` : elementKey;
|
|
94
|
-
return makeElement(isStaticChildren, hostType, { ...
|
|
317
|
+
return makeElement(isStaticChildren, hostType, { ...hostRestWithLayout, style: finalStyle }, finalKey);
|
|
95
318
|
}
|
|
96
319
|
function processElement(resolveStyle2, type, rawProps, key, isStaticChildren) {
|
|
97
320
|
if (type === null || typeof type === "symbol" || !rawProps) {
|
|
@@ -101,7 +324,7 @@ function processElement(resolveStyle2, type, rawProps, key, isStaticChildren) {
|
|
|
101
324
|
if (typeof classStrRaw !== "string") {
|
|
102
325
|
return makeElement(isStaticChildren, type, rawProps, key);
|
|
103
326
|
}
|
|
104
|
-
if (DARK_MODIFIER_RE.test(classStrRaw) || BREAKPOINT_MODIFIER_RE.test(classStrRaw) || classStrRaw.includes("var(--")) {
|
|
327
|
+
if (DARK_MODIFIER_RE.test(classStrRaw) || BREAKPOINT_MODIFIER_RE.test(classStrRaw) || classStrRaw.includes("var(--") || PERCENT_RELATIVE_CALC_HINT_RE.test(classStrRaw)) {
|
|
105
328
|
return (0, import_jsx_runtime.jsx)(
|
|
106
329
|
ReactiveElement,
|
|
107
330
|
{ hostType: type, hostRest: rest, classStrRaw, userStyle, resolveStyle: resolveStyle2, elementKey: key, isStaticChildren },
|
|
@@ -1222,153 +1445,6 @@ function resolveUtilityNative(parsed, theme) {
|
|
|
1222
1445
|
return resolveFlex(parsed, false) ?? resolve(parsed, theme) ?? resolve2(parsed, theme) ?? resolve3(parsed, theme) ?? resolveColorNative(parsed, theme) ?? resolveLeadingTrackingNative(parsed) ?? resolveTypographyNative(parsed) ?? nativeShadowDeclarations(parsed);
|
|
1223
1446
|
}
|
|
1224
1447
|
|
|
1225
|
-
// src/jsEngine/calc.ts
|
|
1226
|
-
function reduceConstantMath(raw) {
|
|
1227
|
-
const trimmed = raw.trim();
|
|
1228
|
-
const calc = stripCall(trimmed, "calc");
|
|
1229
|
-
if (calc !== null) {
|
|
1230
|
-
return new Evaluator(calc).parseExprToEnd();
|
|
1231
|
-
}
|
|
1232
|
-
const clamp = stripCall(trimmed, "clamp");
|
|
1233
|
-
if (clamp !== null) {
|
|
1234
|
-
const args = splitTopLevelCommas(clamp);
|
|
1235
|
-
if (args.length !== 3) return null;
|
|
1236
|
-
const [min2, preferred, max2] = args.map((a) => new Evaluator(a).parseExprToEnd());
|
|
1237
|
-
if (min2 === null || preferred === null || max2 === null) return null;
|
|
1238
|
-
return Math.max(min2, Math.min(preferred, max2));
|
|
1239
|
-
}
|
|
1240
|
-
const min = stripCall(trimmed, "min");
|
|
1241
|
-
if (min !== null) {
|
|
1242
|
-
const values = splitTopLevelCommas(min).map((a) => new Evaluator(a).parseExprToEnd());
|
|
1243
|
-
return values.some((v) => v === null) ? null : Math.min(...values);
|
|
1244
|
-
}
|
|
1245
|
-
const max = stripCall(trimmed, "max");
|
|
1246
|
-
if (max !== null) {
|
|
1247
|
-
const values = splitTopLevelCommas(max).map((a) => new Evaluator(a).parseExprToEnd());
|
|
1248
|
-
return values.some((v) => v === null) ? null : Math.max(...values);
|
|
1249
|
-
}
|
|
1250
|
-
return null;
|
|
1251
|
-
}
|
|
1252
|
-
function stripCall(raw, name) {
|
|
1253
|
-
if (!raw.startsWith(name)) return null;
|
|
1254
|
-
const afterName = raw.slice(name.length).trimStart();
|
|
1255
|
-
if (!afterName.startsWith("(") || !afterName.endsWith(")")) return null;
|
|
1256
|
-
return afterName.slice(1, -1);
|
|
1257
|
-
}
|
|
1258
|
-
function splitTopLevelCommas(s) {
|
|
1259
|
-
const parts = [];
|
|
1260
|
-
let depth = 0;
|
|
1261
|
-
let start = 0;
|
|
1262
|
-
for (let i = 0; i < s.length; i++) {
|
|
1263
|
-
const ch = s[i];
|
|
1264
|
-
if (ch === "(") depth++;
|
|
1265
|
-
else if (ch === ")") depth--;
|
|
1266
|
-
else if (ch === "," && depth === 0) {
|
|
1267
|
-
parts.push(s.slice(start, i).trim());
|
|
1268
|
-
start = i + 1;
|
|
1269
|
-
}
|
|
1270
|
-
}
|
|
1271
|
-
parts.push(s.slice(start).trim());
|
|
1272
|
-
return parts;
|
|
1273
|
-
}
|
|
1274
|
-
var Evaluator = class {
|
|
1275
|
-
constructor(s) {
|
|
1276
|
-
this.pos = 0;
|
|
1277
|
-
this.s = s;
|
|
1278
|
-
}
|
|
1279
|
-
parseExprToEnd() {
|
|
1280
|
-
const value = this.expr();
|
|
1281
|
-
if (value === null) return null;
|
|
1282
|
-
this.skipWs();
|
|
1283
|
-
return this.pos === this.s.length ? value : null;
|
|
1284
|
-
}
|
|
1285
|
-
skipWs() {
|
|
1286
|
-
while (this.pos < this.s.length && /\s/.test(this.s[this.pos])) this.pos++;
|
|
1287
|
-
}
|
|
1288
|
-
peek() {
|
|
1289
|
-
this.skipWs();
|
|
1290
|
-
return this.s[this.pos];
|
|
1291
|
-
}
|
|
1292
|
-
expr() {
|
|
1293
|
-
let value = this.term();
|
|
1294
|
-
if (value === null) return null;
|
|
1295
|
-
for (; ; ) {
|
|
1296
|
-
const ch = this.peek();
|
|
1297
|
-
if (ch === "+") {
|
|
1298
|
-
this.pos++;
|
|
1299
|
-
const rhs = this.term();
|
|
1300
|
-
if (rhs === null) return null;
|
|
1301
|
-
value += rhs;
|
|
1302
|
-
} else if (ch === "-") {
|
|
1303
|
-
this.pos++;
|
|
1304
|
-
const rhs = this.term();
|
|
1305
|
-
if (rhs === null) return null;
|
|
1306
|
-
value -= rhs;
|
|
1307
|
-
} else {
|
|
1308
|
-
return value;
|
|
1309
|
-
}
|
|
1310
|
-
}
|
|
1311
|
-
}
|
|
1312
|
-
term() {
|
|
1313
|
-
let value = this.factor();
|
|
1314
|
-
if (value === null) return null;
|
|
1315
|
-
for (; ; ) {
|
|
1316
|
-
const ch = this.peek();
|
|
1317
|
-
if (ch === "*") {
|
|
1318
|
-
this.pos++;
|
|
1319
|
-
const rhs = this.factor();
|
|
1320
|
-
if (rhs === null) return null;
|
|
1321
|
-
value *= rhs;
|
|
1322
|
-
} else if (ch === "/") {
|
|
1323
|
-
this.pos++;
|
|
1324
|
-
const divisor = this.factor();
|
|
1325
|
-
if (divisor === null || divisor === 0) return null;
|
|
1326
|
-
value /= divisor;
|
|
1327
|
-
} else {
|
|
1328
|
-
return value;
|
|
1329
|
-
}
|
|
1330
|
-
}
|
|
1331
|
-
}
|
|
1332
|
-
factor() {
|
|
1333
|
-
const ch = this.peek();
|
|
1334
|
-
if (ch === void 0) return null;
|
|
1335
|
-
if (ch === "(") {
|
|
1336
|
-
this.pos++;
|
|
1337
|
-
const value = this.expr();
|
|
1338
|
-
if (value === null || this.peek() !== ")") return null;
|
|
1339
|
-
this.pos++;
|
|
1340
|
-
return value;
|
|
1341
|
-
}
|
|
1342
|
-
if (ch === "-") {
|
|
1343
|
-
this.pos++;
|
|
1344
|
-
const value = this.factor();
|
|
1345
|
-
return value === null ? null : -value;
|
|
1346
|
-
}
|
|
1347
|
-
return this.numberWithUnit();
|
|
1348
|
-
}
|
|
1349
|
-
numberWithUnit() {
|
|
1350
|
-
this.skipWs();
|
|
1351
|
-
const start = this.pos;
|
|
1352
|
-
while (this.pos < this.s.length && (/[0-9]/.test(this.s[this.pos]) || this.s[this.pos] === ".")) this.pos++;
|
|
1353
|
-
if (this.pos === start) return null;
|
|
1354
|
-
const n = Number(this.s.slice(start, this.pos));
|
|
1355
|
-
if (!Number.isFinite(n)) return null;
|
|
1356
|
-
const unitStart = this.pos;
|
|
1357
|
-
while (this.pos < this.s.length && /[a-zA-Z]/.test(this.s[this.pos])) this.pos++;
|
|
1358
|
-
const unit = this.s.slice(unitStart, this.pos);
|
|
1359
|
-
switch (unit) {
|
|
1360
|
-
case "":
|
|
1361
|
-
return n;
|
|
1362
|
-
case "px":
|
|
1363
|
-
return n;
|
|
1364
|
-
case "rem":
|
|
1365
|
-
return n * 16;
|
|
1366
|
-
default:
|
|
1367
|
-
return null;
|
|
1368
|
-
}
|
|
1369
|
-
}
|
|
1370
|
-
};
|
|
1371
|
-
|
|
1372
1448
|
// src/jsEngine/resolveStyle.ts
|
|
1373
1449
|
var RESPONSIVE_BREAKPOINTS = /* @__PURE__ */ new Set(["sm", "md", "lg", "xl", "2xl"]);
|
|
1374
1450
|
function nativeModifierState(modifier, theme, colorScheme, pressed, width) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kbach/react-native",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.20",
|
|
4
4
|
"description": "Kbach's utility-class styling engine for React Native — the same class names as @kbach/react, resolved to a StyleSheet-ready style object via a Kotlin/JNI TurboModule (native), the same WASM engine @kbach/react uses (Expo Web / react-native-web), or a pure-JS fallback engine (Expo Go). Ships its own native Android module — one npm install, no separate native package. Beta. Native is Android-only (no iOS bridge yet); works with the React Native CLI, an Expo dev client, AND Expo Go (a reduced-coverage pure-JS fallback, since Expo Go can't load any custom native module).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"css",
|