@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.es.js CHANGED
@@ -752,7 +752,7 @@ function createContext(issues, value, path, parent) {
752
752
  addIssue(issue) {
753
753
  issues.push({
754
754
  received: this.value,
755
- path: this.path,
755
+ path: this.path.join(" > "),
756
756
  ...issue
757
757
  });
758
758
  },
@@ -1126,6 +1126,13 @@ var Plugin = class {
1126
1126
  static set id(shadowId) {
1127
1127
  this._shadowId = shadowId;
1128
1128
  }
1129
+ // Plugins passed to `startPlugins` are started in batches of equal sequence,
1130
+ // ascending (lower first), like Resource/Registry. Each batch's onWillStart
1131
+ // callbacks fully settle before the next batch is instantiated, so
1132
+ // foundational plugins (low sequence) are ready before later plugins even
1133
+ // run their setup. Explicit `plugin(X)` dependencies bypass batching and
1134
+ // start immediately.
1135
+ static sequence = 50;
1129
1136
  __owl__;
1130
1137
  constructor(manager) {
1131
1138
  this.__owl__ = manager;
@@ -1136,11 +1143,13 @@ var Plugin = class {
1136
1143
  var PluginManager = class extends Scope {
1137
1144
  config;
1138
1145
  plugins;
1139
- // Resolves once all pending plugin willStart callbacks have settled. The
1140
- // scope transitions to MOUNTED as the last step of this chain. Consumers
1141
- // (the root's mount(), providePlugins) await this before treating the
1142
- // manager as ready. `willStart` itself is inherited from Scope.
1146
+ // Resolves once all batches of plugins have started and their willStart
1147
+ // callbacks have settled. The scope transitions to MOUNTED as the last step
1148
+ // of this chain. Consumers (the root's mount(), providePlugins) await this
1149
+ // before treating the manager as ready. `willStart` itself is inherited
1150
+ // from Scope.
1143
1151
  ready = Promise.resolve();
1152
+ hasPendingReady = false;
1144
1153
  constructor(app, options = {}) {
1145
1154
  super(app);
1146
1155
  this.config = options.config ?? {};
@@ -1181,24 +1190,61 @@ var PluginManager = class extends Scope {
1181
1190
  return plugin2;
1182
1191
  }
1183
1192
  startPlugins(pluginConstructors) {
1184
- scopeStack.push(this);
1185
- try {
1186
- for (const pluginConstructor of pluginConstructors) {
1187
- this.startPlugin(pluginConstructor);
1193
+ const fresh = pluginConstructors.filter((ctor) => {
1194
+ if (!ctor.id || this.plugins.hasOwnProperty(ctor.id)) {
1195
+ this.startPlugin(ctor);
1196
+ return false;
1188
1197
  }
1189
- } finally {
1190
- scopeStack.pop();
1198
+ return true;
1199
+ });
1200
+ if (!fresh.length) {
1201
+ return;
1191
1202
  }
1192
- const pending = this.willStart.splice(0);
1193
- if (pending.length) {
1194
- this.ready = Promise.all(pending.map((fn) => fn())).then(() => {
1195
- if (this.status < STATUS.MOUNTED) {
1196
- this.status = STATUS.MOUNTED;
1203
+ fresh.sort((p1, p2) => p1.sequence - p2.sequence);
1204
+ const batches = [];
1205
+ for (const ctor of fresh) {
1206
+ const batch = batches[batches.length - 1];
1207
+ if (batch && batch[0].sequence === ctor.sequence) {
1208
+ batch.push(ctor);
1209
+ } else {
1210
+ batches.push([ctor]);
1211
+ }
1212
+ }
1213
+ const startBatch = (batch) => {
1214
+ scopeStack.push(this);
1215
+ try {
1216
+ for (const ctor of batch) {
1217
+ this.startPlugin(ctor);
1197
1218
  }
1198
- });
1199
- } else if (this.status < STATUS.MOUNTED) {
1200
- this.status = STATUS.MOUNTED;
1219
+ } finally {
1220
+ scopeStack.pop();
1221
+ }
1222
+ const pending = this.willStart.splice(0);
1223
+ return pending.length ? Promise.all(pending.map((fn) => fn())) : null;
1224
+ };
1225
+ let chain = this.hasPendingReady ? this.ready : null;
1226
+ for (const batch of batches) {
1227
+ if (chain) {
1228
+ chain = chain.then(() => startBatch(batch));
1229
+ } else {
1230
+ chain = startBatch(batch);
1231
+ }
1201
1232
  }
1233
+ if (!chain) {
1234
+ if (this.status < STATUS.MOUNTED) {
1235
+ this.status = STATUS.MOUNTED;
1236
+ }
1237
+ return;
1238
+ }
1239
+ this.hasPendingReady = true;
1240
+ const ready = this.ready = chain.then(() => {
1241
+ if (this.status < STATUS.MOUNTED) {
1242
+ this.status = STATUS.MOUNTED;
1243
+ }
1244
+ if (this.ready === ready) {
1245
+ this.hasPendingReady = false;
1246
+ }
1247
+ });
1202
1248
  }
1203
1249
  };
1204
1250
  function startPlugins(manager, plugins) {
@@ -1309,7 +1355,7 @@ function markup(valueOrStrings, ...placeholders) {
1309
1355
  }
1310
1356
 
1311
1357
  // ../owl-runtime/dist/owl-runtime.es.js
1312
- var version = "3.0.0-alpha.33";
1358
+ var version = "3.0.0-alpha.34";
1313
1359
  var fibersInError = /* @__PURE__ */ new WeakMap();
1314
1360
  var nodeErrorHandlers = /* @__PURE__ */ new WeakMap();
1315
1361
  function invokeErrorHandlers(node, error, finalize, markFibers) {
@@ -1589,20 +1635,20 @@ function toClassObj(expr) {
1589
1635
  }
1590
1636
  }
1591
1637
  var CSS_PROP_CACHE = {};
1592
- function toKebabCase(prop2) {
1593
- if (prop2 in CSS_PROP_CACHE) {
1594
- return CSS_PROP_CACHE[prop2];
1638
+ function toKebabCase(prop) {
1639
+ if (prop in CSS_PROP_CACHE) {
1640
+ return CSS_PROP_CACHE[prop];
1595
1641
  }
1596
- const result = prop2.replace(/[A-Z]/g, (m) => "-" + m.toLowerCase());
1597
- CSS_PROP_CACHE[prop2] = result;
1642
+ const result = prop.replace(/[A-Z]/g, (m) => "-" + m.toLowerCase());
1643
+ CSS_PROP_CACHE[prop] = result;
1598
1644
  return result;
1599
1645
  }
1600
1646
  var IMPORTANT_RE = /\s*!\s*important\s*$/i;
1601
- function setStyleProp(style, prop2, value) {
1647
+ function setStyleProp(style, prop, value) {
1602
1648
  if (IMPORTANT_RE.test(value)) {
1603
- style.setProperty(prop2, value.replace(IMPORTANT_RE, ""), "important");
1649
+ style.setProperty(prop, value.replace(IMPORTANT_RE, ""), "important");
1604
1650
  } else {
1605
- style.setProperty(prop2, value);
1651
+ style.setProperty(prop, value);
1606
1652
  }
1607
1653
  }
1608
1654
  function toStyleObj(expr) {
@@ -1646,19 +1692,19 @@ function toStyleObj(expr) {
1646
1692
  if (colonIdx === -1) {
1647
1693
  continue;
1648
1694
  }
1649
- const prop2 = trim.call(part.slice(0, colonIdx));
1695
+ const prop = trim.call(part.slice(0, colonIdx));
1650
1696
  const value = trim.call(part.slice(colonIdx + 1));
1651
- if (prop2 && value && value !== "undefined") {
1652
- result[prop2] = value;
1697
+ if (prop && value && value !== "undefined") {
1698
+ result[prop] = value;
1653
1699
  }
1654
1700
  }
1655
1701
  return result;
1656
1702
  }
1657
1703
  case "object":
1658
- for (let prop2 in expr) {
1659
- const value = expr[prop2];
1704
+ for (let prop in expr) {
1705
+ const value = expr[prop];
1660
1706
  if (value || value === 0) {
1661
- result[toKebabCase(prop2)] = String(value);
1707
+ result[toKebabCase(prop)] = String(value);
1662
1708
  }
1663
1709
  }
1664
1710
  return result;
@@ -1689,22 +1735,22 @@ function updateClass(val, oldVal) {
1689
1735
  function setStyle(val) {
1690
1736
  val = val === "" ? {} : toStyleObj(val);
1691
1737
  const style = this.style;
1692
- for (let prop2 in val) {
1693
- setStyleProp(style, prop2, val[prop2]);
1738
+ for (let prop in val) {
1739
+ setStyleProp(style, prop, val[prop]);
1694
1740
  }
1695
1741
  }
1696
1742
  function updateStyle(val, oldVal) {
1697
1743
  oldVal = oldVal === "" ? {} : toStyleObj(oldVal);
1698
1744
  val = val === "" ? {} : toStyleObj(val);
1699
1745
  const style = this.style;
1700
- for (let prop2 in oldVal) {
1701
- if (!(prop2 in val)) {
1702
- style.removeProperty(prop2);
1746
+ for (let prop in oldVal) {
1747
+ if (!(prop in val)) {
1748
+ style.removeProperty(prop);
1703
1749
  }
1704
1750
  }
1705
- for (let prop2 in val) {
1706
- if (val[prop2] !== oldVal[prop2]) {
1707
- setStyleProp(style, prop2, val[prop2]);
1751
+ for (let prop in val) {
1752
+ if (val[prop] !== oldVal[prop]) {
1753
+ setStyleProp(style, prop, val[prop]);
1708
1754
  }
1709
1755
  }
1710
1756
  if (!style.cssText) {
@@ -3196,6 +3242,10 @@ var ComponentNode = class extends Scope {
3196
3242
  parent;
3197
3243
  children = /* @__PURE__ */ Object.create(null);
3198
3244
  willUpdateProps = [];
3245
+ // Fired right after `props` is applied to `node.props` on a parent re-render,
3246
+ // so reactive prop notifications happen once the new values are observable
3247
+ // (after user `onWillUpdateProps` hooks, including async ones, have run).
3248
+ propsUpdated = [];
3199
3249
  willUnmount = [];
3200
3250
  mounted = [];
3201
3251
  willPatch = [];
@@ -3730,6 +3780,7 @@ function createComponent(app, name, isStatic, hasSlotsProp, hasDynamicPropList,
3730
3780
  () => {
3731
3781
  if (fiber !== node.fiber) return;
3732
3782
  node.props = props2;
3783
+ for (const f of node.propsUpdated) f();
3733
3784
  fiber.render();
3734
3785
  },
3735
3786
  (error) => {
@@ -3738,6 +3789,7 @@ function createComponent(app, name, isStatic, hasSlotsProp, hasDynamicPropList,
3738
3789
  );
3739
3790
  } else {
3740
3791
  node.props = props2;
3792
+ for (const f of node.propsUpdated) f();
3741
3793
  fiber.render();
3742
3794
  }
3743
3795
  }
@@ -4110,6 +4162,24 @@ function onError(callback) {
4110
4162
  }
4111
4163
  handlers.push(callback.bind(scope.component));
4112
4164
  }
4165
+ function staticProp(key, type, ...args) {
4166
+ const node = getComponentScope();
4167
+ const hasDefault = args.length > 0;
4168
+ const propValue = node.props[key];
4169
+ if (node.app.dev) {
4170
+ if (type !== void 0 && (!hasDefault || propValue !== void 0)) {
4171
+ assertType(propValue, type, `Invalid prop '${key}' in '${node.componentName}'`);
4172
+ }
4173
+ node.willUpdateProps.push((nextProps) => {
4174
+ if (nextProps[key] !== node.props[key]) {
4175
+ throw new OwlError(
4176
+ `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).`
4177
+ );
4178
+ }
4179
+ });
4180
+ }
4181
+ return propValue === void 0 && hasDefault ? args[0] : propValue;
4182
+ }
4113
4183
  function componentType() {
4114
4184
  return constructorType(Component);
4115
4185
  }
@@ -4131,35 +4201,51 @@ function validateDefaults(schema) {
4131
4201
  }
4132
4202
  return types2.strictObject(validation);
4133
4203
  }
4134
- function props(type, defaults) {
4204
+ function makeProps(type, defaults) {
4135
4205
  const node = getComponentScope();
4136
4206
  const { app, componentName } = node;
4137
4207
  if (defaults) {
4138
4208
  node.defaultProps = Object.assign(node.defaultProps || {}, defaults);
4139
4209
  }
4140
- function getProp(key) {
4141
- if (node.props[key] === void 0 && defaults) {
4210
+ function resolveValue(props2, key) {
4211
+ if (props2[key] === void 0 && defaults) {
4142
4212
  return defaults[key];
4143
4213
  }
4144
- return node.props[key];
4214
+ return props2[key];
4145
4215
  }
4216
+ const signals = /* @__PURE__ */ Object.create(null);
4146
4217
  const result = /* @__PURE__ */ Object.create(null);
4147
- function applyPropGetters(keys) {
4218
+ function defineProp(key) {
4219
+ signals[key] = signal(resolveValue(node.props, key));
4220
+ Reflect.defineProperty(result, key, {
4221
+ enumerable: true,
4222
+ configurable: true,
4223
+ get: signals[key]
4224
+ });
4225
+ }
4226
+ function defineProps(keys) {
4148
4227
  for (const key of keys) {
4149
- Reflect.defineProperty(result, key, {
4150
- enumerable: true,
4151
- get: getProp.bind(null, key)
4152
- });
4228
+ defineProp(key);
4229
+ }
4230
+ }
4231
+ function updateSignals(keys) {
4232
+ for (const key of keys) {
4233
+ signals[key].set(resolveValue(node.props, key));
4153
4234
  }
4154
4235
  }
4155
4236
  if (type) {
4156
4237
  const keys = (Array.isArray(type) ? type : Object.keys(type)).map(
4157
4238
  (key) => key.endsWith("?") ? key.slice(0, -1) : key
4158
4239
  );
4159
- applyPropGetters(keys);
4240
+ defineProps(keys);
4241
+ node.propsUpdated.push(() => updateSignals(keys));
4160
4242
  if (app.dev) {
4161
4243
  if (defaults) {
4162
- assertType(defaults, validateDefaults(type), `Invalid component default props (${componentName})`);
4244
+ assertType(
4245
+ defaults,
4246
+ validateDefaults(type),
4247
+ `Invalid component default props (${componentName})`
4248
+ );
4163
4249
  }
4164
4250
  const validation = types2.object(type);
4165
4251
  assertType(node.props, validation, `Invalid component props (${componentName})`);
@@ -4185,17 +4271,28 @@ function props(type, defaults) {
4185
4271
  return keys2;
4186
4272
  };
4187
4273
  let keys = getKeys(node.props);
4188
- applyPropGetters(keys);
4189
- node.willUpdateProps.push((np) => {
4274
+ defineProps(keys);
4275
+ node.propsUpdated.push(() => {
4276
+ const nextKeys = getKeys(node.props);
4277
+ const nextKeySet = new Set(nextKeys);
4190
4278
  for (const key of keys) {
4191
- Reflect.deleteProperty(result, key);
4279
+ if (!nextKeySet.has(key)) {
4280
+ Reflect.deleteProperty(result, key);
4281
+ delete signals[key];
4282
+ }
4283
+ }
4284
+ for (const key of nextKeys) {
4285
+ if (!(key in signals)) {
4286
+ defineProp(key);
4287
+ }
4192
4288
  }
4193
- keys = getKeys(np);
4194
- applyPropGetters(keys);
4289
+ updateSignals(nextKeys);
4290
+ keys = nextKeys;
4195
4291
  });
4196
4292
  }
4197
4293
  return result;
4198
4294
  }
4295
+ var props = Object.assign(makeProps, { static: staticProp });
4199
4296
  var ErrorBoundary = class extends Component {
4200
4297
  static template = xml`
4201
4298
  <t t-if="this.props.error()">
@@ -4294,24 +4391,6 @@ var Suspense = class extends Component {
4294
4391
  onWillDestroy(() => root.destroy());
4295
4392
  }
4296
4393
  };
4297
- function prop(key, type, ...args) {
4298
- const node = getComponentScope();
4299
- const hasDefault = args.length > 0;
4300
- const propValue = node.props[key];
4301
- if (node.app.dev) {
4302
- if (type !== void 0 && (!hasDefault || propValue !== void 0)) {
4303
- assertType(propValue, type, `Invalid prop '${key}' in '${node.componentName}'`);
4304
- }
4305
- node.willUpdateProps.push((nextProps) => {
4306
- if (nextProps[key] !== node.props[key]) {
4307
- throw new OwlError(
4308
- `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).`
4309
- );
4310
- }
4311
- });
4312
- }
4313
- return propValue === void 0 && hasDefault ? args[0] : propValue;
4314
- }
4315
4394
  function providePlugins(pluginConstructors, config3) {
4316
4395
  const node = getComponentScope();
4317
4396
  const manager = new PluginManager(node.app, { parent: node.pluginManager, config: config3 });
@@ -4340,8 +4419,8 @@ var blockDom = {
4340
4419
  };
4341
4420
  var __info__ = {
4342
4421
  version: App.version,
4343
- date: "2026-05-28T13:29:02.340Z",
4344
- hash: "fadc22b7",
4422
+ date: "2026-06-05T08:44:38.319Z",
4423
+ hash: "3206cf27",
4345
4424
  url: "https://github.com/odoo/owl"
4346
4425
  };
4347
4426
 
@@ -6552,7 +6631,6 @@ export {
6552
6631
  onWillUnmount,
6553
6632
  onWillUpdateProps,
6554
6633
  plugin,
6555
- prop,
6556
6634
  props,
6557
6635
  providePlugins,
6558
6636
  proxy,