@ng-native/fabric 0.18.2 → 0.19.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/dist/engine.d.ts +51 -14
- package/dist/engine.js +114 -16
- package/dist/engine.js.map +1 -1
- package/package.json +1 -1
package/dist/engine.d.ts
CHANGED
|
@@ -228,12 +228,8 @@ export interface EngineNode extends HostNode {
|
|
|
228
228
|
nodeText: string;
|
|
229
229
|
childList: EngineNode[];
|
|
230
230
|
parent: EngineNode | null;
|
|
231
|
-
/**
|
|
232
|
-
|
|
233
|
-
* node put the child there instead, so a component's template lands inside a view its owner
|
|
234
|
-
* placed in the host element. Only the view itself goes in this node.
|
|
235
|
-
*/
|
|
236
|
-
contentView?: EngineNode;
|
|
231
|
+
/** Set by `Engine.wrapChildren`: the view this node's children are committed in. */
|
|
232
|
+
wrapper?: Wrapper;
|
|
237
233
|
listeners: Map<string, Set<(event: unknown) => void>> | null;
|
|
238
234
|
/** CSS classes on this node, for selector matching. */
|
|
239
235
|
classes: Set<string> | null;
|
|
@@ -311,11 +307,11 @@ export interface EngineNode extends HostNode {
|
|
|
311
307
|
scrollsOverflow?: true;
|
|
312
308
|
/** Set while this element is one: see `Engine.settleScrolling`. */
|
|
313
309
|
scrollView?: true;
|
|
314
|
-
/**
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
310
|
+
/**
|
|
311
|
+
* The view a scrolling element's children are in, or a wrapped one's (`wrapper`), as it was
|
|
312
|
+
* last committed: a wrapper's with the props it was committed with.
|
|
313
|
+
*/
|
|
314
|
+
inside?: Inside;
|
|
319
315
|
/** Set while `settleLine` has given an always-inline element a line for the boxes it holds. */
|
|
320
316
|
lined?: true;
|
|
321
317
|
/** Set while an always-inline element is a flex box or a grid by its own style. */
|
|
@@ -545,6 +541,21 @@ export declare function markPage(node: EngineNode): void;
|
|
|
545
541
|
* and its `overflow` is layout alone.
|
|
546
542
|
*/
|
|
547
543
|
export declare function scrollsOverflow(node: EngineNode): void;
|
|
544
|
+
/**
|
|
545
|
+
* A view the engine commits an element's children in, which is no node of the tree: see
|
|
546
|
+
* `Engine.wrapChildren`.
|
|
547
|
+
*/
|
|
548
|
+
export interface Wrapper {
|
|
549
|
+
readonly viewName: string;
|
|
550
|
+
readonly props: Readonly<Record<string, unknown>>;
|
|
551
|
+
}
|
|
552
|
+
/** The view an element's children are committed in, as `inside` keeps it. */
|
|
553
|
+
interface Inside {
|
|
554
|
+
handle: FabricNode;
|
|
555
|
+
childHandles: FabricNode[];
|
|
556
|
+
/** A wrapper's props, as it was committed with them. */
|
|
557
|
+
props?: Record<string, unknown>;
|
|
558
|
+
}
|
|
548
559
|
/**
|
|
549
560
|
* Mark an element as the host of a component. The platform adapter calls this from
|
|
550
561
|
* `RendererFactory2.createRenderer`, which Angular calls once for every component it mounts,
|
|
@@ -1362,8 +1373,8 @@ export declare class Engine implements HostEngine {
|
|
|
1362
1373
|
/** Angular's `@if`/`@for`/`ViewContainerRef` markers. Ordered, never committed. */
|
|
1363
1374
|
createAnchor(): EngineNode;
|
|
1364
1375
|
createText(value: string): EngineNode;
|
|
1365
|
-
appendChild(
|
|
1366
|
-
insertBefore(
|
|
1376
|
+
appendChild(parent: EngineNode, child: EngineNode): void;
|
|
1377
|
+
insertBefore(parent: EngineNode, child: EngineNode, ref: EngineNode | null): void;
|
|
1367
1378
|
/**
|
|
1368
1379
|
* A node coming under a parent other than the one it is under, or under any once it has been
|
|
1369
1380
|
* taken out: what is over it may be other than it was styled under. The resolver sees that for
|
|
@@ -1372,6 +1383,19 @@ export declare class Engine implements HostEngine {
|
|
|
1372
1383
|
*/
|
|
1373
1384
|
private markAdopted;
|
|
1374
1385
|
removeChild(parent: EngineNode | null, child: EngineNode): void;
|
|
1386
|
+
/**
|
|
1387
|
+
* Commit an element's children inside a view of the engine's own, `wrapper.viewName` with
|
|
1388
|
+
* `wrapper.props`, and the element's own view around it; null commits them in the element
|
|
1389
|
+
* again. For a native view that wants its content in a child of a kind it names, where the
|
|
1390
|
+
* element is a component's host: the tree keeps the children in the element, so the
|
|
1391
|
+
* component's `:host` rules, a `:host >` selector and what is inherited reach them as written,
|
|
1392
|
+
* and how the element places its children (`flex-direction`, `justify-content`, `align-items`,
|
|
1393
|
+
* `gap`) is committed on the wrapper, which holds them. What is hoisted into the element and
|
|
1394
|
+
* its fixed boxes stay its own, after the wrapper. Called again with another wrapper's props,
|
|
1395
|
+
* the wrapper is cloned with them; another view name makes the element and what it holds again,
|
|
1396
|
+
* as native gives a view one parent for as long as it lives.
|
|
1397
|
+
*/
|
|
1398
|
+
wrapChildren(node: EngineNode, wrapper: Wrapper | null): void;
|
|
1375
1399
|
/**
|
|
1376
1400
|
* A child came or went under a view that takes its text as a prop: that prop changed. A span
|
|
1377
1401
|
* changes it too, by keeping or dropping the space before it.
|
|
@@ -3114,6 +3138,18 @@ export declare class Engine implements HostEngine {
|
|
|
3114
3138
|
* for a content that was cloned.
|
|
3115
3139
|
*/
|
|
3116
3140
|
private reconcileScroller;
|
|
3141
|
+
/**
|
|
3142
|
+
* `reconcile` for an element whose children are in a wrapper (`wrapChildren`): its own view,
|
|
3143
|
+
* holding the wrapper and then `beside`, and the wrapper holding its children. The wrapper is
|
|
3144
|
+
* created with the element and cloned for what changed of its own, as a scroll view's content
|
|
3145
|
+
* is.
|
|
3146
|
+
*/
|
|
3147
|
+
private reconcileWrapped;
|
|
3148
|
+
/** `noteClone` for a wrapped element, whose children are counted in its wrapper. */
|
|
3149
|
+
private noteWrappedClone;
|
|
3150
|
+
/** A wrapper cloned for what changed of its props, and for children that moved. */
|
|
3151
|
+
private clonedWrapper;
|
|
3152
|
+
private createWrapped;
|
|
3117
3153
|
/** A view cloned for the props and the children that changed, or itself where neither did. */
|
|
3118
3154
|
private clonedFor;
|
|
3119
3155
|
private createScroller;
|
|
@@ -3251,7 +3287,8 @@ export declare class Engine implements HostEngine {
|
|
|
3251
3287
|
/**
|
|
3252
3288
|
* `reconcileChildren` for a node other nodes hoist into: its own children, each followed by
|
|
3253
3289
|
* the hoisted nodes written inside it, then those written in it directly, then the views it
|
|
3254
|
-
* keeps for hoisted nodes that are gone.
|
|
3290
|
+
* keeps for hoisted nodes that are gone. A wrapped node's hoisted nodes and kept views go in
|
|
3291
|
+
* `beside`, beside its wrapper and not in it, in the same order.
|
|
3255
3292
|
*/
|
|
3256
3293
|
private reconcileHoistTarget;
|
|
3257
3294
|
/**
|
package/dist/engine.js
CHANGED
|
@@ -461,15 +461,33 @@ export function markPage(node) {
|
|
|
461
461
|
export function scrollsOverflow(node) {
|
|
462
462
|
node.scrollsOverflow = true;
|
|
463
463
|
}
|
|
464
|
+
/** How a flex container places its children, which the view they are in takes. */
|
|
465
|
+
const CHILD_PLACING_KEYS = [
|
|
466
|
+
...['flexDirection', 'flexWrap', 'alignItems', 'alignContent', 'justifyContent'],
|
|
467
|
+
...['gap', 'rowGap', 'columnGap'],
|
|
468
|
+
];
|
|
464
469
|
/** What a scrolling element lays out what it holds by, which its content view takes. */
|
|
465
470
|
const CONTENT_KEYS = new Set([
|
|
466
471
|
...['padding', 'paddingTop', 'paddingRight', 'paddingBottom', 'paddingLeft'],
|
|
467
472
|
...['paddingHorizontal', 'paddingVertical', 'paddingStart', 'paddingEnd'],
|
|
468
473
|
...['paddingInline', 'paddingBlock', 'paddingInlineStart', 'paddingInlineEnd'],
|
|
469
474
|
...['paddingBlockStart', 'paddingBlockEnd'],
|
|
470
|
-
...
|
|
471
|
-
...['gap', 'rowGap', 'columnGap'],
|
|
475
|
+
...CHILD_PLACING_KEYS,
|
|
472
476
|
]);
|
|
477
|
+
const CHILD_PLACING = new Set(CHILD_PLACING_KEYS);
|
|
478
|
+
/**
|
|
479
|
+
* A wrapped element's props split between its two views: the box it is, on its own view, and how
|
|
480
|
+
* its children are placed, on the wrapper, after the wrapper's own props. Its padding stays on
|
|
481
|
+
* the element, outside what the wrapper insets by.
|
|
482
|
+
*/
|
|
483
|
+
function splitWrapped(props, own = {}) {
|
|
484
|
+
const box = {};
|
|
485
|
+
const content = { ...own };
|
|
486
|
+
for (const [key, value] of Object.entries(props)) {
|
|
487
|
+
(CHILD_PLACING.has(key) ? content : box)[key] = value;
|
|
488
|
+
}
|
|
489
|
+
return { box, content };
|
|
490
|
+
}
|
|
473
491
|
/** A scrolling element's props split between its two views: see `scrollerProps`. */
|
|
474
492
|
function splitScroller(props) {
|
|
475
493
|
const box = {};
|
|
@@ -4793,6 +4811,7 @@ class RetainedNode {
|
|
|
4793
4811
|
inlineInherits = undefined;
|
|
4794
4812
|
line = undefined;
|
|
4795
4813
|
inside = undefined;
|
|
4814
|
+
wrapper = undefined;
|
|
4796
4815
|
transitions;
|
|
4797
4816
|
playing;
|
|
4798
4817
|
scrolled;
|
|
@@ -5012,7 +5031,7 @@ const ENGINE_NODE_FIELDS = {
|
|
|
5012
5031
|
structureDirty: true,
|
|
5013
5032
|
subtreeDirty: true,
|
|
5014
5033
|
inside: true,
|
|
5015
|
-
|
|
5034
|
+
wrapper: true,
|
|
5016
5035
|
scrollsOverflow: true,
|
|
5017
5036
|
engine: true,
|
|
5018
5037
|
};
|
|
@@ -6613,8 +6632,7 @@ export class Engine {
|
|
|
6613
6632
|
node.nodeText = value;
|
|
6614
6633
|
return node;
|
|
6615
6634
|
}
|
|
6616
|
-
appendChild(
|
|
6617
|
-
const parent = into.contentView && into.contentView !== child ? into.contentView : into;
|
|
6635
|
+
appendChild(parent, child) {
|
|
6618
6636
|
this.markAdopted(child, parent);
|
|
6619
6637
|
this.detach(child);
|
|
6620
6638
|
this.markReturned(child);
|
|
@@ -6629,8 +6647,7 @@ export class Engine {
|
|
|
6629
6647
|
this.markStructure(parent, child, parent.childList.length - 1);
|
|
6630
6648
|
this.markTextContent(parent, child);
|
|
6631
6649
|
}
|
|
6632
|
-
insertBefore(
|
|
6633
|
-
const parent = into.contentView && into.contentView !== child ? into.contentView : into;
|
|
6650
|
+
insertBefore(parent, child, ref) {
|
|
6634
6651
|
this.markAdopted(child, parent);
|
|
6635
6652
|
this.detach(child);
|
|
6636
6653
|
this.markReturned(child);
|
|
@@ -6674,6 +6691,25 @@ export class Engine {
|
|
|
6674
6691
|
this.markStructure(target, child, at);
|
|
6675
6692
|
this.markTextContent(target, child);
|
|
6676
6693
|
}
|
|
6694
|
+
/**
|
|
6695
|
+
* Commit an element's children inside a view of the engine's own, `wrapper.viewName` with
|
|
6696
|
+
* `wrapper.props`, and the element's own view around it; null commits them in the element
|
|
6697
|
+
* again. For a native view that wants its content in a child of a kind it names, where the
|
|
6698
|
+
* element is a component's host: the tree keeps the children in the element, so the
|
|
6699
|
+
* component's `:host` rules, a `:host >` selector and what is inherited reach them as written,
|
|
6700
|
+
* and how the element places its children (`flex-direction`, `justify-content`, `align-items`,
|
|
6701
|
+
* `gap`) is committed on the wrapper, which holds them. What is hoisted into the element and
|
|
6702
|
+
* its fixed boxes stay its own, after the wrapper. Called again with another wrapper's props,
|
|
6703
|
+
* the wrapper is cloned with them; another view name makes the element and what it holds again,
|
|
6704
|
+
* as native gives a view one parent for as long as it lives.
|
|
6705
|
+
*/
|
|
6706
|
+
wrapChildren(node, wrapper) {
|
|
6707
|
+
const was = node.wrapper;
|
|
6708
|
+
node.wrapper = wrapper ?? undefined;
|
|
6709
|
+
if (was?.viewName !== wrapper?.viewName && node.committed)
|
|
6710
|
+
this.forgetCommitted(node);
|
|
6711
|
+
this.markProps(node, false);
|
|
6712
|
+
}
|
|
6677
6713
|
/**
|
|
6678
6714
|
* A child came or went under a view that takes its text as a prop: that prop changed. A span
|
|
6679
6715
|
* changes it too, by keeping or dropping the space before it.
|
|
@@ -12755,15 +12791,19 @@ export class Engine {
|
|
|
12755
12791
|
this.forgetRenamed(node, viewName);
|
|
12756
12792
|
this.noteBaselineFields(node);
|
|
12757
12793
|
this.freshBaselines(node);
|
|
12758
|
-
|
|
12794
|
+
// A wrapped node's own views beside the wrapper: what is hoisted into it, and its fixed boxes.
|
|
12795
|
+
const beside = node.wrapper && [];
|
|
12796
|
+
const childHandles = this.reconcileChildren(node, viewName, style, beside);
|
|
12759
12797
|
if (this.heldMoves.size)
|
|
12760
12798
|
this.heldHandles(node, childHandles);
|
|
12761
12799
|
if (this.fixedIn.size)
|
|
12762
|
-
this.fixedHandles(node, childHandles);
|
|
12800
|
+
this.fixedHandles(node, beside ?? childHandles);
|
|
12763
12801
|
this.raise(node, viewName);
|
|
12764
12802
|
noteTouches(node, style);
|
|
12765
12803
|
if (scroller)
|
|
12766
12804
|
return this.reconcileScroller(node, viewName, childHandles, styleChanged);
|
|
12805
|
+
if (beside)
|
|
12806
|
+
return this.reconcileWrapped(node, viewName, childHandles, beside, styleChanged);
|
|
12767
12807
|
const previous = node.committed;
|
|
12768
12808
|
this.notePresented(node, viewName);
|
|
12769
12809
|
if (!previous)
|
|
@@ -12863,6 +12903,62 @@ export class Engine {
|
|
|
12863
12903
|
this.clearFlags(node);
|
|
12864
12904
|
return handle;
|
|
12865
12905
|
}
|
|
12906
|
+
/**
|
|
12907
|
+
* `reconcile` for an element whose children are in a wrapper (`wrapChildren`): its own view,
|
|
12908
|
+
* holding the wrapper and then `beside`, and the wrapper holding its children. The wrapper is
|
|
12909
|
+
* created with the element and cloned for what changed of its own, as a scroll view's content
|
|
12910
|
+
* is.
|
|
12911
|
+
*/
|
|
12912
|
+
reconcileWrapped(node, viewName, childHandles, beside, styleChanged) {
|
|
12913
|
+
const previous = node.committed;
|
|
12914
|
+
const held = node.inside;
|
|
12915
|
+
if (!previous || !held?.props)
|
|
12916
|
+
return this.createWrapped(node, viewName, childHandles, beside);
|
|
12917
|
+
const propsMoved = node.propsDirty || styleChanged;
|
|
12918
|
+
const props = propsMoved ? this.mergeProps(node, viewName) : previous.props;
|
|
12919
|
+
const payload = propsMoved ? this.propsPayload(node, previous.props, props) : null;
|
|
12920
|
+
if (this.asked & LAYOUTS)
|
|
12921
|
+
this.noteHow(node, payload);
|
|
12922
|
+
const moved = this.childrenMoved(node, childHandles, held.childHandles);
|
|
12923
|
+
this.noteWrappedClone(node, payload, moved, childHandles, previous, held);
|
|
12924
|
+
const content = propsMoved ? splitWrapped(props, node.wrapper.props).content : held.props;
|
|
12925
|
+
const inside = this.clonedWrapper(held, content, moved ? childHandles : null);
|
|
12926
|
+
const around = [inside, ...beside];
|
|
12927
|
+
const aroundMoved = !sameHandles(around, previous.childHandles);
|
|
12928
|
+
const box = payload && someProps(splitWrapped(payload).box);
|
|
12929
|
+
const boxPayload = this.paintNatively(node, viewName, props, box, aroundMoved);
|
|
12930
|
+
const handle = this.clonedFor(previous.handle, boxPayload, aroundMoved ? around : null);
|
|
12931
|
+
node.committed = { handle, tag: previous.tag, props, childHandles: around, viewName };
|
|
12932
|
+
node.inside = { handle: inside, childHandles, props: content };
|
|
12933
|
+
this.clearFlags(node);
|
|
12934
|
+
return handle;
|
|
12935
|
+
}
|
|
12936
|
+
/** `noteClone` for a wrapped element, whose children are counted in its wrapper. */
|
|
12937
|
+
noteWrappedClone(node, payload, moved, childHandles, previous, held) {
|
|
12938
|
+
if (!this.notesMoves)
|
|
12939
|
+
return;
|
|
12940
|
+
const before = { ...previous, childHandles: held.childHandles };
|
|
12941
|
+
this.noteClone(node, payload, moved, childHandles, before);
|
|
12942
|
+
}
|
|
12943
|
+
/** A wrapper cloned for what changed of its props, and for children that moved. */
|
|
12944
|
+
clonedWrapper(held, props, children) {
|
|
12945
|
+
const payload = props === held.props ? null : diffProps(held.props, props);
|
|
12946
|
+
return this.clonedFor(held.handle, payload, children);
|
|
12947
|
+
}
|
|
12948
|
+
createWrapped(node, viewName, childHandles, beside) {
|
|
12949
|
+
const wrapper = node.wrapper;
|
|
12950
|
+
const props = this.mergeProps(node, viewName);
|
|
12951
|
+
const { box, content } = splitWrapped(props, wrapper.props);
|
|
12952
|
+
// A touch on the wrapper lands on the element, as one on a scroll view's content does.
|
|
12953
|
+
const inside = this.fabric.createNode(nextTag(), wrapper.viewName, this.rootTag, this.processed(content, false), node);
|
|
12954
|
+
this.stats.createdNodes++;
|
|
12955
|
+
for (const child of childHandles)
|
|
12956
|
+
this.fabric.appendChild(inside, child);
|
|
12957
|
+
const handle = this.create(node, viewName, box, [inside, ...beside]);
|
|
12958
|
+
node.committed = { ...node.committed, props };
|
|
12959
|
+
node.inside = { handle: inside, childHandles, props: content };
|
|
12960
|
+
return handle;
|
|
12961
|
+
}
|
|
12866
12962
|
/** A view cloned for the props and the children that changed, or itself where neither did. */
|
|
12867
12963
|
clonedFor(handle, props, children) {
|
|
12868
12964
|
if (!props && !children)
|
|
@@ -12922,12 +13018,12 @@ export class Engine {
|
|
|
12922
13018
|
// Exempt from the complexity limit as `mergeProps` is: run for every node with children, where
|
|
12923
13019
|
// the loop in a function of its own was a call more a node in `pnpm bench`.
|
|
12924
13020
|
// eslint-disable-next-line complexity
|
|
12925
|
-
reconcileChildren(node, viewName, style) {
|
|
13021
|
+
reconcileChildren(node, viewName, style, beside) {
|
|
12926
13022
|
const context = style?.context;
|
|
12927
13023
|
if (HOIST_ONLY.has(node.tag))
|
|
12928
13024
|
return this.reconcileOnlyHoisted(node);
|
|
12929
13025
|
if (HOIST_TARGETS.has(node.tag))
|
|
12930
|
-
return this.reconcileHoistTarget(node, context);
|
|
13026
|
+
return this.reconcileHoistTarget(node, context, beside);
|
|
12931
13027
|
if (node.flow !== undefined)
|
|
12932
13028
|
return this.reconcileInFlow(node, node.flow, viewName, context);
|
|
12933
13029
|
// A node with no flow of its own holds nothing in a line: each child is its own view under it.
|
|
@@ -13325,10 +13421,12 @@ export class Engine {
|
|
|
13325
13421
|
/**
|
|
13326
13422
|
* `reconcileChildren` for a node other nodes hoist into: its own children, each followed by
|
|
13327
13423
|
* the hoisted nodes written inside it, then those written in it directly, then the views it
|
|
13328
|
-
* keeps for hoisted nodes that are gone.
|
|
13424
|
+
* keeps for hoisted nodes that are gone. A wrapped node's hoisted nodes and kept views go in
|
|
13425
|
+
* `beside`, beside its wrapper and not in it, in the same order.
|
|
13329
13426
|
*/
|
|
13330
|
-
reconcileHoistTarget(node, context) {
|
|
13427
|
+
reconcileHoistTarget(node, context, beside) {
|
|
13331
13428
|
const handles = [];
|
|
13429
|
+
const landing = beside ?? handles;
|
|
13332
13430
|
const hoisted = this.hoistedInto(node);
|
|
13333
13431
|
const landed = new Set();
|
|
13334
13432
|
// One written directly in the node goes after its siblings: a page writes its header first,
|
|
@@ -13346,13 +13444,13 @@ export class Engine {
|
|
|
13346
13444
|
const moved = hoisted?.get(child);
|
|
13347
13445
|
for (const written of moved ?? []) {
|
|
13348
13446
|
if (!this.undisplayedUnder(node, written))
|
|
13349
|
-
|
|
13447
|
+
landing.push(this.land(node, written, landed));
|
|
13350
13448
|
}
|
|
13351
13449
|
}
|
|
13352
13450
|
for (const child of direct)
|
|
13353
|
-
|
|
13451
|
+
landing.push(this.land(node, child, landed));
|
|
13354
13452
|
if (node.kept)
|
|
13355
|
-
this.standIn(node, landed,
|
|
13453
|
+
this.standIn(node, landed, landing);
|
|
13356
13454
|
return handles;
|
|
13357
13455
|
}
|
|
13358
13456
|
/**
|