@number10/jsx-core 5.0.0
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/LICENSE +667 -0
- package/README.md +38 -0
- package/dist/animation/animated-signal.cjs +19 -0
- package/dist/animation/animated-signal.cjs.map +1 -0
- package/dist/animation/animated-signal.d.ts +35 -0
- package/dist/animation/animated-signal.d.ts.map +1 -0
- package/dist/animation/animated-signal.js +19 -0
- package/dist/animation/animated-signal.js.map +1 -0
- package/dist/animation/create-spring.cjs +80 -0
- package/dist/animation/create-spring.cjs.map +1 -0
- package/dist/animation/create-spring.d.ts +56 -0
- package/dist/animation/create-spring.d.ts.map +1 -0
- package/dist/animation/create-spring.js +80 -0
- package/dist/animation/create-spring.js.map +1 -0
- package/dist/animation/easing.cjs +76 -0
- package/dist/animation/easing.cjs.map +1 -0
- package/dist/animation/easing.d.ts +45 -0
- package/dist/animation/easing.d.ts.map +1 -0
- package/dist/animation/easing.js +76 -0
- package/dist/animation/easing.js.map +1 -0
- package/dist/animation/effect-definitions.cjs +441 -0
- package/dist/animation/effect-definitions.cjs.map +1 -0
- package/dist/animation/effect-definitions.d.ts +60 -0
- package/dist/animation/effect-definitions.d.ts.map +1 -0
- package/dist/animation/effect-definitions.js +441 -0
- package/dist/animation/effect-definitions.js.map +1 -0
- package/dist/animation/effect-engine.cjs +189 -0
- package/dist/animation/effect-engine.cjs.map +1 -0
- package/dist/animation/effect-engine.d.ts +70 -0
- package/dist/animation/effect-engine.d.ts.map +1 -0
- package/dist/animation/effect-engine.js +189 -0
- package/dist/animation/effect-engine.js.map +1 -0
- package/dist/animation/index.d.ts +24 -0
- package/dist/animation/index.d.ts.map +1 -0
- package/dist/animation/spring-physics.cjs +94 -0
- package/dist/animation/spring-physics.cjs.map +1 -0
- package/dist/animation/spring-physics.d.ts +145 -0
- package/dist/animation/spring-physics.d.ts.map +1 -0
- package/dist/animation/spring-physics.js +94 -0
- package/dist/animation/spring-physics.js.map +1 -0
- package/dist/animation/tween.cjs +67 -0
- package/dist/animation/tween.cjs.map +1 -0
- package/dist/animation/tween.d.ts +60 -0
- package/dist/animation/tween.d.ts.map +1 -0
- package/dist/animation/tween.js +67 -0
- package/dist/animation/tween.js.map +1 -0
- package/dist/animation/types.d.ts +31 -0
- package/dist/animation/types.d.ts.map +1 -0
- package/dist/animation/useSpring.cjs +152 -0
- package/dist/animation/useSpring.cjs.map +1 -0
- package/dist/animation/useSpring.d.ts +55 -0
- package/dist/animation/useSpring.d.ts.map +1 -0
- package/dist/animation/useSpring.js +149 -0
- package/dist/animation/useSpring.js.map +1 -0
- package/dist/animation/useTween.cjs +208 -0
- package/dist/animation/useTween.cjs.map +1 -0
- package/dist/animation/useTween.d.ts +116 -0
- package/dist/animation/useTween.d.ts.map +1 -0
- package/dist/animation/useTween.js +208 -0
- package/dist/animation/useTween.js.map +1 -0
- package/dist/border-geometry.cjs +447 -0
- package/dist/border-geometry.cjs.map +1 -0
- package/dist/border-geometry.d.ts +114 -0
- package/dist/border-geometry.d.ts.map +1 -0
- package/dist/border-geometry.js +447 -0
- package/dist/border-geometry.js.map +1 -0
- package/dist/colors/color-presets.cjs +236 -0
- package/dist/colors/color-presets.cjs.map +1 -0
- package/dist/colors/color-presets.d.ts +89 -0
- package/dist/colors/color-presets.d.ts.map +1 -0
- package/dist/colors/color-presets.js +236 -0
- package/dist/colors/color-presets.js.map +1 -0
- package/dist/colors/color-theme-helpers.cjs +32 -0
- package/dist/colors/color-theme-helpers.cjs.map +1 -0
- package/dist/colors/color-theme-helpers.d.ts +65 -0
- package/dist/colors/color-theme-helpers.d.ts.map +1 -0
- package/dist/colors/color-theme-helpers.js +32 -0
- package/dist/colors/color-theme-helpers.js.map +1 -0
- package/dist/colors/color-types.cjs +38 -0
- package/dist/colors/color-types.cjs.map +1 -0
- package/dist/colors/color-types.d.ts +112 -0
- package/dist/colors/color-types.d.ts.map +1 -0
- package/dist/colors/color-types.js +38 -0
- package/dist/colors/color-types.js.map +1 -0
- package/dist/colors/color-utils.cjs +197 -0
- package/dist/colors/color-utils.cjs.map +1 -0
- package/dist/colors/color-utils.d.ts +216 -0
- package/dist/colors/color-utils.d.ts.map +1 -0
- package/dist/colors/color-utils.js +197 -0
- package/dist/colors/color-utils.js.map +1 -0
- package/dist/colors/contrast-contracts.cjs +265 -0
- package/dist/colors/contrast-contracts.cjs.map +1 -0
- package/dist/colors/contrast-contracts.d.ts +289 -0
- package/dist/colors/contrast-contracts.d.ts.map +1 -0
- package/dist/colors/contrast-contracts.js +265 -0
- package/dist/colors/contrast-contracts.js.map +1 -0
- package/dist/colors/index.cjs +55 -0
- package/dist/colors/index.cjs.map +1 -0
- package/dist/colors/index.d.ts +16 -0
- package/dist/colors/index.d.ts.map +1 -0
- package/dist/colors/index.js +55 -0
- package/dist/colors/index.js.map +1 -0
- package/dist/core-props.cjs +66 -0
- package/dist/core-props.cjs.map +1 -0
- package/dist/core-props.d.ts +395 -0
- package/dist/core-props.d.ts.map +1 -0
- package/dist/core-props.js +66 -0
- package/dist/core-props.js.map +1 -0
- package/dist/design-tokens/design-token-presets.cjs +91 -0
- package/dist/design-tokens/design-token-presets.cjs.map +1 -0
- package/dist/design-tokens/design-token-presets.d.ts +34 -0
- package/dist/design-tokens/design-token-presets.d.ts.map +1 -0
- package/dist/design-tokens/design-token-presets.js +91 -0
- package/dist/design-tokens/design-token-presets.js.map +1 -0
- package/dist/design-tokens/design-token-types.d.ts +97 -0
- package/dist/design-tokens/design-token-types.d.ts.map +1 -0
- package/dist/design-tokens/index.cjs +10 -0
- package/dist/design-tokens/index.cjs.map +1 -0
- package/dist/design-tokens/index.d.ts +9 -0
- package/dist/design-tokens/index.d.ts.map +1 -0
- package/dist/design-tokens/index.js +10 -0
- package/dist/design-tokens/index.js.map +1 -0
- package/dist/dev-config.cjs +296 -0
- package/dist/dev-config.cjs.map +1 -0
- package/dist/dev-config.d.ts +238 -0
- package/dist/dev-config.d.ts.map +1 -0
- package/dist/dev-config.js +296 -0
- package/dist/dev-config.js.map +1 -0
- package/dist/effects.cjs +69 -0
- package/dist/effects.cjs.map +1 -0
- package/dist/effects.d.ts +152 -0
- package/dist/effects.d.ts.map +1 -0
- package/dist/effects.js +69 -0
- package/dist/effects.js.map +1 -0
- package/dist/global-registry.cjs +25 -0
- package/dist/global-registry.cjs.map +1 -0
- package/dist/global-registry.d.ts +19 -0
- package/dist/global-registry.d.ts.map +1 -0
- package/dist/global-registry.js +25 -0
- package/dist/global-registry.js.map +1 -0
- package/dist/hooks.cjs +378 -0
- package/dist/hooks.cjs.map +1 -0
- package/dist/hooks.d.ts +322 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +378 -0
- package/dist/hooks.js.map +1 -0
- package/dist/host-adapter.d.ts +414 -0
- package/dist/host-adapter.d.ts.map +1 -0
- package/dist/index.cjs +229 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +226 -0
- package/dist/index.js.map +1 -0
- package/dist/jsx-dev-runtime.cjs +10 -0
- package/dist/jsx-dev-runtime.cjs.map +1 -0
- package/dist/jsx-dev-runtime.d.ts +5 -0
- package/dist/jsx-dev-runtime.d.ts.map +1 -0
- package/dist/jsx-dev-runtime.js +11 -0
- package/dist/jsx-dev-runtime.js.map +1 -0
- package/dist/jsx-runtime.cjs +44 -0
- package/dist/jsx-runtime.cjs.map +1 -0
- package/dist/jsx-runtime.d.ts +24 -0
- package/dist/jsx-runtime.d.ts.map +1 -0
- package/dist/jsx-runtime.js +44 -0
- package/dist/jsx-runtime.js.map +1 -0
- package/dist/jsx-types.d.ts +25 -0
- package/dist/jsx-types.d.ts.map +1 -0
- package/dist/layout/appliers/container-applier.cjs +20 -0
- package/dist/layout/appliers/container-applier.cjs.map +1 -0
- package/dist/layout/appliers/container-applier.d.ts +9 -0
- package/dist/layout/appliers/container-applier.d.ts.map +1 -0
- package/dist/layout/appliers/container-applier.js +20 -0
- package/dist/layout/appliers/container-applier.js.map +1 -0
- package/dist/layout/appliers/position-applier.cjs +31 -0
- package/dist/layout/appliers/position-applier.cjs.map +1 -0
- package/dist/layout/appliers/position-applier.d.ts +8 -0
- package/dist/layout/appliers/position-applier.d.ts.map +1 -0
- package/dist/layout/appliers/position-applier.js +31 -0
- package/dist/layout/appliers/position-applier.js.map +1 -0
- package/dist/layout/layout-engine-test-utils.d.ts +26 -0
- package/dist/layout/layout-engine-test-utils.d.ts.map +1 -0
- package/dist/layout/layout-engine.cjs +628 -0
- package/dist/layout/layout-engine.cjs.map +1 -0
- package/dist/layout/layout-engine.d.ts +140 -0
- package/dist/layout/layout-engine.d.ts.map +1 -0
- package/dist/layout/layout-engine.js +628 -0
- package/dist/layout/layout-engine.js.map +1 -0
- package/dist/layout/strategies/base-strategy.cjs +31 -0
- package/dist/layout/strategies/base-strategy.cjs.map +1 -0
- package/dist/layout/strategies/base-strategy.d.ts +59 -0
- package/dist/layout/strategies/base-strategy.d.ts.map +1 -0
- package/dist/layout/strategies/base-strategy.js +31 -0
- package/dist/layout/strategies/base-strategy.js.map +1 -0
- package/dist/layout/strategies/column-layout.cjs +145 -0
- package/dist/layout/strategies/column-layout.cjs.map +1 -0
- package/dist/layout/strategies/column-layout.d.ts +38 -0
- package/dist/layout/strategies/column-layout.d.ts.map +1 -0
- package/dist/layout/strategies/column-layout.js +145 -0
- package/dist/layout/strategies/column-layout.js.map +1 -0
- package/dist/layout/strategies/row-layout.cjs +145 -0
- package/dist/layout/strategies/row-layout.cjs.map +1 -0
- package/dist/layout/strategies/row-layout.d.ts +38 -0
- package/dist/layout/strategies/row-layout.d.ts.map +1 -0
- package/dist/layout/strategies/row-layout.js +145 -0
- package/dist/layout/strategies/row-layout.js.map +1 -0
- package/dist/layout/strategies/stack-layout.cjs +94 -0
- package/dist/layout/strategies/stack-layout.cjs.map +1 -0
- package/dist/layout/strategies/stack-layout.d.ts +30 -0
- package/dist/layout/strategies/stack-layout.d.ts.map +1 -0
- package/dist/layout/strategies/stack-layout.js +94 -0
- package/dist/layout/strategies/stack-layout.js.map +1 -0
- package/dist/layout/types.d.ts +134 -0
- package/dist/layout/types.d.ts.map +1 -0
- package/dist/layout/utils/child-utils.cjs +129 -0
- package/dist/layout/utils/child-utils.cjs.map +1 -0
- package/dist/layout/utils/child-utils.d.ts +54 -0
- package/dist/layout/utils/child-utils.d.ts.map +1 -0
- package/dist/layout/utils/child-utils.js +129 -0
- package/dist/layout/utils/child-utils.js.map +1 -0
- package/dist/layout/utils/dimension-calculator.cjs +109 -0
- package/dist/layout/utils/dimension-calculator.cjs.map +1 -0
- package/dist/layout/utils/dimension-calculator.d.ts +59 -0
- package/dist/layout/utils/dimension-calculator.d.ts.map +1 -0
- package/dist/layout/utils/dimension-calculator.js +109 -0
- package/dist/layout/utils/dimension-calculator.js.map +1 -0
- package/dist/layout/utils/flex-distributor.cjs +173 -0
- package/dist/layout/utils/flex-distributor.cjs.map +1 -0
- package/dist/layout/utils/flex-distributor.d.ts +18 -0
- package/dist/layout/utils/flex-distributor.d.ts.map +1 -0
- package/dist/layout/utils/flex-distributor.js +173 -0
- package/dist/layout/utils/flex-distributor.js.map +1 -0
- package/dist/layout/utils/size-resolver.cjs +280 -0
- package/dist/layout/utils/size-resolver.cjs.map +1 -0
- package/dist/layout/utils/size-resolver.d.ts +84 -0
- package/dist/layout/utils/size-resolver.d.ts.map +1 -0
- package/dist/layout/utils/size-resolver.js +280 -0
- package/dist/layout/utils/size-resolver.js.map +1 -0
- package/dist/layout/utils/spacing-calculator.cjs +50 -0
- package/dist/layout/utils/spacing-calculator.cjs.map +1 -0
- package/dist/layout/utils/spacing-calculator.d.ts +27 -0
- package/dist/layout/utils/spacing-calculator.d.ts.map +1 -0
- package/dist/layout/utils/spacing-calculator.js +50 -0
- package/dist/layout/utils/spacing-calculator.js.map +1 -0
- package/dist/memo.cjs +18 -0
- package/dist/memo.cjs.map +1 -0
- package/dist/memo.d.ts +29 -0
- package/dist/memo.d.ts.map +1 -0
- package/dist/memo.js +18 -0
- package/dist/memo.js.map +1 -0
- package/dist/nineslice-contract.cjs +60 -0
- package/dist/nineslice-contract.cjs.map +1 -0
- package/dist/nineslice-contract.d.ts +107 -0
- package/dist/nineslice-contract.d.ts.map +1 -0
- package/dist/nineslice-contract.js +60 -0
- package/dist/nineslice-contract.js.map +1 -0
- package/dist/placeholder.cjs +12 -0
- package/dist/placeholder.cjs.map +1 -0
- package/dist/placeholder.d.ts +44 -0
- package/dist/placeholder.d.ts.map +1 -0
- package/dist/placeholder.js +12 -0
- package/dist/placeholder.js.map +1 -0
- package/dist/portal.cjs +89 -0
- package/dist/portal.cjs.map +1 -0
- package/dist/portal.d.ts +62 -0
- package/dist/portal.d.ts.map +1 -0
- package/dist/portal.js +89 -0
- package/dist/portal.js.map +1 -0
- package/dist/primitive-contracts.cjs +12 -0
- package/dist/primitive-contracts.cjs.map +1 -0
- package/dist/primitive-contracts.d.ts +186 -0
- package/dist/primitive-contracts.d.ts.map +1 -0
- package/dist/primitive-contracts.js +12 -0
- package/dist/primitive-contracts.js.map +1 -0
- package/dist/theme.cjs +332 -0
- package/dist/theme.cjs.map +1 -0
- package/dist/theme.d.ts +204 -0
- package/dist/theme.d.ts.map +1 -0
- package/dist/theme.js +332 -0
- package/dist/theme.js.map +1 -0
- package/dist/types.d.ts +86 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/vdom/create-runtime.cjs +79 -0
- package/dist/vdom/create-runtime.cjs.map +1 -0
- package/dist/vdom/create-runtime.d.ts +7 -0
- package/dist/vdom/create-runtime.d.ts.map +1 -0
- package/dist/vdom/create-runtime.js +79 -0
- package/dist/vdom/create-runtime.js.map +1 -0
- package/dist/vdom/index.cjs +8 -0
- package/dist/vdom/index.cjs.map +1 -0
- package/dist/vdom/index.d.ts +4 -0
- package/dist/vdom/index.d.ts.map +1 -0
- package/dist/vdom/index.js +8 -0
- package/dist/vdom/index.js.map +1 -0
- package/dist/vdom/mount.cjs +161 -0
- package/dist/vdom/mount.cjs.map +1 -0
- package/dist/vdom/mount.d.ts +6 -0
- package/dist/vdom/mount.d.ts.map +1 -0
- package/dist/vdom/mount.js +161 -0
- package/dist/vdom/mount.js.map +1 -0
- package/dist/vdom/patch.cjs +163 -0
- package/dist/vdom/patch.cjs.map +1 -0
- package/dist/vdom/patch.d.ts +3 -0
- package/dist/vdom/patch.d.ts.map +1 -0
- package/dist/vdom/patch.js +163 -0
- package/dist/vdom/patch.js.map +1 -0
- package/dist/vdom/registry.cjs +85 -0
- package/dist/vdom/registry.cjs.map +1 -0
- package/dist/vdom/registry.d.ts +28 -0
- package/dist/vdom/registry.d.ts.map +1 -0
- package/dist/vdom/registry.js +85 -0
- package/dist/vdom/registry.js.map +1 -0
- package/dist/vdom/runtime-helpers.cjs +23 -0
- package/dist/vdom/runtime-helpers.cjs.map +1 -0
- package/dist/vdom/runtime-helpers.d.ts +8 -0
- package/dist/vdom/runtime-helpers.d.ts.map +1 -0
- package/dist/vdom/runtime-helpers.js +23 -0
- package/dist/vdom/runtime-helpers.js.map +1 -0
- package/dist/vdom/surface.cjs +107 -0
- package/dist/vdom/surface.cjs.map +1 -0
- package/dist/vdom/surface.d.ts +9 -0
- package/dist/vdom/surface.d.ts.map +1 -0
- package/dist/vdom/surface.js +107 -0
- package/dist/vdom/surface.js.map +1 -0
- package/dist/vdom/types.d.ts +104 -0
- package/dist/vdom/types.d.ts.map +1 -0
- package/dist/vdom/utils.cjs +146 -0
- package/dist/vdom/utils.cjs.map +1 -0
- package/dist/vdom/utils.d.ts +24 -0
- package/dist/vdom/utils.d.ts.map +1 -0
- package/dist/vdom/utils.js +146 -0
- package/dist/vdom/utils.js.map +1 -0
- package/dist/vdom.d.ts +4 -0
- package/dist/vdom.d.ts.map +1 -0
- package/dist/vector-draw-context.d.ts +63 -0
- package/dist/vector-draw-context.d.ts.map +1 -0
- package/package.json +161 -0
- package/vdom/index.cjs +1 -0
- package/vdom/index.d.ts +1 -0
- package/vdom/index.js +1 -0
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import { DebugLogger } from "../../dev-config.js";
|
|
2
|
+
const parseSizeCache = /* @__PURE__ */ new Map();
|
|
3
|
+
const warnedSizes = /* @__PURE__ */ new Set();
|
|
4
|
+
function parseCalcOperand(operand) {
|
|
5
|
+
const trimmed = operand.trim();
|
|
6
|
+
const percentMatch = trimmed.match(/^(\d+(?:\.\d+)?)%$/);
|
|
7
|
+
if (percentMatch && percentMatch[1]) {
|
|
8
|
+
return { type: "percent", value: parseFloat(percentMatch[1]) };
|
|
9
|
+
}
|
|
10
|
+
const vwMatch = trimmed.match(/^(\d+(?:\.\d+)?)vw$/);
|
|
11
|
+
if (vwMatch && vwMatch[1]) {
|
|
12
|
+
return { type: "vw", value: parseFloat(vwMatch[1]) };
|
|
13
|
+
}
|
|
14
|
+
const vhMatch = trimmed.match(/^(\d+(?:\.\d+)?)vh$/);
|
|
15
|
+
if (vhMatch && vhMatch[1]) {
|
|
16
|
+
return { type: "vh", value: parseFloat(vhMatch[1]) };
|
|
17
|
+
}
|
|
18
|
+
const pixelMatch = trimmed.match(/^(-?\d+(?:\.\d+)?)(?:px)?$/);
|
|
19
|
+
if (pixelMatch && pixelMatch[1]) {
|
|
20
|
+
return { type: "fixed", value: parseFloat(pixelMatch[1]) };
|
|
21
|
+
}
|
|
22
|
+
throw new Error(`[Size] Invalid calc operand: "${operand}"`);
|
|
23
|
+
}
|
|
24
|
+
function parseCalcExpression(expr) {
|
|
25
|
+
expr = expr.replace(/\s+/g, "");
|
|
26
|
+
function parseExpression(str) {
|
|
27
|
+
str = str.trim();
|
|
28
|
+
if (str.startsWith("(") && str.endsWith(")")) {
|
|
29
|
+
return parseExpression(str.slice(1, -1));
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
return parseCalcOperand(str);
|
|
33
|
+
} catch {
|
|
34
|
+
}
|
|
35
|
+
const operators = ["+", "-", "*", "/"];
|
|
36
|
+
let parenDepth = 0;
|
|
37
|
+
let lastOpIndex = -1;
|
|
38
|
+
let lastOp = "";
|
|
39
|
+
for (let i = str.length - 1; i >= 0; i--) {
|
|
40
|
+
const char = str.charAt(i);
|
|
41
|
+
if (char === ")") parenDepth++;
|
|
42
|
+
else if (char === "(") parenDepth--;
|
|
43
|
+
else if (parenDepth === 0 && operators.includes(char)) {
|
|
44
|
+
if (char === "*" || char === "/" || lastOp !== "*" && lastOp !== "/") {
|
|
45
|
+
lastOpIndex = i;
|
|
46
|
+
lastOp = char;
|
|
47
|
+
if (char === "+" || char === "-") break;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (lastOpIndex === -1) {
|
|
52
|
+
throw new Error(`[Size] No valid operator found in calc expression: "${str}"`);
|
|
53
|
+
}
|
|
54
|
+
const leftStr = str.slice(0, lastOpIndex);
|
|
55
|
+
const rightStr = str.slice(lastOpIndex + 1);
|
|
56
|
+
if (!leftStr || !rightStr) {
|
|
57
|
+
throw new Error(`[Size] Invalid calc expression: "${str}"`);
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
left: parseExpression(leftStr),
|
|
61
|
+
operator: lastOp,
|
|
62
|
+
right: parseExpression(rightStr)
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
return parseExpression(expr);
|
|
66
|
+
}
|
|
67
|
+
function parseSize(size) {
|
|
68
|
+
const cached = parseSizeCache.get(size);
|
|
69
|
+
if (cached !== void 0) {
|
|
70
|
+
return cached;
|
|
71
|
+
}
|
|
72
|
+
const result = parseSizeInternal(size);
|
|
73
|
+
parseSizeCache.set(size, result);
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
function parseSizeInternal(size) {
|
|
77
|
+
if (size === void 0) {
|
|
78
|
+
return { type: "auto" };
|
|
79
|
+
}
|
|
80
|
+
if (typeof size === "number") {
|
|
81
|
+
return { type: "fixed", value: size };
|
|
82
|
+
}
|
|
83
|
+
if (size === "auto") {
|
|
84
|
+
return { type: "auto" };
|
|
85
|
+
}
|
|
86
|
+
if (size === "fill") {
|
|
87
|
+
return { type: "fill" };
|
|
88
|
+
}
|
|
89
|
+
const calcMatch = size.match(/^calc\((.+)\)$/);
|
|
90
|
+
if (calcMatch && calcMatch[1]) {
|
|
91
|
+
return { type: "calc", calc: parseCalcExpression(calcMatch[1]) };
|
|
92
|
+
}
|
|
93
|
+
const percentMatch = size.match(/^(\d+(?:\.\d+)?)%$/);
|
|
94
|
+
if (percentMatch && percentMatch[1]) {
|
|
95
|
+
const value = parseFloat(percentMatch[1]);
|
|
96
|
+
if (value < 0 || value > 100) {
|
|
97
|
+
const warnKey = `percent:${value}`;
|
|
98
|
+
if (!warnedSizes.has(warnKey)) {
|
|
99
|
+
warnedSizes.add(warnKey);
|
|
100
|
+
DebugLogger.warn("Size", `Percentage value ${value}% is outside valid range (0-100%)`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return { type: "percent", value };
|
|
104
|
+
}
|
|
105
|
+
const vwMatch = size.match(/^(\d+(?:\.\d+)?)vw$/);
|
|
106
|
+
if (vwMatch && vwMatch[1]) {
|
|
107
|
+
return { type: "vw", value: parseFloat(vwMatch[1]) };
|
|
108
|
+
}
|
|
109
|
+
const vhMatch = size.match(/^(\d+(?:\.\d+)?)vh$/);
|
|
110
|
+
if (vhMatch && vhMatch[1]) {
|
|
111
|
+
return { type: "vh", value: parseFloat(vhMatch[1]) };
|
|
112
|
+
}
|
|
113
|
+
throw new Error(
|
|
114
|
+
`[Size] Invalid size format: "${size}". Supported formats: number, "X%", "XvW", "Xvh", "calc(...)", "auto", "fill", undefined`
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
function resolveCalcOperand(operand, parentSize, viewportSize) {
|
|
118
|
+
if ("type" in operand) {
|
|
119
|
+
if (operand.type === "fixed") {
|
|
120
|
+
return operand.value;
|
|
121
|
+
}
|
|
122
|
+
if (operand.type === "percent") {
|
|
123
|
+
if (parentSize === void 0) {
|
|
124
|
+
return 0;
|
|
125
|
+
}
|
|
126
|
+
return parentSize * operand.value / 100;
|
|
127
|
+
}
|
|
128
|
+
if (operand.type === "vw") {
|
|
129
|
+
const viewport = viewportSize || { width: 0 };
|
|
130
|
+
if (!viewport) {
|
|
131
|
+
DebugLogger.warn("Size", "Cannot resolve vw without viewport size. Using 0.");
|
|
132
|
+
return 0;
|
|
133
|
+
}
|
|
134
|
+
return viewport.width * operand.value / 100;
|
|
135
|
+
}
|
|
136
|
+
if (operand.type === "vh") {
|
|
137
|
+
const viewport = viewportSize || { height: 0 };
|
|
138
|
+
if (!viewport) {
|
|
139
|
+
DebugLogger.warn("Size", "Cannot resolve vh without viewport size. Using 0.");
|
|
140
|
+
return 0;
|
|
141
|
+
}
|
|
142
|
+
return viewport.height * operand.value / 100;
|
|
143
|
+
}
|
|
144
|
+
return 0;
|
|
145
|
+
} else {
|
|
146
|
+
return resolveCalcExpression(operand, parentSize, viewportSize);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
function resolveCalcExpression(calc, parentSize, viewportSize) {
|
|
150
|
+
const left = resolveCalcOperand(calc.left, parentSize, viewportSize);
|
|
151
|
+
const right = resolveCalcOperand(calc.right, parentSize, viewportSize);
|
|
152
|
+
switch (calc.operator) {
|
|
153
|
+
case "+":
|
|
154
|
+
return left + right;
|
|
155
|
+
case "-":
|
|
156
|
+
return left - right;
|
|
157
|
+
case "*":
|
|
158
|
+
return left * right;
|
|
159
|
+
case "/":
|
|
160
|
+
if (right === 0) {
|
|
161
|
+
DebugLogger.error("Size", "Division by zero in calc expression");
|
|
162
|
+
return 0;
|
|
163
|
+
}
|
|
164
|
+
return left / right;
|
|
165
|
+
default:
|
|
166
|
+
DebugLogger.error("Size", `Unknown calc operator: ${calc.operator}`);
|
|
167
|
+
return 0;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
function resolveSize(parsed, parentSize, contentSize, parentPadding, viewportSize) {
|
|
171
|
+
switch (parsed.type) {
|
|
172
|
+
case "fixed":
|
|
173
|
+
return parsed.value ?? 100;
|
|
174
|
+
case "percent":
|
|
175
|
+
if (parentSize === void 0) {
|
|
176
|
+
if (contentSize === void 0) {
|
|
177
|
+
DebugLogger.warn(
|
|
178
|
+
"Size",
|
|
179
|
+
"Cannot resolve percentage without parent size and no content fallback."
|
|
180
|
+
);
|
|
181
|
+
return 100;
|
|
182
|
+
}
|
|
183
|
+
return contentSize;
|
|
184
|
+
}
|
|
185
|
+
return parentSize * (parsed.value ?? 0) / 100;
|
|
186
|
+
case "vw": {
|
|
187
|
+
const viewport = viewportSize || { width: 0 };
|
|
188
|
+
if (!viewport) {
|
|
189
|
+
DebugLogger.warn("Size", "Cannot resolve vw without viewport size. Using fallback 100px");
|
|
190
|
+
return 100;
|
|
191
|
+
}
|
|
192
|
+
return viewport.width * (parsed.value ?? 0) / 100;
|
|
193
|
+
}
|
|
194
|
+
case "vh": {
|
|
195
|
+
const viewport = viewportSize || { height: 0 };
|
|
196
|
+
if (!viewport) {
|
|
197
|
+
DebugLogger.warn("Size", "Cannot resolve vh without viewport size. Using fallback 100px");
|
|
198
|
+
return 100;
|
|
199
|
+
}
|
|
200
|
+
return viewport.height * (parsed.value ?? 0) / 100;
|
|
201
|
+
}
|
|
202
|
+
case "calc":
|
|
203
|
+
if (!parsed.calc) {
|
|
204
|
+
DebugLogger.error("Size", "Calc type without calc expression");
|
|
205
|
+
return 100;
|
|
206
|
+
}
|
|
207
|
+
return resolveCalcExpression(parsed.calc, parentSize, viewportSize);
|
|
208
|
+
case "auto":
|
|
209
|
+
if (contentSize === void 0) {
|
|
210
|
+
DebugLogger.warn("Size", "Auto size without content size, using fallback 100px");
|
|
211
|
+
return 100;
|
|
212
|
+
}
|
|
213
|
+
return contentSize;
|
|
214
|
+
case "fill": {
|
|
215
|
+
if (parentSize === void 0) {
|
|
216
|
+
return 0;
|
|
217
|
+
}
|
|
218
|
+
if (parentPadding !== void 0 && parentPadding > 0) {
|
|
219
|
+
return Math.max(0, parentSize - parentPadding);
|
|
220
|
+
}
|
|
221
|
+
return parentSize;
|
|
222
|
+
}
|
|
223
|
+
default:
|
|
224
|
+
DebugLogger.error("Size", `Unknown size type: ${parsed.type}`);
|
|
225
|
+
return 100;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
function clearSizeCaches() {
|
|
229
|
+
parseSizeCache.clear();
|
|
230
|
+
warnedSizes.clear();
|
|
231
|
+
}
|
|
232
|
+
function calcRequiresParent(calc) {
|
|
233
|
+
const checkOperand = (op) => {
|
|
234
|
+
if ("type" in op) {
|
|
235
|
+
return op.type === "percent";
|
|
236
|
+
} else {
|
|
237
|
+
return calcRequiresParent(op);
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
return checkOperand(calc.left) || checkOperand(calc.right);
|
|
241
|
+
}
|
|
242
|
+
function requiresParent(parsed) {
|
|
243
|
+
if (parsed.type === "percent" || parsed.type === "fill") {
|
|
244
|
+
return true;
|
|
245
|
+
}
|
|
246
|
+
if (parsed.type === "calc" && parsed.calc) {
|
|
247
|
+
return calcRequiresParent(parsed.calc);
|
|
248
|
+
}
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
251
|
+
function isExplicit(parsed) {
|
|
252
|
+
return parsed.type === "fixed" || parsed.type === "percent" || parsed.type === "vw" || parsed.type === "vh" || parsed.type === "calc" || parsed.type === "fill";
|
|
253
|
+
}
|
|
254
|
+
function clampSize(size, minSize, maxSize, parentSize, fallbackSize, parentPadding) {
|
|
255
|
+
let clamped = size;
|
|
256
|
+
if (minSize !== void 0) {
|
|
257
|
+
const parsedMin = parseSize(minSize);
|
|
258
|
+
const resolvedMin = resolveSize(parsedMin, parentSize, fallbackSize, parentPadding);
|
|
259
|
+
if (clamped < resolvedMin) {
|
|
260
|
+
clamped = resolvedMin;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
if (maxSize !== void 0) {
|
|
264
|
+
const parsedMax = parseSize(maxSize);
|
|
265
|
+
const resolvedMax = resolveSize(parsedMax, parentSize, fallbackSize, parentPadding);
|
|
266
|
+
if (clamped > resolvedMax) {
|
|
267
|
+
clamped = resolvedMax;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return clamped;
|
|
271
|
+
}
|
|
272
|
+
export {
|
|
273
|
+
clampSize,
|
|
274
|
+
clearSizeCaches,
|
|
275
|
+
isExplicit,
|
|
276
|
+
parseSize,
|
|
277
|
+
requiresParent,
|
|
278
|
+
resolveSize
|
|
279
|
+
};
|
|
280
|
+
//# sourceMappingURL=size-resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"size-resolver.js","sources":["../../../src/layout/utils/size-resolver.ts"],"sourcesContent":["/**\n * Size resolution utilities for handling different size value types.\n * Supports fixed pixels, percentages, viewport units (vw/vh), auto sizing, and calc() expressions.\n * Renderer-neutral — viewport dimensions are passed as parameters.\n */\nimport { DebugLogger } from '../../dev-config'\nimport type { CalcExpression, CalcOperand, ParsedSize } from '../types'\n\n// Re-export for convenience\nexport type { ParsedSize } from '../types'\n\n/**\n * Cache for parseSize results to avoid repeated string parsing\n * Key: original size value, Value: parsed size object\n */\nconst parseSizeCache = new Map<unknown, ParsedSize>()\n\n/**\n * Set of size values that already triggered a warning\n * Prevents console spam from repeated warnings for the same invalid value\n */\nconst warnedSizes = new Set<string>()\n\n/**\n * Parse a calc operand (e.g., \"50%\" or \"20px\" or \"100vw\")\n * @param operand - String operand from calc expression\n * @returns Parsed operand\n */\nfunction parseCalcOperand(operand: string): CalcOperand {\n const trimmed = operand.trim()\n\n // Percentage: \"50%\"\n const percentMatch = trimmed.match(/^(\\d+(?:\\.\\d+)?)%$/)\n if (percentMatch && percentMatch[1]) {\n return { type: 'percent', value: parseFloat(percentMatch[1]) }\n }\n\n // Viewport width: \"100vw\"\n const vwMatch = trimmed.match(/^(\\d+(?:\\.\\d+)?)vw$/)\n if (vwMatch && vwMatch[1]) {\n return { type: 'vw', value: parseFloat(vwMatch[1]) }\n }\n\n // Viewport height: \"100vh\"\n const vhMatch = trimmed.match(/^(\\d+(?:\\.\\d+)?)vh$/)\n if (vhMatch && vhMatch[1]) {\n return { type: 'vh', value: parseFloat(vhMatch[1]) }\n }\n\n // Fixed pixels: \"20px\" or \"20\"\n const pixelMatch = trimmed.match(/^(-?\\d+(?:\\.\\d+)?)(?:px)?$/)\n if (pixelMatch && pixelMatch[1]) {\n return { type: 'fixed', value: parseFloat(pixelMatch[1]) }\n }\n\n throw new Error(`[Size] Invalid calc operand: \"${operand}\"`)\n}\n\n/**\n * Parse a calc() expression\n * @param expr - Calc expression string without \"calc(\" prefix\n * @returns Parsed calc expression\n */\nfunction parseCalcExpression(expr: string): CalcExpression {\n // Remove spaces\n expr = expr.replace(/\\s+/g, '')\n\n // Simple recursive parser for calc expressions\n function parseExpression(str: string): CalcExpression | CalcOperand {\n str = str.trim()\n\n // Handle parentheses\n if (str.startsWith('(') && str.endsWith(')')) {\n return parseExpression(str.slice(1, -1))\n }\n\n // Check if it's just an operand\n try {\n return parseCalcOperand(str)\n } catch {\n // Not an operand, continue parsing\n }\n\n // Find operators, respecting precedence: * / before + -\n const operators = ['+', '-', '*', '/']\n let parenDepth = 0\n let lastOpIndex = -1\n let lastOp = ''\n\n for (let i = str.length - 1; i >= 0; i--) {\n const char = str.charAt(i)\n if (char === ')') parenDepth++\n else if (char === '(') parenDepth--\n else if (parenDepth === 0 && operators.includes(char)) {\n // Check precedence: prefer * / over + -\n if (char === '*' || char === '/' || (lastOp !== '*' && lastOp !== '/')) {\n lastOpIndex = i\n lastOp = char\n if (char === '+' || char === '-') break // Lowest precedence, stop here\n }\n }\n }\n\n if (lastOpIndex === -1) {\n throw new Error(`[Size] No valid operator found in calc expression: \"${str}\"`)\n }\n\n const leftStr = str.slice(0, lastOpIndex)\n const rightStr = str.slice(lastOpIndex + 1)\n\n if (!leftStr || !rightStr) {\n throw new Error(`[Size] Invalid calc expression: \"${str}\"`)\n }\n\n return {\n left: parseExpression(leftStr),\n operator: lastOp as '+' | '-' | '*' | '/',\n right: parseExpression(rightStr),\n }\n }\n\n return parseExpression(expr) as CalcExpression\n}\n\n/**\n * Parse a size value into its components\n * Results are cached to avoid repeated string parsing during layout calculations\n * @param size - Size value (number, string, or undefined)\n * @returns Parsed size information\n * @throws Error if string format is invalid\n *\n * @example\n * parseSize(100) // { type: 'fixed', value: 100 }\n * parseSize('50%') // { type: 'percent', value: 50 }\n * parseSize('calc(100% - 40px)') // { type: 'calc', calc: {...} }\n * parseSize(undefined) // { type: 'auto' }\n * parseSize('auto') // { type: 'auto' }\n */\nexport function parseSize(size: number | string | undefined): ParsedSize {\n // Debug: Track parseSize call frequency\n // console.log('parseSize called:', size)\n\n // Check cache first (huge performance win for repeated calls)\n const cached = parseSizeCache.get(size)\n if (cached !== undefined) {\n return cached\n }\n\n // Parse the size value\n const result = parseSizeInternal(size)\n\n // Cache the result for future calls\n parseSizeCache.set(size, result)\n\n return result\n}\n\n/**\n * Internal parsing logic for size values\n * Separated to allow caching in parseSize()\n * @param size - Size value to parse\n * @returns Parsed size information\n */\nfunction parseSizeInternal(size: number | string | undefined): ParsedSize {\n // undefined -> auto (dynamic based on content)\n if (size === undefined) {\n return { type: 'auto' }\n }\n\n // number -> fixed pixel value\n if (typeof size === 'number') {\n return { type: 'fixed', value: size }\n }\n\n // string -> parse format\n if (size === 'auto') {\n return { type: 'auto' }\n }\n\n if (size === 'fill') {\n return { type: 'fill' }\n }\n\n // Calc expression: \"calc(100% - 40px)\"\n const calcMatch = size.match(/^calc\\((.+)\\)$/)\n if (calcMatch && calcMatch[1]) {\n return { type: 'calc', calc: parseCalcExpression(calcMatch[1]) }\n }\n\n // Percentage format: \"50%\", \"75.5%\", \"100%\"\n const percentMatch = size.match(/^(\\d+(?:\\.\\d+)?)%$/)\n if (percentMatch && percentMatch[1]) {\n const value = parseFloat(percentMatch[1])\n if (value < 0 || value > 100) {\n // Only warn once per unique invalid value to prevent console spam\n const warnKey = `percent:${value}`\n if (!warnedSizes.has(warnKey)) {\n warnedSizes.add(warnKey)\n DebugLogger.warn('Size', `Percentage value ${value}% is outside valid range (0-100%)`)\n }\n }\n return { type: 'percent', value }\n }\n\n // Viewport width: \"100vw\", \"50vw\"\n const vwMatch = size.match(/^(\\d+(?:\\.\\d+)?)vw$/)\n if (vwMatch && vwMatch[1]) {\n return { type: 'vw', value: parseFloat(vwMatch[1]) }\n }\n\n // Viewport height: \"100vh\", \"50vh\"\n const vhMatch = size.match(/^(\\d+(?:\\.\\d+)?)vh$/)\n if (vhMatch && vhMatch[1]) {\n return { type: 'vh', value: parseFloat(vhMatch[1]) }\n }\n\n // Unknown format\n throw new Error(\n `[Size] Invalid size format: \"${size}\". Supported formats: number, \"X%\", \"XvW\", \"Xvh\", \"calc(...)\", \"auto\", \"fill\", undefined`\n )\n}\n\n/**\n * Resolve a calc operand to pixel value\n * @param operand - Calc operand or sub-expression\n * @param parentSize - Parent dimension for percentage resolution\n * @param viewportSize - Viewport dimensions for vw/vh resolution\n * @returns Resolved pixel value\n */\nfunction resolveCalcOperand(\n operand: CalcOperand | CalcExpression,\n parentSize?: number,\n viewportSize?: { width: number; height: number }\n): number {\n if ('type' in operand) {\n // It's a CalcOperand\n if (operand.type === 'fixed') {\n return operand.value\n }\n\n // Percentage\n if (operand.type === 'percent') {\n if (parentSize === undefined) {\n return 0\n }\n return (parentSize * operand.value) / 100\n }\n\n // Viewport width\n if (operand.type === 'vw') {\n const viewport = viewportSize || { width: 0, height: 0 }\n if (!viewport) {\n DebugLogger.warn('Size', 'Cannot resolve vw without viewport size. Using 0.')\n return 0\n }\n return (viewport.width * operand.value) / 100\n }\n\n // Viewport height\n if (operand.type === 'vh') {\n const viewport = viewportSize || { width: 0, height: 0 }\n if (!viewport) {\n DebugLogger.warn('Size', 'Cannot resolve vh without viewport size. Using 0.')\n return 0\n }\n return (viewport.height * operand.value) / 100\n }\n\n return 0\n } else {\n // It's a CalcExpression\n return resolveCalcExpression(operand, parentSize, viewportSize)\n }\n}\n\n/**\n * Resolve a calc expression to pixel value\n * @param calc - Calc expression\n * @param parentSize - Parent dimension for percentage resolution\n * @param viewportSize - Viewport dimensions for vw/vh resolution\n * @returns Resolved pixel value\n */\nfunction resolveCalcExpression(\n calc: CalcExpression,\n parentSize?: number,\n viewportSize?: { width: number; height: number }\n): number {\n const left = resolveCalcOperand(calc.left, parentSize, viewportSize)\n const right = resolveCalcOperand(calc.right, parentSize, viewportSize)\n\n switch (calc.operator) {\n case '+':\n return left + right\n case '-':\n return left - right\n case '*':\n return left * right\n case '/':\n if (right === 0) {\n DebugLogger.error('Size', 'Division by zero in calc expression')\n return 0\n }\n return left / right\n default:\n DebugLogger.error('Size', `Unknown calc operator: ${calc.operator}`)\n return 0\n }\n}\n\n/**\n * Resolve a parsed size to actual pixel value\n * @param parsed - Parsed size information\n * @param parentSize - Parent dimension in pixels (required for percentage and calc)\n * @param contentSize - Content dimension in pixels (fallback for auto)\n * @param parentPadding - Parent padding in the relevant direction (for fill)\n * @param viewportSize - Viewport dimensions for vw/vh resolution\n * @returns Resolved size in pixels\n *\n * @example\n * resolveSize({ type: 'fixed', value: 100 }, 200) // 100\n * resolveSize({ type: 'percent', value: 50 }, 200) // 100 (50% of 200)\n * resolveSize({ type: 'vw', value: 100 }, undefined, undefined, undefined, viewport) // viewport.width\n * resolveSize({ type: 'vh', value: 50 }, undefined, undefined, undefined, viewport) // viewport.height * 0.5\n * resolveSize({ type: 'calc', calc: {...} }, 200) // calc result\n * resolveSize({ type: 'auto' }, 200, 150) // 150 (content size)\n * resolveSize({ type: 'fill' }, 200, undefined, 40) // 160 (200 - 40)\n */\nexport function resolveSize(\n parsed: ParsedSize,\n parentSize?: number,\n contentSize?: number,\n parentPadding?: number,\n viewportSize?: { width: number; height: number }\n): number {\n switch (parsed.type) {\n case 'fixed':\n return parsed.value ?? 100\n\n case 'percent':\n if (parentSize === undefined) {\n // Only warn if we also don't have a fallback content size\n if (contentSize === undefined) {\n DebugLogger.warn(\n 'Size',\n 'Cannot resolve percentage without parent size and no content fallback.'\n )\n return 100\n }\n // Parent size will be available in next layout pass - use content size for now\n return contentSize\n }\n return (parentSize * (parsed.value ?? 0)) / 100\n\n case 'vw': {\n const viewport = viewportSize || { width: 0, height: 0 }\n if (!viewport) {\n DebugLogger.warn('Size', 'Cannot resolve vw without viewport size. Using fallback 100px')\n return 100\n }\n return (viewport.width * (parsed.value ?? 0)) / 100\n }\n\n case 'vh': {\n const viewport = viewportSize || { width: 0, height: 0 }\n if (!viewport) {\n DebugLogger.warn('Size', 'Cannot resolve vh without viewport size. Using fallback 100px')\n return 100\n }\n return (viewport.height * (parsed.value ?? 0)) / 100\n }\n\n case 'calc':\n if (!parsed.calc) {\n DebugLogger.error('Size', 'Calc type without calc expression')\n return 100\n }\n return resolveCalcExpression(parsed.calc, parentSize, viewportSize)\n\n case 'auto':\n if (contentSize === undefined) {\n DebugLogger.warn('Size', 'Auto size without content size, using fallback 100px')\n return 100\n }\n return contentSize\n\n case 'fill': {\n if (parentSize === undefined) {\n // this would be possible at startup before parent sizes are known, therefore just return 0\n // DebugLogger.warn('Size', 'Fill size without parent size, using fallback 0px')\n return 0\n }\n // Fill = parent size minus padding (content-area)\n if (parentPadding !== undefined && parentPadding > 0) {\n return Math.max(0, parentSize - parentPadding)\n }\n // No padding or already content-area\n return parentSize\n }\n\n default:\n // Should never happen with proper typing\n DebugLogger.error('Size', `Unknown size type: ${(parsed as ParsedSize).type}`)\n return 100\n }\n}\n\n/**\n * Clear the parseSize cache and warning deduplication set\n * Useful for testing or memory management in long-running applications\n *\n * @example\n * ```typescript\n * // Clear caches after major UI rebuild\n * clearSizeCaches()\n * ```\n */\nexport function clearSizeCaches(): void {\n parseSizeCache.clear()\n warnedSizes.clear()\n}\n\n/**\n * Check if a calc expression requires parent context\n * @param calc - Calc expression\n * @returns True if expression contains percentages\n */\nfunction calcRequiresParent(calc: CalcExpression): boolean {\n const checkOperand = (op: CalcOperand | CalcExpression): boolean => {\n if ('type' in op) {\n return op.type === 'percent'\n } else {\n return calcRequiresParent(op)\n }\n }\n return checkOperand(calc.left) || checkOperand(calc.right)\n}\n\n/**\n * Check if a size needs parent context to resolve\n * @param parsed - Parsed size information\n * @returns True if size requires parent dimension\n */\nexport function requiresParent(parsed: ParsedSize): boolean {\n if (parsed.type === 'percent' || parsed.type === 'fill') {\n return true\n }\n\n // Calc expressions might contain percentages\n if (parsed.type === 'calc' && parsed.calc) {\n return calcRequiresParent(parsed.calc)\n }\n\n return false\n}\n\n/**\n * Check if a size can be determined without content measurement\n * @param parsed - Parsed size information\n * @returns True if size is explicitly defined (not auto)\n */\nexport function isExplicit(parsed: ParsedSize): boolean {\n return (\n parsed.type === 'fixed' ||\n parsed.type === 'percent' ||\n parsed.type === 'vw' ||\n parsed.type === 'vh' ||\n parsed.type === 'calc' ||\n parsed.type === 'fill'\n )\n}\n\n/**\n * Clamp a size value to min/max constraints\n * Min/max constraints can be SizeValue (pixels, percentage, viewport units, calc)\n * They are resolved relative to the same parent/viewport context as the size itself\n *\n * @param size - Resolved size in pixels\n * @param minSize - Minimum size constraint (SizeValue or undefined = no constraint)\n * @param maxSize - Maximum size constraint (SizeValue or undefined = no constraint)\n * @param parentSize - Parent dimension for percentage resolution in constraints\n * @param fallbackSize - Fallback size for auto constraints (not typically used for min/max)\n * @param parentPadding - Parent padding for fill constraints (not typically used for min/max)\n * @returns Clamped size in pixels\n *\n * @example\n * clampSize(150, 100, 200) // 150 (within bounds)\n * clampSize(50, 100, 200) // 100 (clamped to min)\n * clampSize(300, 100, 200) // 200 (clamped to max)\n * clampSize(150, undefined, \"80%\", 1000) // 150 (max = 800px)\n * clampSize(1000, undefined, \"80%\", 1000) // 800 (clamped to 80% of parent)\n */\nexport function clampSize(\n size: number,\n minSize?: number | string,\n maxSize?: number | string,\n parentSize?: number,\n fallbackSize?: number,\n parentPadding?: number\n): number {\n let clamped = size\n\n // Resolve and apply minimum constraint\n if (minSize !== undefined) {\n const parsedMin = parseSize(minSize)\n const resolvedMin = resolveSize(parsedMin, parentSize, fallbackSize, parentPadding)\n if (clamped < resolvedMin) {\n clamped = resolvedMin\n }\n }\n\n // Resolve and apply maximum constraint\n if (maxSize !== undefined) {\n const parsedMax = parseSize(maxSize)\n const resolvedMax = resolveSize(parsedMax, parentSize, fallbackSize, parentPadding)\n if (clamped > resolvedMax) {\n clamped = resolvedMax\n }\n }\n\n return clamped\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
function calculateJustifyContent(justifyContent, remainingSpace, childCount) {
|
|
4
|
+
let mainStart;
|
|
5
|
+
let spaceBetween = 0;
|
|
6
|
+
switch (justifyContent) {
|
|
7
|
+
case "start":
|
|
8
|
+
mainStart = 0;
|
|
9
|
+
break;
|
|
10
|
+
case "center":
|
|
11
|
+
mainStart = Math.max(0, remainingSpace / 2);
|
|
12
|
+
break;
|
|
13
|
+
case "end":
|
|
14
|
+
mainStart = Math.max(0, remainingSpace);
|
|
15
|
+
break;
|
|
16
|
+
case "space-between":
|
|
17
|
+
mainStart = 0;
|
|
18
|
+
spaceBetween = childCount > 1 ? remainingSpace / (childCount - 1) : 0;
|
|
19
|
+
break;
|
|
20
|
+
case "space-around":
|
|
21
|
+
spaceBetween = childCount > 0 ? remainingSpace / childCount : 0;
|
|
22
|
+
mainStart = spaceBetween / 2;
|
|
23
|
+
break;
|
|
24
|
+
case "space-evenly":
|
|
25
|
+
spaceBetween = childCount > 0 ? remainingSpace / (childCount + 1) : 0;
|
|
26
|
+
mainStart = spaceBetween;
|
|
27
|
+
break;
|
|
28
|
+
default:
|
|
29
|
+
mainStart = 0;
|
|
30
|
+
break;
|
|
31
|
+
}
|
|
32
|
+
return { mainStart, spaceBetween };
|
|
33
|
+
}
|
|
34
|
+
function calculateAlignItems(alignItems, contentArea, childSize, marginStart, marginEnd) {
|
|
35
|
+
switch (alignItems) {
|
|
36
|
+
case "start":
|
|
37
|
+
return marginStart;
|
|
38
|
+
case "center":
|
|
39
|
+
return (contentArea - childSize) / 2;
|
|
40
|
+
case "end":
|
|
41
|
+
return contentArea - childSize - marginEnd;
|
|
42
|
+
case "stretch":
|
|
43
|
+
return marginStart;
|
|
44
|
+
default:
|
|
45
|
+
return marginStart;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
exports.calculateAlignItems = calculateAlignItems;
|
|
49
|
+
exports.calculateJustifyContent = calculateJustifyContent;
|
|
50
|
+
//# sourceMappingURL=spacing-calculator.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spacing-calculator.cjs","sources":["../../../src/layout/utils/spacing-calculator.ts"],"sourcesContent":["/**\n * Spacing and alignment calculation utilities\n * Handles justifyContent and alignItems positioning logic\n */\nimport type { LayoutProps } from '../../core-props'\n\n/**\n * Justify content calculation result\n */\nexport interface JustifyResult {\n mainStart: number\n spaceBetween: number\n}\n\n/**\n * Calculate main axis starting position and spacing between children\n * @param justifyContent - Justify content value\n * @param remainingSpace - Space remaining after children are placed\n * @param childCount - Number of children\n * @returns Main axis starting offset and spacing between children\n */\nexport function calculateJustifyContent(\n justifyContent: LayoutProps['justifyContent'],\n remainingSpace: number,\n childCount: number\n): JustifyResult {\n let mainStart: number\n let spaceBetween = 0\n\n switch (justifyContent) {\n case 'start':\n mainStart = 0\n break\n case 'center':\n mainStart = Math.max(0, remainingSpace / 2)\n break\n case 'end':\n mainStart = Math.max(0, remainingSpace)\n break\n case 'space-between':\n mainStart = 0\n spaceBetween = childCount > 1 ? remainingSpace / (childCount - 1) : 0\n break\n case 'space-around':\n spaceBetween = childCount > 0 ? remainingSpace / childCount : 0\n mainStart = spaceBetween / 2\n break\n case 'space-evenly':\n spaceBetween = childCount > 0 ? remainingSpace / (childCount + 1) : 0\n mainStart = spaceBetween\n break\n default:\n // 'start' is default\n mainStart = 0\n break\n }\n\n return { mainStart, spaceBetween }\n}\n\n/**\n * Calculate cross axis position for a child\n * @param alignItems - Align items value\n * @param contentArea - Available space on cross axis\n * @param childSize - Size of child on cross axis\n * @param marginStart - Margin at start of cross axis (top for row, left for column)\n * @param marginEnd - Margin at end of cross axis (bottom for row, right for column)\n * @returns Cross axis position\n */\nexport function calculateAlignItems(\n alignItems: LayoutProps['alignItems'],\n contentArea: number,\n childSize: number,\n marginStart: number,\n marginEnd: number\n): number {\n switch (alignItems) {\n case 'start':\n return marginStart\n case 'center':\n return (contentArea - childSize) / 2\n case 'end':\n return contentArea - childSize - marginEnd\n case 'stretch':\n // Stretch: position at start (size is stretched in layout engine)\n return marginStart\n default:\n return marginStart\n }\n}\n"],"names":[],"mappings":";;AAqBO,SAAS,wBACd,gBACA,gBACA,YACe;AACf,MAAI;AACJ,MAAI,eAAe;AAEnB,UAAQ,gBAAA;AAAA,IACN,KAAK;AACH,kBAAY;AACZ;AAAA,IACF,KAAK;AACH,kBAAY,KAAK,IAAI,GAAG,iBAAiB,CAAC;AAC1C;AAAA,IACF,KAAK;AACH,kBAAY,KAAK,IAAI,GAAG,cAAc;AACtC;AAAA,IACF,KAAK;AACH,kBAAY;AACZ,qBAAe,aAAa,IAAI,kBAAkB,aAAa,KAAK;AACpE;AAAA,IACF,KAAK;AACH,qBAAe,aAAa,IAAI,iBAAiB,aAAa;AAC9D,kBAAY,eAAe;AAC3B;AAAA,IACF,KAAK;AACH,qBAAe,aAAa,IAAI,kBAAkB,aAAa,KAAK;AACpE,kBAAY;AACZ;AAAA,IACF;AAEE,kBAAY;AACZ;AAAA,EAAA;AAGJ,SAAO,EAAE,WAAW,aAAA;AACtB;AAWO,SAAS,oBACd,YACA,aACA,WACA,aACA,WACQ;AACR,UAAQ,YAAA;AAAA,IACN,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,cAAQ,cAAc,aAAa;AAAA,IACrC,KAAK;AACH,aAAO,cAAc,YAAY;AAAA,IACnC,KAAK;AAEH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EAAA;AAEb;;;"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { LayoutProps } from '../../core-props';
|
|
2
|
+
/**
|
|
3
|
+
* Justify content calculation result
|
|
4
|
+
*/
|
|
5
|
+
export interface JustifyResult {
|
|
6
|
+
mainStart: number;
|
|
7
|
+
spaceBetween: number;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Calculate main axis starting position and spacing between children
|
|
11
|
+
* @param justifyContent - Justify content value
|
|
12
|
+
* @param remainingSpace - Space remaining after children are placed
|
|
13
|
+
* @param childCount - Number of children
|
|
14
|
+
* @returns Main axis starting offset and spacing between children
|
|
15
|
+
*/
|
|
16
|
+
export declare function calculateJustifyContent(justifyContent: LayoutProps['justifyContent'], remainingSpace: number, childCount: number): JustifyResult;
|
|
17
|
+
/**
|
|
18
|
+
* Calculate cross axis position for a child
|
|
19
|
+
* @param alignItems - Align items value
|
|
20
|
+
* @param contentArea - Available space on cross axis
|
|
21
|
+
* @param childSize - Size of child on cross axis
|
|
22
|
+
* @param marginStart - Margin at start of cross axis (top for row, left for column)
|
|
23
|
+
* @param marginEnd - Margin at end of cross axis (bottom for row, right for column)
|
|
24
|
+
* @returns Cross axis position
|
|
25
|
+
*/
|
|
26
|
+
export declare function calculateAlignItems(alignItems: LayoutProps['alignItems'], contentArea: number, childSize: number, marginStart: number, marginEnd: number): number;
|
|
27
|
+
//# sourceMappingURL=spacing-calculator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spacing-calculator.d.ts","sourceRoot":"","sources":["../../../src/layout/utils/spacing-calculator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAEnD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAA;IACjB,YAAY,EAAE,MAAM,CAAA;CACrB;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,cAAc,EAAE,WAAW,CAAC,gBAAgB,CAAC,EAC7C,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,MAAM,GACjB,aAAa,CAiCf;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,WAAW,CAAC,YAAY,CAAC,EACrC,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,GAChB,MAAM,CAcR"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
function calculateJustifyContent(justifyContent, remainingSpace, childCount) {
|
|
2
|
+
let mainStart;
|
|
3
|
+
let spaceBetween = 0;
|
|
4
|
+
switch (justifyContent) {
|
|
5
|
+
case "start":
|
|
6
|
+
mainStart = 0;
|
|
7
|
+
break;
|
|
8
|
+
case "center":
|
|
9
|
+
mainStart = Math.max(0, remainingSpace / 2);
|
|
10
|
+
break;
|
|
11
|
+
case "end":
|
|
12
|
+
mainStart = Math.max(0, remainingSpace);
|
|
13
|
+
break;
|
|
14
|
+
case "space-between":
|
|
15
|
+
mainStart = 0;
|
|
16
|
+
spaceBetween = childCount > 1 ? remainingSpace / (childCount - 1) : 0;
|
|
17
|
+
break;
|
|
18
|
+
case "space-around":
|
|
19
|
+
spaceBetween = childCount > 0 ? remainingSpace / childCount : 0;
|
|
20
|
+
mainStart = spaceBetween / 2;
|
|
21
|
+
break;
|
|
22
|
+
case "space-evenly":
|
|
23
|
+
spaceBetween = childCount > 0 ? remainingSpace / (childCount + 1) : 0;
|
|
24
|
+
mainStart = spaceBetween;
|
|
25
|
+
break;
|
|
26
|
+
default:
|
|
27
|
+
mainStart = 0;
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
return { mainStart, spaceBetween };
|
|
31
|
+
}
|
|
32
|
+
function calculateAlignItems(alignItems, contentArea, childSize, marginStart, marginEnd) {
|
|
33
|
+
switch (alignItems) {
|
|
34
|
+
case "start":
|
|
35
|
+
return marginStart;
|
|
36
|
+
case "center":
|
|
37
|
+
return (contentArea - childSize) / 2;
|
|
38
|
+
case "end":
|
|
39
|
+
return contentArea - childSize - marginEnd;
|
|
40
|
+
case "stretch":
|
|
41
|
+
return marginStart;
|
|
42
|
+
default:
|
|
43
|
+
return marginStart;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
export {
|
|
47
|
+
calculateAlignItems,
|
|
48
|
+
calculateJustifyContent
|
|
49
|
+
};
|
|
50
|
+
//# sourceMappingURL=spacing-calculator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spacing-calculator.js","sources":["../../../src/layout/utils/spacing-calculator.ts"],"sourcesContent":["/**\n * Spacing and alignment calculation utilities\n * Handles justifyContent and alignItems positioning logic\n */\nimport type { LayoutProps } from '../../core-props'\n\n/**\n * Justify content calculation result\n */\nexport interface JustifyResult {\n mainStart: number\n spaceBetween: number\n}\n\n/**\n * Calculate main axis starting position and spacing between children\n * @param justifyContent - Justify content value\n * @param remainingSpace - Space remaining after children are placed\n * @param childCount - Number of children\n * @returns Main axis starting offset and spacing between children\n */\nexport function calculateJustifyContent(\n justifyContent: LayoutProps['justifyContent'],\n remainingSpace: number,\n childCount: number\n): JustifyResult {\n let mainStart: number\n let spaceBetween = 0\n\n switch (justifyContent) {\n case 'start':\n mainStart = 0\n break\n case 'center':\n mainStart = Math.max(0, remainingSpace / 2)\n break\n case 'end':\n mainStart = Math.max(0, remainingSpace)\n break\n case 'space-between':\n mainStart = 0\n spaceBetween = childCount > 1 ? remainingSpace / (childCount - 1) : 0\n break\n case 'space-around':\n spaceBetween = childCount > 0 ? remainingSpace / childCount : 0\n mainStart = spaceBetween / 2\n break\n case 'space-evenly':\n spaceBetween = childCount > 0 ? remainingSpace / (childCount + 1) : 0\n mainStart = spaceBetween\n break\n default:\n // 'start' is default\n mainStart = 0\n break\n }\n\n return { mainStart, spaceBetween }\n}\n\n/**\n * Calculate cross axis position for a child\n * @param alignItems - Align items value\n * @param contentArea - Available space on cross axis\n * @param childSize - Size of child on cross axis\n * @param marginStart - Margin at start of cross axis (top for row, left for column)\n * @param marginEnd - Margin at end of cross axis (bottom for row, right for column)\n * @returns Cross axis position\n */\nexport function calculateAlignItems(\n alignItems: LayoutProps['alignItems'],\n contentArea: number,\n childSize: number,\n marginStart: number,\n marginEnd: number\n): number {\n switch (alignItems) {\n case 'start':\n return marginStart\n case 'center':\n return (contentArea - childSize) / 2\n case 'end':\n return contentArea - childSize - marginEnd\n case 'stretch':\n // Stretch: position at start (size is stretched in layout engine)\n return marginStart\n default:\n return marginStart\n }\n}\n"],"names":[],"mappings":"AAqBO,SAAS,wBACd,gBACA,gBACA,YACe;AACf,MAAI;AACJ,MAAI,eAAe;AAEnB,UAAQ,gBAAA;AAAA,IACN,KAAK;AACH,kBAAY;AACZ;AAAA,IACF,KAAK;AACH,kBAAY,KAAK,IAAI,GAAG,iBAAiB,CAAC;AAC1C;AAAA,IACF,KAAK;AACH,kBAAY,KAAK,IAAI,GAAG,cAAc;AACtC;AAAA,IACF,KAAK;AACH,kBAAY;AACZ,qBAAe,aAAa,IAAI,kBAAkB,aAAa,KAAK;AACpE;AAAA,IACF,KAAK;AACH,qBAAe,aAAa,IAAI,iBAAiB,aAAa;AAC9D,kBAAY,eAAe;AAC3B;AAAA,IACF,KAAK;AACH,qBAAe,aAAa,IAAI,kBAAkB,aAAa,KAAK;AACpE,kBAAY;AACZ;AAAA,IACF;AAEE,kBAAY;AACZ;AAAA,EAAA;AAGJ,SAAO,EAAE,WAAW,aAAA;AACtB;AAWO,SAAS,oBACd,YACA,aACA,WACA,aACA,WACQ;AACR,UAAQ,YAAA;AAAA,IACN,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,cAAQ,cAAc,aAAa;AAAA,IACrC,KAAK;AACH,aAAO,cAAc,YAAY;AAAA,IACnC,KAAK;AAEH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EAAA;AAEb;"}
|
package/dist/memo.cjs
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
function setMemoSafe(vnode, value) {
|
|
4
|
+
if (Object.isExtensible(vnode)) {
|
|
5
|
+
vnode.__memo = value;
|
|
6
|
+
return vnode;
|
|
7
|
+
}
|
|
8
|
+
return { ...vnode, __memo: value };
|
|
9
|
+
}
|
|
10
|
+
function noMemo(vnode) {
|
|
11
|
+
return setMemoSafe(vnode, false);
|
|
12
|
+
}
|
|
13
|
+
function memo(vnode) {
|
|
14
|
+
return setMemoSafe(vnode, true);
|
|
15
|
+
}
|
|
16
|
+
exports.memo = memo;
|
|
17
|
+
exports.noMemo = noMemo;
|
|
18
|
+
//# sourceMappingURL=memo.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memo.cjs","sources":["../src/memo.ts"],"sourcesContent":["/**\n * Component memoization utilities\n * Similar to React.memo() - prevents re-renders when props haven't changed\n */\nimport type { VNode } from './types'\n\n/**\n * Safely sets __memo on a VNode, handling frozen/sealed objects from bundlers\n * @param vnode - VNode to set __memo on\n * @param value - Memoization value\n * @returns Original VNode if extensible, or shallow copy with __memo\n */\nfunction setMemoSafe<T extends VNode>(vnode: T, value: boolean): T {\n if (Object.isExtensible(vnode)) {\n vnode.__memo = value\n return vnode\n }\n // VNode is frozen - create shallow copy\n return { ...vnode, __memo: value } as T\n}\n\n/**\n * Marks a component to skip memoization (always re-render on prop changes)\n * Use when component has side effects or needs to re-render every time\n *\n * @example\n * ```tsx\n * function AlwaysUpdate({ value }) {\n * console.log('Rendering with:', value)\n * return <Text text={value} />\n * }\n *\n * // Disable memoization\n * <AlwaysUpdate value={counter} __memo={false} />\n * ```\n *\n * @param vnode - VNode to mark\n * @returns Same VNode with memoization disabled (may be a copy if frozen)\n */\nexport function noMemo<T extends VNode>(vnode: T): T {\n return setMemoSafe(vnode, false)\n}\n\n/**\n * Explicitly enable memoization for a component (default behavior)\n * This is the default - you don't need to call this unless you want to be explicit\n *\n * @param vnode - VNode to mark\n * @returns Same VNode with memoization enabled (may be a copy if frozen)\n */\nexport function memo<T extends VNode>(vnode: T): T {\n return setMemoSafe(vnode, true)\n}\n"],"names":[],"mappings":";;AAYA,SAAS,YAA6B,OAAU,OAAmB;AACjE,MAAI,OAAO,aAAa,KAAK,GAAG;AAC9B,UAAM,SAAS;AACf,WAAO;AAAA,EACT;AAEA,SAAO,EAAE,GAAG,OAAO,QAAQ,MAAA;AAC7B;AAoBO,SAAS,OAAwB,OAAa;AACnD,SAAO,YAAY,OAAO,KAAK;AACjC;AASO,SAAS,KAAsB,OAAa;AACjD,SAAO,YAAY,OAAO,IAAI;AAChC;;;"}
|
package/dist/memo.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { VNode } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Marks a component to skip memoization (always re-render on prop changes)
|
|
4
|
+
* Use when component has side effects or needs to re-render every time
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```tsx
|
|
8
|
+
* function AlwaysUpdate({ value }) {
|
|
9
|
+
* console.log('Rendering with:', value)
|
|
10
|
+
* return <Text text={value} />
|
|
11
|
+
* }
|
|
12
|
+
*
|
|
13
|
+
* // Disable memoization
|
|
14
|
+
* <AlwaysUpdate value={counter} __memo={false} />
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* @param vnode - VNode to mark
|
|
18
|
+
* @returns Same VNode with memoization disabled (may be a copy if frozen)
|
|
19
|
+
*/
|
|
20
|
+
export declare function noMemo<T extends VNode>(vnode: T): T;
|
|
21
|
+
/**
|
|
22
|
+
* Explicitly enable memoization for a component (default behavior)
|
|
23
|
+
* This is the default - you don't need to call this unless you want to be explicit
|
|
24
|
+
*
|
|
25
|
+
* @param vnode - VNode to mark
|
|
26
|
+
* @returns Same VNode with memoization enabled (may be a copy if frozen)
|
|
27
|
+
*/
|
|
28
|
+
export declare function memo<T extends VNode>(vnode: T): T;
|
|
29
|
+
//# sourceMappingURL=memo.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memo.d.ts","sourceRoot":"","sources":["../src/memo.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAiBpC;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,MAAM,CAAC,CAAC,SAAS,KAAK,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CAEnD;AAED;;;;;;GAMG;AACH,wBAAgB,IAAI,CAAC,CAAC,SAAS,KAAK,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CAEjD"}
|
package/dist/memo.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
function setMemoSafe(vnode, value) {
|
|
2
|
+
if (Object.isExtensible(vnode)) {
|
|
3
|
+
vnode.__memo = value;
|
|
4
|
+
return vnode;
|
|
5
|
+
}
|
|
6
|
+
return { ...vnode, __memo: value };
|
|
7
|
+
}
|
|
8
|
+
function noMemo(vnode) {
|
|
9
|
+
return setMemoSafe(vnode, false);
|
|
10
|
+
}
|
|
11
|
+
function memo(vnode) {
|
|
12
|
+
return setMemoSafe(vnode, true);
|
|
13
|
+
}
|
|
14
|
+
export {
|
|
15
|
+
memo,
|
|
16
|
+
noMemo
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=memo.js.map
|
package/dist/memo.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memo.js","sources":["../src/memo.ts"],"sourcesContent":["/**\n * Component memoization utilities\n * Similar to React.memo() - prevents re-renders when props haven't changed\n */\nimport type { VNode } from './types'\n\n/**\n * Safely sets __memo on a VNode, handling frozen/sealed objects from bundlers\n * @param vnode - VNode to set __memo on\n * @param value - Memoization value\n * @returns Original VNode if extensible, or shallow copy with __memo\n */\nfunction setMemoSafe<T extends VNode>(vnode: T, value: boolean): T {\n if (Object.isExtensible(vnode)) {\n vnode.__memo = value\n return vnode\n }\n // VNode is frozen - create shallow copy\n return { ...vnode, __memo: value } as T\n}\n\n/**\n * Marks a component to skip memoization (always re-render on prop changes)\n * Use when component has side effects or needs to re-render every time\n *\n * @example\n * ```tsx\n * function AlwaysUpdate({ value }) {\n * console.log('Rendering with:', value)\n * return <Text text={value} />\n * }\n *\n * // Disable memoization\n * <AlwaysUpdate value={counter} __memo={false} />\n * ```\n *\n * @param vnode - VNode to mark\n * @returns Same VNode with memoization disabled (may be a copy if frozen)\n */\nexport function noMemo<T extends VNode>(vnode: T): T {\n return setMemoSafe(vnode, false)\n}\n\n/**\n * Explicitly enable memoization for a component (default behavior)\n * This is the default - you don't need to call this unless you want to be explicit\n *\n * @param vnode - VNode to mark\n * @returns Same VNode with memoization enabled (may be a copy if frozen)\n */\nexport function memo<T extends VNode>(vnode: T): T {\n return setMemoSafe(vnode, true)\n}\n"],"names":[],"mappings":"AAYA,SAAS,YAA6B,OAAU,OAAmB;AACjE,MAAI,OAAO,aAAa,KAAK,GAAG;AAC9B,UAAM,SAAS;AACf,WAAO;AAAA,EACT;AAEA,SAAO,EAAE,GAAG,OAAO,QAAQ,MAAA;AAC7B;AAoBO,SAAS,OAAwB,OAAa;AACnD,SAAO,YAAY,OAAO,KAAK;AACjC;AASO,SAAS,KAAsB,OAAa;AACjD,SAAO,YAAY,OAAO,IAAI;AAChC;"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
function computeSourceSlices(frameW, frameH, left, right, top, bottom) {
|
|
4
|
+
const centerW = Math.max(0, frameW - left - right);
|
|
5
|
+
const centerH = Math.max(0, frameH - top - bottom);
|
|
6
|
+
return [
|
|
7
|
+
{ x: 0, y: 0, w: left, h: top },
|
|
8
|
+
{ x: left, y: 0, w: centerW, h: top },
|
|
9
|
+
{ x: frameW - right, y: 0, w: right, h: top },
|
|
10
|
+
{ x: 0, y: top, w: left, h: centerH },
|
|
11
|
+
{ x: left, y: top, w: centerW, h: centerH },
|
|
12
|
+
{ x: frameW - right, y: top, w: right, h: centerH },
|
|
13
|
+
{ x: 0, y: frameH - bottom, w: left, h: bottom },
|
|
14
|
+
{ x: left, y: frameH - bottom, w: centerW, h: bottom },
|
|
15
|
+
{ x: frameW - right, y: frameH - bottom, w: right, h: bottom }
|
|
16
|
+
];
|
|
17
|
+
}
|
|
18
|
+
function computeTargetXs(x, width, leftWidth, rightWidth) {
|
|
19
|
+
return [x, x + leftWidth, x + width - rightWidth, x + width];
|
|
20
|
+
}
|
|
21
|
+
function computeTargetYs(y, height, topHeight, bottomHeight) {
|
|
22
|
+
return [y, y + topHeight, y + height - bottomHeight, y + height];
|
|
23
|
+
}
|
|
24
|
+
const SEGMENT_EDGE_MAP = [
|
|
25
|
+
[0, 1, 0, 1],
|
|
26
|
+
// TL
|
|
27
|
+
[1, 2, 0, 1],
|
|
28
|
+
// Top
|
|
29
|
+
[2, 3, 0, 1],
|
|
30
|
+
// TR
|
|
31
|
+
[0, 1, 1, 2],
|
|
32
|
+
// Left
|
|
33
|
+
[1, 2, 1, 2],
|
|
34
|
+
// Center
|
|
35
|
+
[2, 3, 1, 2],
|
|
36
|
+
// Right
|
|
37
|
+
[0, 1, 2, 3],
|
|
38
|
+
// BL
|
|
39
|
+
[1, 2, 2, 3],
|
|
40
|
+
// Bottom
|
|
41
|
+
[2, 3, 2, 3]
|
|
42
|
+
// BR
|
|
43
|
+
];
|
|
44
|
+
function deriveTargetRects(xs, ys) {
|
|
45
|
+
const rects = [];
|
|
46
|
+
for (const [x0, x1, y0, y1] of SEGMENT_EDGE_MAP) {
|
|
47
|
+
rects.push({
|
|
48
|
+
x: xs[x0] ?? 0,
|
|
49
|
+
y: ys[y0] ?? 0,
|
|
50
|
+
w: Math.max(0, (xs[x1] ?? 0) - (xs[x0] ?? 0)),
|
|
51
|
+
h: Math.max(0, (ys[y1] ?? 0) - (ys[y0] ?? 0))
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
return rects;
|
|
55
|
+
}
|
|
56
|
+
exports.computeSourceSlices = computeSourceSlices;
|
|
57
|
+
exports.computeTargetXs = computeTargetXs;
|
|
58
|
+
exports.computeTargetYs = computeTargetYs;
|
|
59
|
+
exports.deriveTargetRects = deriveTargetRects;
|
|
60
|
+
//# sourceMappingURL=nineslice-contract.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nineslice-contract.cjs","sources":["../src/nineslice-contract.ts"],"sourcesContent":["/**\n * Portable NineSlice primitive contract — renderer-neutral.\n *\n * Defines the props interface for the native `nineslice` host primitive.\n * When a renderer declares the `nineslice` capability, the portable\n * NineSlice component renders a single `<nineslice>` element instead\n * of multiple `<image>` fragments.\n *\n * The portable layer passes texture info and slice dimensions\n * (leftWidth, rightWidth, topHeight, bottomHeight). The renderer:\n *\n * - Computes the 9 source slice regions from the texture frame geometry\n * - Receives the resolved target width/height from the layout system\n * - Applies the effective device/content scale\n * - Snaps shared edges to the physical pixel grid (once per axis)\n * - Derives all 9 target rectangles from snapped edges\n * - Draws all segments as a single draw operation\n */\n\nimport type { SizeValue, TransformProps } from './core-props'\nimport type { PropsDefaultExtension } from './types'\n\n/** A rectangle in the source texture (texture-pixel coordinates) */\nexport interface SliceRect {\n readonly x: number\n readonly y: number\n readonly w: number\n readonly h: number\n}\n\n/**\n * Portable props for the native NineSlice primitive.\n *\n * The portable NineSlice component passes texture identity and slice\n * dimensions. The renderer resolves texture frame geometry, computes\n * the 9 source regions, and derives target-space edge arrays from the\n * resolved layout size — snapping once per axis to avoid sub-pixel seams.\n */\nexport interface NineSlicePrimitiveProps extends TransformProps {\n /** Texture key */\n texture: string\n /** Optional atlas frame name */\n frame?: string | undefined\n /** Optional tint colour */\n tint?: number | undefined\n /** Target display width (resolved by the layout system) */\n width: SizeValue\n /** Target display height (resolved by the layout system) */\n height: SizeValue\n /** Width of the left slice in source texture pixels */\n leftWidth: number\n /** Width of the right slice in source texture pixels */\n rightWidth: number\n /** Height of the top slice in source texture pixels (0 = 3-slice mode) */\n topHeight: number\n /** Height of the bottom slice in source texture pixels (0 = 3-slice mode) */\n bottomHeight: number\n /**\n * Whether image smoothing is enabled when scaling segments.\n * Default: false (prefer crisp rendering for UI textures).\n */\n imageSmoothingEnabled?: boolean | undefined\n /**\n * When true, the element is rendered but excluded from layout calculations.\n * Used for decorative background layers inside stack containers.\n */\n headless?: boolean | undefined\n}\n\n/**\n * Complete NineSlice props including JSX extension props (ref, key).\n */\nexport interface NineSlicePrimitivePropsComplete<TNode = unknown>\n extends NineSlicePrimitiveProps, PropsDefaultExtension<TNode> {}\n\n// ---------------------------------------------------------------------------\n// Slice computation helpers (portable, renderer-neutral)\n// ---------------------------------------------------------------------------\n\n/**\n * Compute the 9 source slice rectangles from a texture frame and slice widths.\n *\n * @param frameW - Source texture / frame width in pixels\n * @param frameH - Source texture / frame height in pixels\n * @param left - Left slice width\n * @param right - Right slice width\n * @param top - Top slice height (0 for 3-slice mode)\n * @param bottom - Bottom slice height (0 for 3-slice mode)\n * @returns 9-element tuple of source slice rects\n */\nexport function computeSourceSlices(\n frameW: number,\n frameH: number,\n left: number,\n right: number,\n top: number,\n bottom: number\n): readonly [\n SliceRect,\n SliceRect,\n SliceRect,\n SliceRect,\n SliceRect,\n SliceRect,\n SliceRect,\n SliceRect,\n SliceRect,\n] {\n const centerW = Math.max(0, frameW - left - right)\n const centerH = Math.max(0, frameH - top - bottom)\n\n return [\n { x: 0, y: 0, w: left, h: top },\n { x: left, y: 0, w: centerW, h: top },\n { x: frameW - right, y: 0, w: right, h: top },\n { x: 0, y: top, w: left, h: centerH },\n { x: left, y: top, w: centerW, h: centerH },\n { x: frameW - right, y: top, w: right, h: centerH },\n { x: 0, y: frameH - bottom, w: left, h: bottom },\n { x: left, y: frameH - bottom, w: centerW, h: bottom },\n { x: frameW - right, y: frameH - bottom, w: right, h: bottom },\n ]\n}\n\n/**\n * Compute 4 shared X edge positions for the target NineSlice.\n *\n * @param x - Left edge of the target area\n * @param width - Total target width\n * @param leftWidth - Left slice width (in target pixels)\n * @param rightWidth - Right slice width (in target pixels)\n * @returns [left, left+leftWidth, right-rightWidth, right]\n */\nexport function computeTargetXs(\n x: number,\n width: number,\n leftWidth: number,\n rightWidth: number\n): readonly [number, number, number, number] {\n return [x, x + leftWidth, x + width - rightWidth, x + width] as const\n}\n\n/**\n * Compute 4 shared Y edge positions for the target NineSlice.\n *\n * @param y - Top edge of the target area\n * @param height - Total target height\n * @param topHeight - Top slice height (in target pixels)\n * @param bottomHeight - Bottom slice height (in target pixels)\n * @returns [top, top+topHeight, bottom-bottomHeight, bottom]\n */\nexport function computeTargetYs(\n y: number,\n height: number,\n topHeight: number,\n bottomHeight: number\n): readonly [number, number, number, number] {\n return [y, y + topHeight, y + height - bottomHeight, y + height] as const\n}\n\n/**\n * Edge index pairs for segment target rectangles.\n * Each entry: [xsLeftIndex, xsRightIndex, ysTopIndex, ysBottomIndex]\n */\nconst SEGMENT_EDGE_MAP: readonly (readonly [number, number, number, number])[] = [\n [0, 1, 0, 1], // TL\n [1, 2, 0, 1], // Top\n [2, 3, 0, 1], // TR\n [0, 1, 1, 2], // Left\n [1, 2, 1, 2], // Center\n [2, 3, 1, 2], // Right\n [0, 1, 2, 3], // BL\n [1, 2, 2, 3], // Bottom\n [2, 3, 2, 3], // BR\n] as const\n\n/**\n * Derive all 9 target rectangles from shared edge arrays.\n *\n * Since adjacent segments share edges, computing target rects this way\n * guarantees zero overlap and zero gaps — provided the edge arrays have\n * been snapped to the physical pixel grid by the renderer backend.\n *\n * @param xs - 4 shared X edges (must be monotonically non-decreasing)\n * @param ys - 4 shared Y edges (must be monotonically non-decreasing)\n * @returns 9 target rectangles with {x, y, w, h}\n */\nexport function deriveTargetRects(\n xs: readonly [number, number, number, number],\n ys: readonly [number, number, number, number]\n): readonly SliceRect[] {\n const rects: SliceRect[] = []\n for (const [x0, x1, y0, y1] of SEGMENT_EDGE_MAP) {\n rects.push({\n x: xs[x0] ?? 0,\n y: ys[y0] ?? 0,\n w: Math.max(0, (xs[x1] ?? 0) - (xs[x0] ?? 0)),\n h: Math.max(0, (ys[y1] ?? 0) - (ys[y0] ?? 0)),\n })\n }\n return rects\n}\n"],"names":[],"mappings":";;AA0FO,SAAS,oBACd,QACA,QACA,MACA,OACA,KACA,QAWA;AACA,QAAM,UAAU,KAAK,IAAI,GAAG,SAAS,OAAO,KAAK;AACjD,QAAM,UAAU,KAAK,IAAI,GAAG,SAAS,MAAM,MAAM;AAEjD,SAAO;AAAA,IACL,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,MAAM,GAAG,IAAA;AAAA,IAC1B,EAAE,GAAG,MAAM,GAAG,GAAG,GAAG,SAAS,GAAG,IAAA;AAAA,IAChC,EAAE,GAAG,SAAS,OAAO,GAAG,GAAG,GAAG,OAAO,GAAG,IAAA;AAAA,IACxC,EAAE,GAAG,GAAG,GAAG,KAAK,GAAG,MAAM,GAAG,QAAA;AAAA,IAC5B,EAAE,GAAG,MAAM,GAAG,KAAK,GAAG,SAAS,GAAG,QAAA;AAAA,IAClC,EAAE,GAAG,SAAS,OAAO,GAAG,KAAK,GAAG,OAAO,GAAG,QAAA;AAAA,IAC1C,EAAE,GAAG,GAAG,GAAG,SAAS,QAAQ,GAAG,MAAM,GAAG,OAAA;AAAA,IACxC,EAAE,GAAG,MAAM,GAAG,SAAS,QAAQ,GAAG,SAAS,GAAG,OAAA;AAAA,IAC9C,EAAE,GAAG,SAAS,OAAO,GAAG,SAAS,QAAQ,GAAG,OAAO,GAAG,OAAA;AAAA,EAAO;AAEjE;AAWO,SAAS,gBACd,GACA,OACA,WACA,YAC2C;AAC3C,SAAO,CAAC,GAAG,IAAI,WAAW,IAAI,QAAQ,YAAY,IAAI,KAAK;AAC7D;AAWO,SAAS,gBACd,GACA,QACA,WACA,cAC2C;AAC3C,SAAO,CAAC,GAAG,IAAI,WAAW,IAAI,SAAS,cAAc,IAAI,MAAM;AACjE;AAMA,MAAM,mBAA2E;AAAA,EAC/E,CAAC,GAAG,GAAG,GAAG,CAAC;AAAA;AAAA,EACX,CAAC,GAAG,GAAG,GAAG,CAAC;AAAA;AAAA,EACX,CAAC,GAAG,GAAG,GAAG,CAAC;AAAA;AAAA,EACX,CAAC,GAAG,GAAG,GAAG,CAAC;AAAA;AAAA,EACX,CAAC,GAAG,GAAG,GAAG,CAAC;AAAA;AAAA,EACX,CAAC,GAAG,GAAG,GAAG,CAAC;AAAA;AAAA,EACX,CAAC,GAAG,GAAG,GAAG,CAAC;AAAA;AAAA,EACX,CAAC,GAAG,GAAG,GAAG,CAAC;AAAA;AAAA,EACX,CAAC,GAAG,GAAG,GAAG,CAAC;AAAA;AACb;AAaO,SAAS,kBACd,IACA,IACsB;AACtB,QAAM,QAAqB,CAAA;AAC3B,aAAW,CAAC,IAAI,IAAI,IAAI,EAAE,KAAK,kBAAkB;AAC/C,UAAM,KAAK;AAAA,MACT,GAAG,GAAG,EAAE,KAAK;AAAA,MACb,GAAG,GAAG,EAAE,KAAK;AAAA,MACb,GAAG,KAAK,IAAI,IAAI,GAAG,EAAE,KAAK,MAAM,GAAG,EAAE,KAAK,EAAE;AAAA,MAC5C,GAAG,KAAK,IAAI,IAAI,GAAG,EAAE,KAAK,MAAM,GAAG,EAAE,KAAK,EAAE;AAAA,IAAA,CAC7C;AAAA,EACH;AACA,SAAO;AACT;;;;;"}
|