@odoo/owl 3.0.0-alpha.40 → 3.0.0-alpha.42

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/owl.es.js CHANGED
@@ -339,18 +339,15 @@ function getTargetKeyAtom(target, key) {
339
339
  function onReadTargetKey(target, key, atom) {
340
340
  onReadAtom(atom ?? getTargetKeyAtom(target, key));
341
341
  }
342
- function onWriteTargetKey(target, key, atom) {
343
- if (!atom) {
344
- const keyToAtomItem = targetToKeysToAtomItem.get(target);
345
- if (!keyToAtomItem) {
346
- return;
347
- }
348
- if (!keyToAtomItem.has(key)) {
349
- return;
350
- }
351
- atom = keyToAtomItem.get(key);
342
+ function onWriteTargetKey(target, key) {
343
+ const keyToAtomItem = targetToKeysToAtomItem.get(target);
344
+ if (!keyToAtomItem) {
345
+ return;
346
+ }
347
+ if (!keyToAtomItem.has(key)) {
348
+ return;
352
349
  }
353
- onWriteAtom(atom);
350
+ onWriteAtom(keyToAtomItem.get(key));
354
351
  }
355
352
  var targets = /* @__PURE__ */ new WeakMap();
356
353
  var proxyCache = /* @__PURE__ */ new WeakMap();
@@ -407,18 +404,30 @@ function basicProxyHandler(atom) {
407
404
  const hadKey = objectHasOwnProperty.call(target, key);
408
405
  const originalValue = Reflect.get(target, key, receiver);
409
406
  const ret = Reflect.set(target, key, toRaw(value), receiver);
410
- if (!hadKey && objectHasOwnProperty.call(target, key)) {
411
- onWriteTargetKey(target, KEYCHANGES, atom);
412
- }
413
- if (originalValue !== Reflect.get(target, key, receiver) || key === "length" && Array.isArray(target)) {
414
- onWriteTargetKey(target, key, atom);
407
+ const keyCreated = !hadKey && objectHasOwnProperty.call(target, key);
408
+ const valueChanged = originalValue !== Reflect.get(target, key, receiver);
409
+ if (atom) {
410
+ if (keyCreated || valueChanged) {
411
+ onWriteAtom(atom);
412
+ }
413
+ } else {
414
+ if (keyCreated) {
415
+ onWriteTargetKey(target, KEYCHANGES);
416
+ }
417
+ if (valueChanged || key === "length" && Array.isArray(target)) {
418
+ onWriteTargetKey(target, key);
419
+ }
415
420
  }
416
421
  return ret;
417
422
  },
418
423
  deleteProperty(target, key) {
419
424
  const ret = Reflect.deleteProperty(target, key);
420
- onWriteTargetKey(target, KEYCHANGES, atom);
421
- onWriteTargetKey(target, key, atom);
425
+ if (atom) {
426
+ onWriteAtom(atom);
427
+ } else {
428
+ onWriteTargetKey(target, KEYCHANGES);
429
+ onWriteTargetKey(target, key);
430
+ }
422
431
  return ret;
423
432
  },
424
433
  ownKeys(target) {
@@ -434,26 +443,26 @@ function basicProxyHandler(atom) {
434
443
  function makeKeyObserver(methodName, target, atom) {
435
444
  return (key) => {
436
445
  key = toRaw(key);
437
- onReadTargetKey(target, key, atom);
446
+ onReadTargetKey(target, key, null);
438
447
  return possiblyReactive(target[methodName](key), atom);
439
448
  };
440
449
  }
441
450
  function makeIteratorObserver(methodName, target, atom) {
442
451
  return function* () {
443
- onReadTargetKey(target, KEYCHANGES, atom);
452
+ onReadTargetKey(target, KEYCHANGES, null);
444
453
  const keys = target.keys();
445
454
  for (const item of target[methodName]()) {
446
455
  const key = keys.next().value;
447
- onReadTargetKey(target, key, atom);
456
+ onReadTargetKey(target, key, null);
448
457
  yield possiblyReactive(item, atom);
449
458
  }
450
459
  };
451
460
  }
452
461
  function makeForEachObserver(target, atom) {
453
462
  return function forEach(forEachCb, thisArg) {
454
- onReadTargetKey(target, KEYCHANGES, atom);
463
+ onReadTargetKey(target, KEYCHANGES, null);
455
464
  target.forEach(function(val, key, targetObj) {
456
- onReadTargetKey(target, key, atom);
465
+ onReadTargetKey(target, key, null);
457
466
  forEachCb.call(
458
467
  thisArg,
459
468
  possiblyReactive(val, atom),
@@ -463,7 +472,7 @@ function makeForEachObserver(target, atom) {
463
472
  }, thisArg);
464
473
  };
465
474
  }
466
- function delegateAndNotify(setterName, getterName, target, atom) {
475
+ function delegateAndNotify(setterName, getterName, target) {
467
476
  return (key, value) => {
468
477
  key = toRaw(key);
469
478
  const hadKey = target.has(key);
@@ -471,61 +480,61 @@ function delegateAndNotify(setterName, getterName, target, atom) {
471
480
  const ret = target[setterName](key, value);
472
481
  const hasKey = target.has(key);
473
482
  if (hadKey !== hasKey) {
474
- onWriteTargetKey(target, KEYCHANGES, atom);
483
+ onWriteTargetKey(target, KEYCHANGES);
475
484
  }
476
485
  if (originalValue !== target[getterName](key)) {
477
- onWriteTargetKey(target, key, atom);
486
+ onWriteTargetKey(target, key);
478
487
  }
479
488
  return ret;
480
489
  };
481
490
  }
482
- function makeClearNotifier(target, atom) {
491
+ function makeClearNotifier(target) {
483
492
  return () => {
484
493
  const allKeys = [...target.keys()];
485
494
  target.clear();
486
- onWriteTargetKey(target, KEYCHANGES, atom);
495
+ onWriteTargetKey(target, KEYCHANGES);
487
496
  for (const key of allKeys) {
488
- onWriteTargetKey(target, key, atom);
497
+ onWriteTargetKey(target, key);
489
498
  }
490
499
  };
491
500
  }
492
501
  var rawTypeToFuncHandlers = {
493
502
  Set: (target, atom) => ({
494
503
  has: makeKeyObserver("has", target, atom),
495
- add: delegateAndNotify("add", "has", target, atom),
496
- delete: delegateAndNotify("delete", "has", target, atom),
504
+ add: delegateAndNotify("add", "has", target),
505
+ delete: delegateAndNotify("delete", "has", target),
497
506
  keys: makeIteratorObserver("keys", target, atom),
498
507
  values: makeIteratorObserver("values", target, atom),
499
508
  entries: makeIteratorObserver("entries", target, atom),
500
509
  [Symbol.iterator]: makeIteratorObserver(Symbol.iterator, target, atom),
501
510
  forEach: makeForEachObserver(target, atom),
502
- clear: makeClearNotifier(target, atom),
511
+ clear: makeClearNotifier(target),
503
512
  get size() {
504
- onReadTargetKey(target, KEYCHANGES, atom);
513
+ onReadTargetKey(target, KEYCHANGES, null);
505
514
  return target.size;
506
515
  }
507
516
  }),
508
517
  Map: (target, atom) => ({
509
518
  has: makeKeyObserver("has", target, atom),
510
519
  get: makeKeyObserver("get", target, atom),
511
- set: delegateAndNotify("set", "get", target, atom),
512
- delete: delegateAndNotify("delete", "has", target, atom),
520
+ set: delegateAndNotify("set", "get", target),
521
+ delete: delegateAndNotify("delete", "has", target),
513
522
  keys: makeIteratorObserver("keys", target, atom),
514
523
  values: makeIteratorObserver("values", target, atom),
515
524
  entries: makeIteratorObserver("entries", target, atom),
516
525
  [Symbol.iterator]: makeIteratorObserver(Symbol.iterator, target, atom),
517
526
  forEach: makeForEachObserver(target, atom),
518
- clear: makeClearNotifier(target, atom),
527
+ clear: makeClearNotifier(target),
519
528
  get size() {
520
- onReadTargetKey(target, KEYCHANGES, atom);
529
+ onReadTargetKey(target, KEYCHANGES, null);
521
530
  return target.size;
522
531
  }
523
532
  }),
524
533
  WeakMap: (target, atom) => ({
525
534
  has: makeKeyObserver("has", target, atom),
526
535
  get: makeKeyObserver("get", target, atom),
527
- set: delegateAndNotify("set", "get", target, atom),
528
- delete: delegateAndNotify("delete", "has", target, atom)
536
+ set: delegateAndNotify("set", "get", target),
537
+ delete: delegateAndNotify("delete", "has", target)
529
538
  })
530
539
  };
531
540
  function collectionsProxyHandler(target, targetRawType, atom) {
@@ -572,16 +581,16 @@ function triggerSignal(signal2) {
572
581
  function signalRef() {
573
582
  return buildSignal(null, (atom) => atom.value);
574
583
  }
575
- function signalArray(initialValue) {
584
+ function signalArray(initialValue = []) {
576
585
  return buildSignal(initialValue, (atom) => proxifyTarget(atom.value, atom));
577
586
  }
578
- function signalObject(initialValue) {
587
+ function signalObject(initialValue = {}) {
579
588
  return buildSignal(initialValue, (atom) => proxifyTarget(atom.value, atom));
580
589
  }
581
- function signalMap(initialValue) {
590
+ function signalMap(initialValue = /* @__PURE__ */ new Map()) {
582
591
  return buildSignal(initialValue, (atom) => proxifyTarget(atom.value, atom));
583
592
  }
584
- function signalSet(initialValue) {
593
+ function signalSet(initialValue = /* @__PURE__ */ new Set()) {
585
594
  return buildSignal(initialValue, (atom) => proxifyTarget(atom.value, atom));
586
595
  }
587
596
  function signal(value) {
@@ -976,6 +985,16 @@ function intersection(types22) {
976
985
  }
977
986
  });
978
987
  validate[intersectionSymbol] = types22;
988
+ validate.toShape = () => {
989
+ const shape = {};
990
+ for (const member of types22) {
991
+ const memberShape = typeof member.toShape === "function" ? member.toShape() : void 0;
992
+ if (memberShape && !Array.isArray(memberShape)) {
993
+ Object.assign(shape, memberShape);
994
+ }
995
+ }
996
+ return shape;
997
+ };
979
998
  return validate;
980
999
  }
981
1000
  function literalType(literal) {
@@ -1051,6 +1070,7 @@ function objectType(schema = {}) {
1051
1070
  if (!Array.isArray(schema)) {
1052
1071
  validate[shapeSymbol] = schema;
1053
1072
  }
1073
+ validate.toShape = () => schema;
1054
1074
  return validate;
1055
1075
  }
1056
1076
  function strictObjectType(schema) {
@@ -1060,6 +1080,7 @@ function strictObjectType(schema) {
1060
1080
  if (!Array.isArray(schema)) {
1061
1081
  validate[shapeSymbol] = schema;
1062
1082
  }
1083
+ validate.toShape = () => schema;
1063
1084
  return validate;
1064
1085
  }
1065
1086
  function promiseType(type) {
@@ -1487,7 +1508,7 @@ function markup(valueOrStrings, ...placeholders) {
1487
1508
  }
1488
1509
 
1489
1510
  // ../owl-runtime/dist/owl-runtime.es.js
1490
- var version = "3.0.0-alpha.40";
1511
+ var version = "3.0.0-alpha.42";
1491
1512
  var fibersInError = /* @__PURE__ */ new WeakMap();
1492
1513
  var nodeErrorHandlers = /* @__PURE__ */ new WeakMap();
1493
1514
  function invokeErrorHandlers(node, error, finalize, markFibers) {
@@ -1880,9 +1901,11 @@ function updateStyle(val, oldVal) {
1880
1901
  style.removeProperty(prop);
1881
1902
  }
1882
1903
  }
1904
+ let changed = false;
1883
1905
  for (let prop in val) {
1884
- if (val[prop] !== oldVal[prop]) {
1906
+ if (changed || val[prop] !== oldVal[prop]) {
1885
1907
  setStyleProp(style, prop, val[prop]);
1908
+ changed = true;
1886
1909
  }
1887
1910
  }
1888
1911
  if (!style.cssText) {
@@ -3109,6 +3132,7 @@ function status(entity) {
3109
3132
  return "destroyed";
3110
3133
  }
3111
3134
  }
3135
+ var MAX_RENDER_ITERATIONS = 1e3;
3112
3136
  function makeChildFiber(node, parent) {
3113
3137
  let current = node.fiber;
3114
3138
  if (current) {
@@ -3121,6 +3145,7 @@ function makeRootFiber(node) {
3121
3145
  let current = node.fiber;
3122
3146
  if (current) {
3123
3147
  let root = current.root;
3148
+ root.renderCount++;
3124
3149
  root.locked = true;
3125
3150
  root.setCounter(root.counter + 1 - cancelFibers(current.children));
3126
3151
  root.locked = false;
@@ -3215,6 +3240,15 @@ var Fiber = class {
3215
3240
  const node = this.node;
3216
3241
  const root = this.root;
3217
3242
  if (root) {
3243
+ if (root.renderCount > MAX_RENDER_ITERATIONS) {
3244
+ handleError({
3245
+ node,
3246
+ error: new OwlError(
3247
+ `Maximum render iterations (${MAX_RENDER_ITERATIONS}) exceeded. Component "${node.componentName}" is stuck in a render loop: rendering it keeps triggering another render before the DOM is updated. A common cause is updating reactive state during render or setup() \u2014 e.g. calling a parent's state setter from a child's setup().`
3248
+ )
3249
+ });
3250
+ return;
3251
+ }
3218
3252
  const c = getCurrentComputation();
3219
3253
  removeSources(node.signalComputation);
3220
3254
  setComputation(node.signalComputation);
@@ -3237,6 +3271,9 @@ var Fiber = class {
3237
3271
  };
3238
3272
  var RootFiber = class extends Fiber {
3239
3273
  counter = 1;
3274
+ // Number of times this (uncommitted) fiber has been recycled by makeRootFiber.
3275
+ // Climbs without bound only in a render loop; see issue #1968.
3276
+ renderCount = 0;
3240
3277
  // only add stuff in this if they have registered some hooks
3241
3278
  willPatch = [];
3242
3279
  patched = [];
@@ -4218,6 +4255,13 @@ var App = class _App extends TemplateSet {
4218
4255
  let error = null;
4219
4256
  try {
4220
4257
  node = new ComponentNode(Root, props2, this, null, null);
4258
+ const subConfig = config3;
4259
+ if (subConfig.pluginManager) {
4260
+ node.pluginManager = subConfig.pluginManager;
4261
+ }
4262
+ if (subConfig.onError) {
4263
+ nodeErrorHandlers.set(node, [subConfig.onError]);
4264
+ }
4221
4265
  } catch (e) {
4222
4266
  error = e;
4223
4267
  reject(e);
@@ -4278,7 +4322,9 @@ var App = class _App extends TemplateSet {
4278
4322
  return promise;
4279
4323
  };
4280
4324
  const root = {
4281
- node,
4325
+ get prepared() {
4326
+ return fiber ? fiber.counter === 0 : false;
4327
+ },
4282
4328
  promise,
4283
4329
  prepare,
4284
4330
  mount: mount3,
@@ -4308,6 +4354,9 @@ var App = class _App extends TemplateSet {
4308
4354
  };
4309
4355
  async function mount2(C, target, config3 = {}) {
4310
4356
  const app = new App(config3);
4357
+ if (app.pluginManager.status < STATUS.MOUNTED) {
4358
+ await app.pluginManager.ready;
4359
+ }
4311
4360
  const root = app.createRoot(C, config3);
4312
4361
  return root.mount(target, config3);
4313
4362
  }
@@ -4544,9 +4593,18 @@ var Portal = class extends Component {
4544
4593
  if (!target) {
4545
4594
  return;
4546
4595
  }
4547
- root = app.createRoot(PortalContent, { props: { slots } });
4548
- root.node.pluginManager = portalNode.pluginManager;
4549
- nodeErrorHandlers.set(root.node, [forwardErrorToParent(portalNode)]);
4596
+ root = app.createRoot(PortalContent, {
4597
+ props: { slots },
4598
+ // Forward the plugin chain from this Portal (createRoot defaults
4599
+ // sub-roots to the app-level plugin manager) so `providePlugins`
4600
+ // contributions from ancestors are visible inside the portaled content.
4601
+ pluginManager: portalNode.pluginManager,
4602
+ // Route errors from the portaled subtree back through Portal's parent
4603
+ // chain so consumer `onError` handlers still catch them. Without this,
4604
+ // sub-root errors would propagate to app._handleError and tear down
4605
+ // the whole app.
4606
+ onError: forwardErrorToParent(portalNode)
4607
+ });
4550
4608
  root.mount(target);
4551
4609
  return tearDown;
4552
4610
  });
@@ -4581,13 +4639,18 @@ var Suspense = class extends Component {
4581
4639
  setup() {
4582
4640
  const suspenseNode = this.__owl__;
4583
4641
  const root = suspenseNode.app.createRoot(SuspenseHost, {
4584
- props: { slots: this.props.slots }
4642
+ props: { slots: this.props.slots },
4643
+ // Thread the plugin manager so `providePlugins` contributions from
4644
+ // ancestors are visible inside the default slot. (createRoot defaults
4645
+ // sub-roots to the app-level plugin manager; override here.) Destroy
4646
+ // cascade is handled explicitly below via `onWillDestroy`.
4647
+ pluginManager: suspenseNode.pluginManager,
4648
+ // Route errors from the sub-root back into Suspense's parent chain so
4649
+ // consumer `onError` handlers still catch descendant failures.
4650
+ onError: forwardErrorToParent(suspenseNode)
4585
4651
  });
4586
- root.node.pluginManager = suspenseNode.pluginManager;
4587
- nodeErrorHandlers.set(root.node, [forwardErrorToParent(suspenseNode)]);
4588
4652
  root.prepare().then(() => this.prepared.set(true));
4589
- const fiber = root.node.fiber;
4590
- if (fiber && fiber.counter === 0) {
4653
+ if (root.prepared) {
4591
4654
  this.prepared.set(true);
4592
4655
  }
4593
4656
  onMounted(() => this.mounted.set(true));
@@ -4630,8 +4693,8 @@ var blockDom = {
4630
4693
  };
4631
4694
  var __info__ = {
4632
4695
  version: App.version,
4633
- date: "2026-06-26T12:29:22.680Z",
4634
- hash: "5565ac15",
4696
+ date: "2026-07-07T08:36:25.562Z",
4697
+ hash: "1d192035",
4635
4698
  url: "https://github.com/odoo/owl"
4636
4699
  };
4637
4700