@odoo/owl 3.0.0-alpha.33 → 3.0.0-alpha.34

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.cjs.js CHANGED
@@ -55,7 +55,6 @@ __export(index_exports, {
55
55
  onWillUnmount: () => onWillUnmount,
56
56
  onWillUpdateProps: () => onWillUpdateProps,
57
57
  plugin: () => plugin,
58
- prop: () => prop,
59
58
  props: () => props,
60
59
  providePlugins: () => providePlugins,
61
60
  proxy: () => proxy,
@@ -828,7 +827,7 @@ function createContext(issues, value, path, parent) {
828
827
  addIssue(issue) {
829
828
  issues.push({
830
829
  received: this.value,
831
- path: this.path,
830
+ path: this.path.join(" > "),
832
831
  ...issue
833
832
  });
834
833
  },
@@ -1202,6 +1201,13 @@ var Plugin = class {
1202
1201
  static set id(shadowId) {
1203
1202
  this._shadowId = shadowId;
1204
1203
  }
1204
+ // Plugins passed to `startPlugins` are started in batches of equal sequence,
1205
+ // ascending (lower first), like Resource/Registry. Each batch's onWillStart
1206
+ // callbacks fully settle before the next batch is instantiated, so
1207
+ // foundational plugins (low sequence) are ready before later plugins even
1208
+ // run their setup. Explicit `plugin(X)` dependencies bypass batching and
1209
+ // start immediately.
1210
+ static sequence = 50;
1205
1211
  __owl__;
1206
1212
  constructor(manager) {
1207
1213
  this.__owl__ = manager;
@@ -1212,11 +1218,13 @@ var Plugin = class {
1212
1218
  var PluginManager = class extends Scope {
1213
1219
  config;
1214
1220
  plugins;
1215
- // Resolves once all pending plugin willStart callbacks have settled. The
1216
- // scope transitions to MOUNTED as the last step of this chain. Consumers
1217
- // (the root's mount(), providePlugins) await this before treating the
1218
- // manager as ready. `willStart` itself is inherited from Scope.
1221
+ // Resolves once all batches of plugins have started and their willStart
1222
+ // callbacks have settled. The scope transitions to MOUNTED as the last step
1223
+ // of this chain. Consumers (the root's mount(), providePlugins) await this
1224
+ // before treating the manager as ready. `willStart` itself is inherited
1225
+ // from Scope.
1219
1226
  ready = Promise.resolve();
1227
+ hasPendingReady = false;
1220
1228
  constructor(app, options = {}) {
1221
1229
  super(app);
1222
1230
  this.config = options.config ?? {};
@@ -1257,24 +1265,61 @@ var PluginManager = class extends Scope {
1257
1265
  return plugin2;
1258
1266
  }
1259
1267
  startPlugins(pluginConstructors) {
1260
- scopeStack.push(this);
1261
- try {
1262
- for (const pluginConstructor of pluginConstructors) {
1263
- this.startPlugin(pluginConstructor);
1268
+ const fresh = pluginConstructors.filter((ctor) => {
1269
+ if (!ctor.id || this.plugins.hasOwnProperty(ctor.id)) {
1270
+ this.startPlugin(ctor);
1271
+ return false;
1264
1272
  }
1265
- } finally {
1266
- scopeStack.pop();
1273
+ return true;
1274
+ });
1275
+ if (!fresh.length) {
1276
+ return;
1267
1277
  }
1268
- const pending = this.willStart.splice(0);
1269
- if (pending.length) {
1270
- this.ready = Promise.all(pending.map((fn) => fn())).then(() => {
1271
- if (this.status < STATUS.MOUNTED) {
1272
- this.status = STATUS.MOUNTED;
1278
+ fresh.sort((p1, p2) => p1.sequence - p2.sequence);
1279
+ const batches = [];
1280
+ for (const ctor of fresh) {
1281
+ const batch = batches[batches.length - 1];
1282
+ if (batch && batch[0].sequence === ctor.sequence) {
1283
+ batch.push(ctor);
1284
+ } else {
1285
+ batches.push([ctor]);
1286
+ }
1287
+ }
1288
+ const startBatch = (batch) => {
1289
+ scopeStack.push(this);
1290
+ try {
1291
+ for (const ctor of batch) {
1292
+ this.startPlugin(ctor);
1273
1293
  }
1274
- });
1275
- } else if (this.status < STATUS.MOUNTED) {
1276
- this.status = STATUS.MOUNTED;
1294
+ } finally {
1295
+ scopeStack.pop();
1296
+ }
1297
+ const pending = this.willStart.splice(0);
1298
+ return pending.length ? Promise.all(pending.map((fn) => fn())) : null;
1299
+ };
1300
+ let chain = this.hasPendingReady ? this.ready : null;
1301
+ for (const batch of batches) {
1302
+ if (chain) {
1303
+ chain = chain.then(() => startBatch(batch));
1304
+ } else {
1305
+ chain = startBatch(batch);
1306
+ }
1277
1307
  }
1308
+ if (!chain) {
1309
+ if (this.status < STATUS.MOUNTED) {
1310
+ this.status = STATUS.MOUNTED;
1311
+ }
1312
+ return;
1313
+ }
1314
+ this.hasPendingReady = true;
1315
+ const ready = this.ready = chain.then(() => {
1316
+ if (this.status < STATUS.MOUNTED) {
1317
+ this.status = STATUS.MOUNTED;
1318
+ }
1319
+ if (this.ready === ready) {
1320
+ this.hasPendingReady = false;
1321
+ }
1322
+ });
1278
1323
  }
1279
1324
  };
1280
1325
  function startPlugins(manager, plugins) {
@@ -1385,7 +1430,7 @@ function markup(valueOrStrings, ...placeholders) {
1385
1430
  }
1386
1431
 
1387
1432
  // ../owl-runtime/dist/owl-runtime.es.js
1388
- var version = "3.0.0-alpha.33";
1433
+ var version = "3.0.0-alpha.34";
1389
1434
  var fibersInError = /* @__PURE__ */ new WeakMap();
1390
1435
  var nodeErrorHandlers = /* @__PURE__ */ new WeakMap();
1391
1436
  function invokeErrorHandlers(node, error, finalize, markFibers) {
@@ -1665,20 +1710,20 @@ function toClassObj(expr) {
1665
1710
  }
1666
1711
  }
1667
1712
  var CSS_PROP_CACHE = {};
1668
- function toKebabCase(prop2) {
1669
- if (prop2 in CSS_PROP_CACHE) {
1670
- return CSS_PROP_CACHE[prop2];
1713
+ function toKebabCase(prop) {
1714
+ if (prop in CSS_PROP_CACHE) {
1715
+ return CSS_PROP_CACHE[prop];
1671
1716
  }
1672
- const result = prop2.replace(/[A-Z]/g, (m) => "-" + m.toLowerCase());
1673
- CSS_PROP_CACHE[prop2] = result;
1717
+ const result = prop.replace(/[A-Z]/g, (m) => "-" + m.toLowerCase());
1718
+ CSS_PROP_CACHE[prop] = result;
1674
1719
  return result;
1675
1720
  }
1676
1721
  var IMPORTANT_RE = /\s*!\s*important\s*$/i;
1677
- function setStyleProp(style, prop2, value) {
1722
+ function setStyleProp(style, prop, value) {
1678
1723
  if (IMPORTANT_RE.test(value)) {
1679
- style.setProperty(prop2, value.replace(IMPORTANT_RE, ""), "important");
1724
+ style.setProperty(prop, value.replace(IMPORTANT_RE, ""), "important");
1680
1725
  } else {
1681
- style.setProperty(prop2, value);
1726
+ style.setProperty(prop, value);
1682
1727
  }
1683
1728
  }
1684
1729
  function toStyleObj(expr) {
@@ -1722,19 +1767,19 @@ function toStyleObj(expr) {
1722
1767
  if (colonIdx === -1) {
1723
1768
  continue;
1724
1769
  }
1725
- const prop2 = trim.call(part.slice(0, colonIdx));
1770
+ const prop = trim.call(part.slice(0, colonIdx));
1726
1771
  const value = trim.call(part.slice(colonIdx + 1));
1727
- if (prop2 && value && value !== "undefined") {
1728
- result[prop2] = value;
1772
+ if (prop && value && value !== "undefined") {
1773
+ result[prop] = value;
1729
1774
  }
1730
1775
  }
1731
1776
  return result;
1732
1777
  }
1733
1778
  case "object":
1734
- for (let prop2 in expr) {
1735
- const value = expr[prop2];
1779
+ for (let prop in expr) {
1780
+ const value = expr[prop];
1736
1781
  if (value || value === 0) {
1737
- result[toKebabCase(prop2)] = String(value);
1782
+ result[toKebabCase(prop)] = String(value);
1738
1783
  }
1739
1784
  }
1740
1785
  return result;
@@ -1765,22 +1810,22 @@ function updateClass(val, oldVal) {
1765
1810
  function setStyle(val) {
1766
1811
  val = val === "" ? {} : toStyleObj(val);
1767
1812
  const style = this.style;
1768
- for (let prop2 in val) {
1769
- setStyleProp(style, prop2, val[prop2]);
1813
+ for (let prop in val) {
1814
+ setStyleProp(style, prop, val[prop]);
1770
1815
  }
1771
1816
  }
1772
1817
  function updateStyle(val, oldVal) {
1773
1818
  oldVal = oldVal === "" ? {} : toStyleObj(oldVal);
1774
1819
  val = val === "" ? {} : toStyleObj(val);
1775
1820
  const style = this.style;
1776
- for (let prop2 in oldVal) {
1777
- if (!(prop2 in val)) {
1778
- style.removeProperty(prop2);
1821
+ for (let prop in oldVal) {
1822
+ if (!(prop in val)) {
1823
+ style.removeProperty(prop);
1779
1824
  }
1780
1825
  }
1781
- for (let prop2 in val) {
1782
- if (val[prop2] !== oldVal[prop2]) {
1783
- setStyleProp(style, prop2, val[prop2]);
1826
+ for (let prop in val) {
1827
+ if (val[prop] !== oldVal[prop]) {
1828
+ setStyleProp(style, prop, val[prop]);
1784
1829
  }
1785
1830
  }
1786
1831
  if (!style.cssText) {
@@ -3272,6 +3317,10 @@ var ComponentNode = class extends Scope {
3272
3317
  parent;
3273
3318
  children = /* @__PURE__ */ Object.create(null);
3274
3319
  willUpdateProps = [];
3320
+ // Fired right after `props` is applied to `node.props` on a parent re-render,
3321
+ // so reactive prop notifications happen once the new values are observable
3322
+ // (after user `onWillUpdateProps` hooks, including async ones, have run).
3323
+ propsUpdated = [];
3275
3324
  willUnmount = [];
3276
3325
  mounted = [];
3277
3326
  willPatch = [];
@@ -3806,6 +3855,7 @@ function createComponent(app, name, isStatic, hasSlotsProp, hasDynamicPropList,
3806
3855
  () => {
3807
3856
  if (fiber !== node.fiber) return;
3808
3857
  node.props = props2;
3858
+ for (const f of node.propsUpdated) f();
3809
3859
  fiber.render();
3810
3860
  },
3811
3861
  (error) => {
@@ -3814,6 +3864,7 @@ function createComponent(app, name, isStatic, hasSlotsProp, hasDynamicPropList,
3814
3864
  );
3815
3865
  } else {
3816
3866
  node.props = props2;
3867
+ for (const f of node.propsUpdated) f();
3817
3868
  fiber.render();
3818
3869
  }
3819
3870
  }
@@ -4186,6 +4237,24 @@ function onError(callback) {
4186
4237
  }
4187
4238
  handlers.push(callback.bind(scope.component));
4188
4239
  }
4240
+ function staticProp(key, type, ...args) {
4241
+ const node = getComponentScope();
4242
+ const hasDefault = args.length > 0;
4243
+ const propValue = node.props[key];
4244
+ if (node.app.dev) {
4245
+ if (type !== void 0 && (!hasDefault || propValue !== void 0)) {
4246
+ assertType(propValue, type, `Invalid prop '${key}' in '${node.componentName}'`);
4247
+ }
4248
+ node.willUpdateProps.push((nextProps) => {
4249
+ if (nextProps[key] !== node.props[key]) {
4250
+ throw new OwlError(
4251
+ `Prop '${key}' changed in component '${node.componentName}'. Props declared with \`props.static()\` are static and should not change. If the prop is a signal, pass the same signal reference (its inner value may change).`
4252
+ );
4253
+ }
4254
+ });
4255
+ }
4256
+ return propValue === void 0 && hasDefault ? args[0] : propValue;
4257
+ }
4189
4258
  function componentType() {
4190
4259
  return constructorType(Component);
4191
4260
  }
@@ -4207,35 +4276,51 @@ function validateDefaults(schema) {
4207
4276
  }
4208
4277
  return types2.strictObject(validation);
4209
4278
  }
4210
- function props(type, defaults) {
4279
+ function makeProps(type, defaults) {
4211
4280
  const node = getComponentScope();
4212
4281
  const { app, componentName } = node;
4213
4282
  if (defaults) {
4214
4283
  node.defaultProps = Object.assign(node.defaultProps || {}, defaults);
4215
4284
  }
4216
- function getProp(key) {
4217
- if (node.props[key] === void 0 && defaults) {
4285
+ function resolveValue(props2, key) {
4286
+ if (props2[key] === void 0 && defaults) {
4218
4287
  return defaults[key];
4219
4288
  }
4220
- return node.props[key];
4289
+ return props2[key];
4221
4290
  }
4291
+ const signals = /* @__PURE__ */ Object.create(null);
4222
4292
  const result = /* @__PURE__ */ Object.create(null);
4223
- function applyPropGetters(keys) {
4293
+ function defineProp(key) {
4294
+ signals[key] = signal(resolveValue(node.props, key));
4295
+ Reflect.defineProperty(result, key, {
4296
+ enumerable: true,
4297
+ configurable: true,
4298
+ get: signals[key]
4299
+ });
4300
+ }
4301
+ function defineProps(keys) {
4224
4302
  for (const key of keys) {
4225
- Reflect.defineProperty(result, key, {
4226
- enumerable: true,
4227
- get: getProp.bind(null, key)
4228
- });
4303
+ defineProp(key);
4304
+ }
4305
+ }
4306
+ function updateSignals(keys) {
4307
+ for (const key of keys) {
4308
+ signals[key].set(resolveValue(node.props, key));
4229
4309
  }
4230
4310
  }
4231
4311
  if (type) {
4232
4312
  const keys = (Array.isArray(type) ? type : Object.keys(type)).map(
4233
4313
  (key) => key.endsWith("?") ? key.slice(0, -1) : key
4234
4314
  );
4235
- applyPropGetters(keys);
4315
+ defineProps(keys);
4316
+ node.propsUpdated.push(() => updateSignals(keys));
4236
4317
  if (app.dev) {
4237
4318
  if (defaults) {
4238
- assertType(defaults, validateDefaults(type), `Invalid component default props (${componentName})`);
4319
+ assertType(
4320
+ defaults,
4321
+ validateDefaults(type),
4322
+ `Invalid component default props (${componentName})`
4323
+ );
4239
4324
  }
4240
4325
  const validation = types2.object(type);
4241
4326
  assertType(node.props, validation, `Invalid component props (${componentName})`);
@@ -4261,17 +4346,28 @@ function props(type, defaults) {
4261
4346
  return keys2;
4262
4347
  };
4263
4348
  let keys = getKeys(node.props);
4264
- applyPropGetters(keys);
4265
- node.willUpdateProps.push((np) => {
4349
+ defineProps(keys);
4350
+ node.propsUpdated.push(() => {
4351
+ const nextKeys = getKeys(node.props);
4352
+ const nextKeySet = new Set(nextKeys);
4266
4353
  for (const key of keys) {
4267
- Reflect.deleteProperty(result, key);
4354
+ if (!nextKeySet.has(key)) {
4355
+ Reflect.deleteProperty(result, key);
4356
+ delete signals[key];
4357
+ }
4358
+ }
4359
+ for (const key of nextKeys) {
4360
+ if (!(key in signals)) {
4361
+ defineProp(key);
4362
+ }
4268
4363
  }
4269
- keys = getKeys(np);
4270
- applyPropGetters(keys);
4364
+ updateSignals(nextKeys);
4365
+ keys = nextKeys;
4271
4366
  });
4272
4367
  }
4273
4368
  return result;
4274
4369
  }
4370
+ var props = Object.assign(makeProps, { static: staticProp });
4275
4371
  var ErrorBoundary = class extends Component {
4276
4372
  static template = xml`
4277
4373
  <t t-if="this.props.error()">
@@ -4370,24 +4466,6 @@ var Suspense = class extends Component {
4370
4466
  onWillDestroy(() => root.destroy());
4371
4467
  }
4372
4468
  };
4373
- function prop(key, type, ...args) {
4374
- const node = getComponentScope();
4375
- const hasDefault = args.length > 0;
4376
- const propValue = node.props[key];
4377
- if (node.app.dev) {
4378
- if (type !== void 0 && (!hasDefault || propValue !== void 0)) {
4379
- assertType(propValue, type, `Invalid prop '${key}' in '${node.componentName}'`);
4380
- }
4381
- node.willUpdateProps.push((nextProps) => {
4382
- if (nextProps[key] !== node.props[key]) {
4383
- throw new OwlError(
4384
- `Prop '${key}' changed in component '${node.componentName}'. Props declared with \`prop()\` are static and should not change. If the prop is a signal, pass the same signal reference (its inner value may change).`
4385
- );
4386
- }
4387
- });
4388
- }
4389
- return propValue === void 0 && hasDefault ? args[0] : propValue;
4390
- }
4391
4469
  function providePlugins(pluginConstructors, config3) {
4392
4470
  const node = getComponentScope();
4393
4471
  const manager = new PluginManager(node.app, { parent: node.pluginManager, config: config3 });
@@ -4416,8 +4494,8 @@ var blockDom = {
4416
4494
  };
4417
4495
  var __info__ = {
4418
4496
  version: App.version,
4419
- date: "2026-05-28T13:29:02.340Z",
4420
- hash: "fadc22b7",
4497
+ date: "2026-06-05T08:44:38.319Z",
4498
+ hash: "3206cf27",
4421
4499
  url: "https://github.com/odoo/owl"
4422
4500
  };
4423
4501