@energy8platform/game-engine 0.13.0 → 0.14.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/README.md +60 -9
- package/dist/index.cjs.js +215 -56
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +28 -6
- package/dist/index.esm.js +215 -56
- package/dist/index.esm.js.map +1 -1
- package/dist/react.cjs.js +216 -57
- package/dist/react.cjs.js.map +1 -1
- package/dist/react.esm.js +216 -57
- package/dist/react.esm.js.map +1 -1
- package/dist/ui.cjs.js +215 -56
- package/dist/ui.cjs.js.map +1 -1
- package/dist/ui.d.ts +29 -7
- package/dist/ui.esm.js +215 -56
- package/dist/ui.esm.js.map +1 -1
- package/package.json +1 -1
- package/scripts/install-simulate.mjs +2 -2
- package/src/react/jsx.d.ts +15 -3
- package/src/react/reconciler.ts +1 -1
- package/src/ui/FlexContainer.ts +241 -61
- package/src/ui/index.ts +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1265,6 +1265,7 @@ declare class SpriteAnimation {
|
|
|
1265
1265
|
type FlexDirection = 'row' | 'column';
|
|
1266
1266
|
type JustifyContent = 'start' | 'center' | 'end' | 'space-between' | 'space-around';
|
|
1267
1267
|
type AlignItems = 'start' | 'center' | 'end' | 'stretch';
|
|
1268
|
+
type AlignContent = 'start' | 'center' | 'end' | 'space-between' | 'stretch';
|
|
1268
1269
|
type AlignSelf = 'auto' | 'start' | 'center' | 'end' | 'stretch';
|
|
1269
1270
|
interface FlexItemConfig {
|
|
1270
1271
|
/** Flex grow factor (0 = fixed size) */
|
|
@@ -1272,13 +1273,21 @@ interface FlexItemConfig {
|
|
|
1272
1273
|
/** Flex shrink factor (0 = don't shrink, default: 1) */
|
|
1273
1274
|
flexShrink?: number;
|
|
1274
1275
|
/** Explicit width override for layout calculations */
|
|
1275
|
-
layoutWidth?: number;
|
|
1276
|
+
layoutWidth?: number | string;
|
|
1276
1277
|
/** Explicit height override for layout calculations */
|
|
1277
|
-
layoutHeight?: number;
|
|
1278
|
+
layoutHeight?: number | string;
|
|
1278
1279
|
/** Override parent's alignItems for this child */
|
|
1279
1280
|
alignSelf?: AlignSelf;
|
|
1280
1281
|
/** Exclude from flex layout (acts like position: absolute) */
|
|
1281
1282
|
flexExclude?: boolean;
|
|
1283
|
+
/** Absolute positioning for flexExclude children (distance from top edge) */
|
|
1284
|
+
top?: number;
|
|
1285
|
+
/** Absolute positioning for flexExclude children (distance from right edge) */
|
|
1286
|
+
right?: number;
|
|
1287
|
+
/** Absolute positioning for flexExclude children (distance from bottom edge) */
|
|
1288
|
+
bottom?: number;
|
|
1289
|
+
/** Absolute positioning for flexExclude children (distance from left edge) */
|
|
1290
|
+
left?: number;
|
|
1282
1291
|
}
|
|
1283
1292
|
interface FlexContainerConfig {
|
|
1284
1293
|
/** Layout direction (default: 'row') */
|
|
@@ -1291,16 +1300,23 @@ interface FlexContainerConfig {
|
|
|
1291
1300
|
gap?: number;
|
|
1292
1301
|
/** Padding [top, right, bottom, left] or single number (default: 0) */
|
|
1293
1302
|
padding?: number | [number, number, number, number];
|
|
1303
|
+
/** Individual padding overrides (take priority over `padding`) */
|
|
1304
|
+
paddingTop?: number;
|
|
1305
|
+
paddingRight?: number;
|
|
1306
|
+
paddingBottom?: number;
|
|
1307
|
+
paddingLeft?: number;
|
|
1294
1308
|
/** Enable wrapping to next line (default: false) */
|
|
1295
1309
|
flexWrap?: boolean;
|
|
1310
|
+
/** Distribution of lines along the cross axis when wrapping (default: 'start') */
|
|
1311
|
+
alignContent?: AlignContent;
|
|
1296
1312
|
/** Maximum width before wrapping (only with flexWrap) */
|
|
1297
1313
|
maxWidth?: number;
|
|
1298
1314
|
/** Maximum height before wrapping (only with flexWrap + column) */
|
|
1299
1315
|
maxHeight?: number;
|
|
1300
|
-
/** Explicit container width
|
|
1301
|
-
width?: number;
|
|
1302
|
-
/** Explicit container height
|
|
1303
|
-
height?: number;
|
|
1316
|
+
/** Explicit container width — number in pixels, or string percentage (e.g. "50%") resolved against parent */
|
|
1317
|
+
width?: number | string;
|
|
1318
|
+
/** Explicit container height — number in pixels, or string percentage (e.g. "50%") resolved against parent */
|
|
1319
|
+
height?: number | string;
|
|
1304
1320
|
}
|
|
1305
1321
|
/**
|
|
1306
1322
|
* Lightweight flexbox-like layout container for PixiJS.
|
|
@@ -1331,6 +1347,12 @@ declare class FlexContainer extends Container {
|
|
|
1331
1347
|
private _maxHeight;
|
|
1332
1348
|
/** @internal */ _explicitWidth: number;
|
|
1333
1349
|
/** @internal */ _explicitHeight: number;
|
|
1350
|
+
/** @internal */ _computedWidth: number;
|
|
1351
|
+
/** @internal */ _computedHeight: number;
|
|
1352
|
+
/** @internal */ _availableWidth: number;
|
|
1353
|
+
/** @internal */ _availableHeight: number;
|
|
1354
|
+
/** @internal */ _rawWidth: number | string;
|
|
1355
|
+
/** @internal */ _rawHeight: number | string;
|
|
1334
1356
|
private _layoutChildren;
|
|
1335
1357
|
private _layoutDirty;
|
|
1336
1358
|
constructor(config?: FlexContainerConfig);
|
package/dist/index.esm.js
CHANGED
|
@@ -2911,26 +2911,90 @@ class SpriteAnimation {
|
|
|
2911
2911
|
function normalizePadding(p) {
|
|
2912
2912
|
return typeof p === 'number' ? [p, p, p, p] : p;
|
|
2913
2913
|
}
|
|
2914
|
+
/** Resolve padding from config: individual props override the base `padding` value */
|
|
2915
|
+
function resolvePadding(config) {
|
|
2916
|
+
const base = normalizePadding(config.padding ?? 0);
|
|
2917
|
+
return [
|
|
2918
|
+
config.paddingTop ?? base[0],
|
|
2919
|
+
config.paddingRight ?? base[1],
|
|
2920
|
+
config.paddingBottom ?? base[2],
|
|
2921
|
+
config.paddingLeft ?? base[3],
|
|
2922
|
+
];
|
|
2923
|
+
}
|
|
2924
|
+
/** Resolve a dimension value — number passes through, "50%" resolves against reference */
|
|
2925
|
+
function resolveDimension(value, reference) {
|
|
2926
|
+
if (value === undefined)
|
|
2927
|
+
return undefined;
|
|
2928
|
+
if (typeof value === 'number')
|
|
2929
|
+
return value;
|
|
2930
|
+
if (typeof value === 'string' && value.endsWith('%')) {
|
|
2931
|
+
const pct = parseFloat(value);
|
|
2932
|
+
if (!isNaN(pct) && reference > 0 && isFinite(reference))
|
|
2933
|
+
return (pct / 100) * reference;
|
|
2934
|
+
}
|
|
2935
|
+
return undefined;
|
|
2936
|
+
}
|
|
2914
2937
|
/** Measure a child's size and bounds offset for layout purposes */
|
|
2915
|
-
function measureChild(child) {
|
|
2938
|
+
function measureChild(child, parentContentW = 0, parentContentH = 0) {
|
|
2916
2939
|
const cfg = child._flexConfig;
|
|
2917
|
-
|
|
2918
|
-
|
|
2940
|
+
const resolvedLW = resolveDimension(cfg?.layoutWidth, parentContentW);
|
|
2941
|
+
const resolvedLH = resolveDimension(cfg?.layoutHeight, parentContentH);
|
|
2942
|
+
if (resolvedLW !== undefined && resolvedLH !== undefined) {
|
|
2943
|
+
return { w: resolvedLW, h: resolvedLH, ox: 0, oy: 0 };
|
|
2919
2944
|
}
|
|
2920
|
-
// For FlexContainers, use their explicit
|
|
2945
|
+
// For FlexContainers, use their explicit or computed size
|
|
2921
2946
|
if (child instanceof FlexContainer) {
|
|
2922
2947
|
const fc = child;
|
|
2923
|
-
|
|
2924
|
-
|
|
2948
|
+
const w = fc._explicitWidth > 0 ? fc._explicitWidth : (fc._computedWidth > 0 ? fc._computedWidth : undefined);
|
|
2949
|
+
const h = fc._explicitHeight > 0 ? fc._explicitHeight : (fc._computedHeight > 0 ? fc._computedHeight : undefined);
|
|
2950
|
+
if (w !== undefined && h !== undefined) {
|
|
2951
|
+
return { w, h, ox: 0, oy: 0 };
|
|
2925
2952
|
}
|
|
2926
2953
|
}
|
|
2927
2954
|
// Use localBounds to get the true visual extent and origin offset.
|
|
2928
2955
|
// This handles children with non-zero anchors (e.g. Button, Label with centered text).
|
|
2929
2956
|
const bounds = child.getLocalBounds();
|
|
2930
|
-
const w =
|
|
2931
|
-
const h =
|
|
2957
|
+
const w = resolvedLW ?? bounds.width;
|
|
2958
|
+
const h = resolvedLH ?? bounds.height;
|
|
2932
2959
|
return { w, h, ox: bounds.x, oy: bounds.y };
|
|
2933
2960
|
}
|
|
2961
|
+
/**
|
|
2962
|
+
* Set a child's main or cross dimension.
|
|
2963
|
+
* For FlexContainer children, calls resize() to trigger internal relayout
|
|
2964
|
+
* instead of the PixiJS scale setter.
|
|
2965
|
+
*/
|
|
2966
|
+
function setChildMainSize(child, isRow, mainSize, item) {
|
|
2967
|
+
if (child instanceof FlexContainer) {
|
|
2968
|
+
const fc = child;
|
|
2969
|
+
fc.resize(isRow ? mainSize : fc._explicitWidth || fc._computedWidth, isRow ? fc._explicitHeight || fc._computedHeight : mainSize);
|
|
2970
|
+
}
|
|
2971
|
+
else {
|
|
2972
|
+
if (isRow) {
|
|
2973
|
+
child.width = mainSize;
|
|
2974
|
+
}
|
|
2975
|
+
else {
|
|
2976
|
+
child.height = mainSize;
|
|
2977
|
+
}
|
|
2978
|
+
}
|
|
2979
|
+
if (isRow)
|
|
2980
|
+
item.w = mainSize;
|
|
2981
|
+
else
|
|
2982
|
+
item.h = mainSize;
|
|
2983
|
+
}
|
|
2984
|
+
function setChildCrossSize(child, isRow, crossSize) {
|
|
2985
|
+
if (child instanceof FlexContainer) {
|
|
2986
|
+
const fc = child;
|
|
2987
|
+
fc.resize(isRow ? fc._explicitWidth || fc._computedWidth : crossSize, isRow ? crossSize : fc._explicitHeight || fc._computedHeight);
|
|
2988
|
+
}
|
|
2989
|
+
else {
|
|
2990
|
+
if (isRow) {
|
|
2991
|
+
child.height = crossSize;
|
|
2992
|
+
}
|
|
2993
|
+
else {
|
|
2994
|
+
child.width = crossSize;
|
|
2995
|
+
}
|
|
2996
|
+
}
|
|
2997
|
+
}
|
|
2934
2998
|
function layoutLine(items, isRow, mainSize, justify, align, gap, crossOffset, crossSize) {
|
|
2935
2999
|
if (items.length === 0)
|
|
2936
3000
|
return;
|
|
@@ -2954,14 +3018,7 @@ function layoutLine(items, isRow, mainSize, justify, align, gap, crossOffset, cr
|
|
|
2954
3018
|
const grow = item.child._flexConfig?.flexGrow ?? 0;
|
|
2955
3019
|
if (grow > 0) {
|
|
2956
3020
|
const flexSize = (grow / totalGrow) * availableForFlex;
|
|
2957
|
-
|
|
2958
|
-
item.w = flexSize;
|
|
2959
|
-
item.child.width = flexSize;
|
|
2960
|
-
}
|
|
2961
|
-
else {
|
|
2962
|
-
item.h = flexSize;
|
|
2963
|
-
item.child.height = flexSize;
|
|
2964
|
-
}
|
|
3021
|
+
setChildMainSize(item.child, isRow, flexSize, item);
|
|
2965
3022
|
}
|
|
2966
3023
|
}
|
|
2967
3024
|
}
|
|
@@ -2983,14 +3040,7 @@ function layoutLine(items, isRow, mainSize, justify, align, gap, crossOffset, cr
|
|
|
2983
3040
|
const itemMain = isRow ? item.w : item.h;
|
|
2984
3041
|
const reduction = overflow * (itemMain / totalShrinkable);
|
|
2985
3042
|
const newSize = Math.max(0, itemMain - reduction);
|
|
2986
|
-
|
|
2987
|
-
item.w = newSize;
|
|
2988
|
-
item.child.width = newSize;
|
|
2989
|
-
}
|
|
2990
|
-
else {
|
|
2991
|
-
item.h = newSize;
|
|
2992
|
-
item.child.height = newSize;
|
|
2993
|
-
}
|
|
3043
|
+
setChildMainSize(item.child, isRow, newSize, item);
|
|
2994
3044
|
}
|
|
2995
3045
|
}
|
|
2996
3046
|
}
|
|
@@ -3047,12 +3097,7 @@ function layoutLine(items, isRow, mainSize, justify, align, gap, crossOffset, cr
|
|
|
3047
3097
|
crossPos += crossSize - crossDim;
|
|
3048
3098
|
break;
|
|
3049
3099
|
case 'stretch':
|
|
3050
|
-
|
|
3051
|
-
item.child.height = crossSize;
|
|
3052
|
-
}
|
|
3053
|
-
else {
|
|
3054
|
-
item.child.width = crossSize;
|
|
3055
|
-
}
|
|
3100
|
+
setChildCrossSize(item.child, isRow, crossSize);
|
|
3056
3101
|
break;
|
|
3057
3102
|
}
|
|
3058
3103
|
// Compensate for local bounds offset (e.g. centered anchors)
|
|
@@ -3097,6 +3142,12 @@ class FlexContainer extends Container {
|
|
|
3097
3142
|
_maxHeight;
|
|
3098
3143
|
/** @internal */ _explicitWidth;
|
|
3099
3144
|
/** @internal */ _explicitHeight;
|
|
3145
|
+
/** @internal */ _computedWidth = 0;
|
|
3146
|
+
/** @internal */ _computedHeight = 0;
|
|
3147
|
+
/** @internal */ _availableWidth = 0;
|
|
3148
|
+
/** @internal */ _availableHeight = 0;
|
|
3149
|
+
/** @internal */ _rawWidth;
|
|
3150
|
+
/** @internal */ _rawHeight;
|
|
3100
3151
|
_layoutChildren = [];
|
|
3101
3152
|
_layoutDirty = true;
|
|
3102
3153
|
constructor(config = {}) {
|
|
@@ -3107,12 +3158,15 @@ class FlexContainer extends Container {
|
|
|
3107
3158
|
alignItems: config.alignItems ?? 'start',
|
|
3108
3159
|
gap: config.gap ?? 0,
|
|
3109
3160
|
flexWrap: config.flexWrap ?? false,
|
|
3161
|
+
alignContent: config.alignContent ?? 'start',
|
|
3110
3162
|
};
|
|
3111
|
-
this._padding =
|
|
3163
|
+
this._padding = resolvePadding(config);
|
|
3112
3164
|
this._maxWidth = config.maxWidth ?? Infinity;
|
|
3113
3165
|
this._maxHeight = config.maxHeight ?? Infinity;
|
|
3114
|
-
this.
|
|
3115
|
-
this.
|
|
3166
|
+
this._rawWidth = config.width ?? 0;
|
|
3167
|
+
this._rawHeight = config.height ?? 0;
|
|
3168
|
+
this._explicitWidth = typeof this._rawWidth === 'number' ? this._rawWidth : 0;
|
|
3169
|
+
this._explicitHeight = typeof this._rawHeight === 'number' ? this._rawHeight : 0;
|
|
3116
3170
|
}
|
|
3117
3171
|
// ─── Public API ──────────────────────────────────────
|
|
3118
3172
|
/** Add a child with optional flex config. Also registers in flex layout. */
|
|
@@ -3214,19 +3268,41 @@ class FlexContainer extends Container {
|
|
|
3214
3268
|
*/
|
|
3215
3269
|
updateLayout() {
|
|
3216
3270
|
this._layoutDirty = false;
|
|
3217
|
-
const { direction, justifyContent, alignItems, gap, flexWrap } = this._config;
|
|
3271
|
+
const { direction, justifyContent, alignItems, gap, flexWrap, alignContent } = this._config;
|
|
3218
3272
|
const [pt, pr, pb, pl] = this._padding;
|
|
3219
3273
|
const isRow = direction === 'row';
|
|
3274
|
+
// Resolve percentage width/height against parent's available space
|
|
3275
|
+
if (typeof this._rawWidth === 'string') {
|
|
3276
|
+
this._explicitWidth = resolveDimension(this._rawWidth, this._availableWidth) ?? 0;
|
|
3277
|
+
}
|
|
3278
|
+
if (typeof this._rawHeight === 'string') {
|
|
3279
|
+
this._explicitHeight = resolveDimension(this._rawHeight, this._availableHeight) ?? 0;
|
|
3280
|
+
}
|
|
3220
3281
|
const contentW = this._explicitWidth > 0 ? this._explicitWidth - pl - pr : Infinity;
|
|
3221
3282
|
const contentH = this._explicitHeight > 0 ? this._explicitHeight - pt - pb : Infinity;
|
|
3222
3283
|
const mainLimit = isRow ? contentW : contentH;
|
|
3223
3284
|
const crossLimit = isRow ? contentH : contentW;
|
|
3285
|
+
// Pass content area to measureChild for percentage resolution
|
|
3286
|
+
const pctRefW = contentW < Infinity ? contentW : 0;
|
|
3287
|
+
const pctRefH = contentH < Infinity ? contentH : 0;
|
|
3288
|
+
// Propagate available size to child FlexContainers and resolve their percentages
|
|
3289
|
+
for (const child of this._layoutChildren) {
|
|
3290
|
+
if (child instanceof FlexContainer) {
|
|
3291
|
+
const fc = child;
|
|
3292
|
+
fc._availableWidth = pctRefW;
|
|
3293
|
+
fc._availableHeight = pctRefH;
|
|
3294
|
+
// If child has percentage dimensions, trigger its layout to resolve them
|
|
3295
|
+
if (typeof fc._rawWidth === 'string' || typeof fc._rawHeight === 'string') {
|
|
3296
|
+
fc.updateLayout();
|
|
3297
|
+
}
|
|
3298
|
+
}
|
|
3299
|
+
}
|
|
3224
3300
|
// Measure children (skip flexExclude — they position themselves)
|
|
3225
3301
|
const measured = [];
|
|
3226
3302
|
for (const child of this._layoutChildren) {
|
|
3227
3303
|
if (child._flexConfig?.flexExclude)
|
|
3228
3304
|
continue;
|
|
3229
|
-
const { w, h, ox, oy } = measureChild(child);
|
|
3305
|
+
const { w, h, ox, oy } = measureChild(child, pctRefW, pctRefH);
|
|
3230
3306
|
measured.push({ child, w, h, ox, oy });
|
|
3231
3307
|
}
|
|
3232
3308
|
// Split into lines (if wrapping)
|
|
@@ -3263,42 +3339,106 @@ class FlexContainer extends Container {
|
|
|
3263
3339
|
}
|
|
3264
3340
|
return maxCross;
|
|
3265
3341
|
});
|
|
3342
|
+
// Compute natural main size (for auto-sizing when no explicit size given)
|
|
3343
|
+
let naturalMainSize = 0;
|
|
3344
|
+
if (mainLimit === Infinity) {
|
|
3345
|
+
for (const line of lines) {
|
|
3346
|
+
let lineMain = 0;
|
|
3347
|
+
for (const item of line) {
|
|
3348
|
+
lineMain += isRow ? item.w : item.h;
|
|
3349
|
+
}
|
|
3350
|
+
lineMain += gap * Math.max(0, line.length - 1);
|
|
3351
|
+
naturalMainSize = Math.max(naturalMainSize, lineMain);
|
|
3352
|
+
}
|
|
3353
|
+
}
|
|
3354
|
+
// Effective main size: explicit if set, otherwise natural content size
|
|
3355
|
+
const effectiveMainSize = mainLimit < Infinity ? mainLimit : naturalMainSize;
|
|
3356
|
+
// Compute alignContent offsets for multi-line layouts
|
|
3357
|
+
const totalLinesCross = lineCrossSizes.reduce((s, v) => s + v, 0) + gap * Math.max(0, lines.length - 1);
|
|
3358
|
+
let acOffset = 0;
|
|
3359
|
+
let acExtraGap = 0;
|
|
3360
|
+
if (lines.length > 1 && crossLimit < Infinity) {
|
|
3361
|
+
const freeSpace = Math.max(0, crossLimit - totalLinesCross);
|
|
3362
|
+
switch (alignContent) {
|
|
3363
|
+
case 'center':
|
|
3364
|
+
acOffset = freeSpace / 2;
|
|
3365
|
+
break;
|
|
3366
|
+
case 'end':
|
|
3367
|
+
acOffset = freeSpace;
|
|
3368
|
+
break;
|
|
3369
|
+
case 'space-between':
|
|
3370
|
+
if (lines.length > 1) {
|
|
3371
|
+
acExtraGap = freeSpace / (lines.length - 1);
|
|
3372
|
+
}
|
|
3373
|
+
break;
|
|
3374
|
+
case 'stretch':
|
|
3375
|
+
if (lines.length > 0) {
|
|
3376
|
+
const extra = freeSpace / lines.length;
|
|
3377
|
+
for (let i = 0; i < lineCrossSizes.length; i++) {
|
|
3378
|
+
lineCrossSizes[i] += extra;
|
|
3379
|
+
}
|
|
3380
|
+
}
|
|
3381
|
+
break;
|
|
3382
|
+
// 'start' — no adjustment
|
|
3383
|
+
}
|
|
3384
|
+
}
|
|
3266
3385
|
// Layout each line
|
|
3267
|
-
let crossOffset = isRow ? pt : pl;
|
|
3386
|
+
let crossOffset = (isRow ? pt : pl) + acOffset;
|
|
3268
3387
|
for (let i = 0; i < lines.length; i++) {
|
|
3269
3388
|
const line = lines[i];
|
|
3270
3389
|
const lineCross = lineCrossSizes[i];
|
|
3271
3390
|
const mainStart = isRow ? pl : pt;
|
|
3272
3391
|
// Offset items by padding
|
|
3273
3392
|
const tempItems = line.map((item) => ({ ...item }));
|
|
3274
|
-
//
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
? crossLimit
|
|
3278
|
-
: (crossLimit < Infinity ? Math.min(lineCross, crossLimit) : lineCross);
|
|
3279
|
-
layoutLine(tempItems, isRow, mainLimit < Infinity ? mainLimit : 0, mainLimit < Infinity ? justifyContent : 'start', alignItems, gap, crossOffset, effectiveCross);
|
|
3393
|
+
// Cross size for alignment: use container cross size for single-line, line cross for multi-line
|
|
3394
|
+
const effectiveCross = lines.length === 1 && crossLimit < Infinity ? crossLimit : lineCross;
|
|
3395
|
+
layoutLine(tempItems, isRow, effectiveMainSize, mainLimit < Infinity ? justifyContent : 'start', alignItems, gap, crossOffset, effectiveCross);
|
|
3280
3396
|
// Apply main-axis padding offset
|
|
3281
3397
|
for (const item of tempItems) {
|
|
3282
3398
|
const origChild = line.find((l) => l.child === item.child);
|
|
3283
3399
|
origChild.child.x = item.child.x + (isRow ? mainStart : 0);
|
|
3284
3400
|
origChild.child.y = item.child.y + (isRow ? 0 : mainStart);
|
|
3285
3401
|
}
|
|
3286
|
-
crossOffset += lineCross + gap;
|
|
3402
|
+
crossOffset += lineCross + gap + acExtraGap;
|
|
3403
|
+
}
|
|
3404
|
+
// Compute and store actual dimensions for measureChild() and getContentSize()
|
|
3405
|
+
let totalCrossNatural = 0;
|
|
3406
|
+
for (let i = 0; i < lineCrossSizes.length; i++) {
|
|
3407
|
+
totalCrossNatural += lineCrossSizes[i];
|
|
3408
|
+
if (i < lineCrossSizes.length - 1)
|
|
3409
|
+
totalCrossNatural += gap;
|
|
3410
|
+
}
|
|
3411
|
+
if (isRow) {
|
|
3412
|
+
this._computedWidth = this._explicitWidth > 0 ? this._explicitWidth : (pl + naturalMainSize + pr);
|
|
3413
|
+
this._computedHeight = this._explicitHeight > 0 ? this._explicitHeight : (pt + totalCrossNatural + pb);
|
|
3414
|
+
}
|
|
3415
|
+
else {
|
|
3416
|
+
this._computedWidth = this._explicitWidth > 0 ? this._explicitWidth : (pl + totalCrossNatural + pr);
|
|
3417
|
+
this._computedHeight = this._explicitHeight > 0 ? this._explicitHeight : (pt + naturalMainSize + pb);
|
|
3418
|
+
}
|
|
3419
|
+
// Position flexExclude children (absolute positioning)
|
|
3420
|
+
for (const child of this._layoutChildren) {
|
|
3421
|
+
if (!child._flexConfig?.flexExclude)
|
|
3422
|
+
continue;
|
|
3423
|
+
const cfg = child._flexConfig;
|
|
3424
|
+
const { w, h } = measureChild(child, pctRefW, pctRefH);
|
|
3425
|
+
const cw = this._computedWidth;
|
|
3426
|
+
const ch = this._computedHeight;
|
|
3427
|
+
if (cfg.left !== undefined)
|
|
3428
|
+
child.x = cfg.left;
|
|
3429
|
+
else if (cfg.right !== undefined)
|
|
3430
|
+
child.x = cw - w - cfg.right;
|
|
3431
|
+
if (cfg.top !== undefined)
|
|
3432
|
+
child.y = cfg.top;
|
|
3433
|
+
else if (cfg.bottom !== undefined)
|
|
3434
|
+
child.y = ch - h - cfg.bottom;
|
|
3287
3435
|
}
|
|
3288
3436
|
}
|
|
3289
3437
|
/** Computed content size (after layout) */
|
|
3290
3438
|
getContentSize() {
|
|
3291
3439
|
if (this._layoutDirty)
|
|
3292
3440
|
this.updateLayout();
|
|
3293
|
-
|
|
3294
|
-
let maxY = 0;
|
|
3295
|
-
for (const child of this._layoutChildren) {
|
|
3296
|
-
const { w, h } = measureChild(child);
|
|
3297
|
-
maxX = Math.max(maxX, child.x + w);
|
|
3298
|
-
maxY = Math.max(maxY, child.y + h);
|
|
3299
|
-
}
|
|
3300
|
-
const [, pr, pb] = this._padding;
|
|
3301
|
-
return { width: maxX + pr, height: maxY + pb };
|
|
3441
|
+
return { width: this._computedWidth, height: this._computedHeight };
|
|
3302
3442
|
}
|
|
3303
3443
|
/** React reconciler update hook — applies changed config props */
|
|
3304
3444
|
updateConfig(changed) {
|
|
@@ -3310,15 +3450,34 @@ class FlexContainer extends Container {
|
|
|
3310
3450
|
this.setAlignItems(changed.alignItems);
|
|
3311
3451
|
if ('gap' in changed)
|
|
3312
3452
|
this.setGap(changed.gap);
|
|
3313
|
-
if ('padding' in changed)
|
|
3314
|
-
this.
|
|
3453
|
+
if ('padding' in changed || 'paddingTop' in changed || 'paddingRight' in changed || 'paddingBottom' in changed || 'paddingLeft' in changed) {
|
|
3454
|
+
this._padding = resolvePadding(changed);
|
|
3455
|
+
this._layoutDirty = true;
|
|
3456
|
+
}
|
|
3315
3457
|
if ('flexWrap' in changed) {
|
|
3316
3458
|
this._config.flexWrap = changed.flexWrap;
|
|
3317
3459
|
this._layoutDirty = true;
|
|
3318
3460
|
}
|
|
3461
|
+
if ('alignContent' in changed) {
|
|
3462
|
+
this._config.alignContent = changed.alignContent;
|
|
3463
|
+
this._layoutDirty = true;
|
|
3464
|
+
}
|
|
3319
3465
|
if ('width' in changed || 'height' in changed) {
|
|
3320
|
-
|
|
3321
|
-
|
|
3466
|
+
const w = changed.width ?? this._rawWidth;
|
|
3467
|
+
const h = changed.height ?? this._rawHeight;
|
|
3468
|
+
this._rawWidth = w;
|
|
3469
|
+
this._rawHeight = h;
|
|
3470
|
+
if (typeof w === 'number' && typeof h === 'number') {
|
|
3471
|
+
this.resize(w, h);
|
|
3472
|
+
}
|
|
3473
|
+
else {
|
|
3474
|
+
// Percentage — will resolve in updateLayout
|
|
3475
|
+
this._explicitWidth = typeof w === 'number' ? w : 0;
|
|
3476
|
+
this._explicitHeight = typeof h === 'number' ? h : 0;
|
|
3477
|
+
this._layoutDirty = true;
|
|
3478
|
+
this.updateLayout();
|
|
3479
|
+
}
|
|
3480
|
+
return;
|
|
3322
3481
|
}
|
|
3323
3482
|
if (this._layoutDirty)
|
|
3324
3483
|
this.updateLayout();
|