@odoo/owl 3.0.0-alpha.21 → 3.0.0-alpha.23

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
@@ -282,31 +282,6 @@ function toClassObj(expr) {
282
282
  return { [expr]: true };
283
283
  }
284
284
  }
285
- function setClass(val) {
286
- val = val === "" ? {} : toClassObj(val);
287
- // add classes
288
- const cl = this.classList;
289
- for (let c in val) {
290
- tokenListAdd.call(cl, c);
291
- }
292
- }
293
- function updateClass(val, oldVal) {
294
- oldVal = oldVal === "" ? {} : toClassObj(oldVal);
295
- val = val === "" ? {} : toClassObj(val);
296
- const cl = this.classList;
297
- // remove classes
298
- for (let c in oldVal) {
299
- if (!(c in val)) {
300
- tokenListRemove.call(cl, c);
301
- }
302
- }
303
- // add classes
304
- for (let c in val) {
305
- if (!(c in oldVal)) {
306
- tokenListAdd.call(cl, c);
307
- }
308
- }
309
- }
310
285
  // ---------------------------------------------------------------------------
311
286
  // Style
312
287
  // ---------------------------------------------------------------------------
@@ -339,7 +314,7 @@ function toStyleObj(expr) {
339
314
  }
340
315
  const prop = trim.call(part.slice(0, colonIdx));
341
316
  const value = trim.call(part.slice(colonIdx + 1));
342
- if (prop && value) {
317
+ if (prop && value && value !== "undefined") {
343
318
  result[prop] = value;
344
319
  }
345
320
  }
@@ -357,6 +332,32 @@ function toStyleObj(expr) {
357
332
  return {};
358
333
  }
359
334
  }
335
+ // ---------------------------------------------------------------------------
336
+ // Class
337
+ // ---------------------------------------------------------------------------
338
+ function setClass(val) {
339
+ val = val === "" ? {} : toClassObj(val);
340
+ for (let k in val) {
341
+ tokenListAdd.call(this.classList, k);
342
+ }
343
+ }
344
+ function updateClass(val, oldVal) {
345
+ oldVal = oldVal === "" ? {} : toClassObj(oldVal);
346
+ val = val === "" ? {} : toClassObj(val);
347
+ for (let k in oldVal) {
348
+ if (!(k in val)) {
349
+ tokenListRemove.call(this.classList, k);
350
+ }
351
+ }
352
+ for (let k in val) {
353
+ if (val[k] !== oldVal[k]) {
354
+ tokenListAdd.call(this.classList, k);
355
+ }
356
+ }
357
+ }
358
+ // ---------------------------------------------------------------------------
359
+ // Style setters
360
+ // ---------------------------------------------------------------------------
360
361
  function setStyle(val) {
361
362
  val = val === "" ? {} : toStyleObj(val);
362
363
  const style = this.style;
@@ -368,18 +369,19 @@ function updateStyle(val, oldVal) {
368
369
  oldVal = oldVal === "" ? {} : toStyleObj(oldVal);
369
370
  val = val === "" ? {} : toStyleObj(val);
370
371
  const style = this.style;
371
- // remove old styles
372
372
  for (let prop in oldVal) {
373
373
  if (!(prop in val)) {
374
374
  style.removeProperty(prop);
375
375
  }
376
376
  }
377
- // set new/changed styles
378
377
  for (let prop in val) {
379
378
  if (val[prop] !== oldVal[prop]) {
380
379
  style.setProperty(prop, val[prop]);
381
380
  }
382
381
  }
382
+ if (!style.cssText) {
383
+ removeAttribute.call(this, "style");
384
+ }
383
385
  }
384
386
 
385
387
  /**
@@ -1998,51 +2000,11 @@ function untrack(fn) {
1998
2000
  // Maps fibers to thrown errors
1999
2001
  const fibersInError = new WeakMap();
2000
2002
  const nodeErrorHandlers = new WeakMap();
2001
- function destroyApp(app, error) {
2002
- try {
2003
- app.destroy();
2004
- }
2005
- catch (e) {
2006
- // mute all errors here because we are in a corrupted state anyway
2007
- }
2008
- const e = Object.assign(new OwlError(`[Owl] Unhandled error. Destroying the root component`), {
2009
- cause: error,
2010
- });
2011
- return e;
2012
- }
2013
- function _handleError(node, error) {
2014
- if (!node) {
2015
- return false;
2016
- }
2017
- const fiber = node.fiber;
2018
- if (fiber) {
2019
- fibersInError.set(fiber, error);
2020
- }
2021
- const errorHandlers = nodeErrorHandlers.get(node);
2022
- if (errorHandlers) {
2023
- let handled = false;
2024
- // execute in the opposite order
2025
- const finalize = () => destroyApp(node.app, error);
2026
- for (let i = errorHandlers.length - 1; i >= 0; i--) {
2027
- try {
2028
- errorHandlers[i](error, finalize);
2029
- handled = true;
2030
- break;
2031
- }
2032
- catch (e) {
2033
- error = e;
2034
- }
2035
- }
2036
- if (handled) {
2037
- return true;
2038
- }
2039
- }
2040
- return _handleError(node.parent, error);
2041
- }
2042
2003
  function handleError(params) {
2043
2004
  let { error } = params;
2044
- const node = "node" in params ? params.node : params.fiber.node;
2005
+ let node = "node" in params ? params.node : params.fiber.node;
2045
2006
  const fiber = "fiber" in params ? params.fiber : node.fiber;
2007
+ const app = node.app;
2046
2008
  if (fiber) {
2047
2009
  // resets the fibers on components if possible. This is important so that
2048
2010
  // new renderings can be properly included in the initial one, if any.
@@ -2054,10 +2016,43 @@ function handleError(params) {
2054
2016
  } while (current);
2055
2017
  fibersInError.set(fiber.root, error);
2056
2018
  }
2057
- const handled = _handleError(node, error);
2058
- if (!handled) {
2059
- throw destroyApp(node.app, error);
2019
+ const finalize = () => {
2020
+ try {
2021
+ app.destroy();
2022
+ }
2023
+ catch (e) {
2024
+ // mute all errors here because we are in a corrupted state anyway
2025
+ }
2026
+ return Object.assign(new OwlError(`[Owl] Unhandled error. Destroying the root component`), {
2027
+ cause: error,
2028
+ });
2029
+ };
2030
+ // Walk up the component tree looking for error handlers
2031
+ while (node) {
2032
+ const nodeFiber = node.fiber;
2033
+ if (nodeFiber) {
2034
+ fibersInError.set(nodeFiber, error);
2035
+ }
2036
+ const errorHandlers = nodeErrorHandlers.get(node);
2037
+ if (errorHandlers) {
2038
+ // execute in the opposite order
2039
+ for (let i = errorHandlers.length - 1; i >= 0; i--) {
2040
+ try {
2041
+ errorHandlers[i](error, finalize);
2042
+ return; // handled
2043
+ }
2044
+ catch (e) {
2045
+ error = e;
2046
+ }
2047
+ }
2048
+ }
2049
+ node = node.parent;
2060
2050
  }
2051
+ // No handler found — create the OwlError, then let the app handle it.
2052
+ // app._handleError is called after error creation, so it doesn't appear
2053
+ // in the error's .stack property.
2054
+ const owlError = finalize();
2055
+ app._handleError(owlError);
2061
2056
  }
2062
2057
 
2063
2058
  function makeChildFiber(node, parent) {
@@ -2193,7 +2188,7 @@ class Fiber {
2193
2188
  this.bdom = node.renderFn();
2194
2189
  }
2195
2190
  catch (e) {
2196
- node.app.handleError({ node, error: e });
2191
+ handleError({ node, error: e });
2197
2192
  }
2198
2193
  setComputation(c);
2199
2194
  root.setCounter(root.counter - 1);
@@ -2263,7 +2258,7 @@ class RootFiber extends Fiber {
2263
2258
  fiber.node.willUnmount = [];
2264
2259
  }
2265
2260
  this.locked = false;
2266
- node.app.handleError({ fiber: current || this, error: e });
2261
+ handleError({ fiber: current || this, error: e });
2267
2262
  }
2268
2263
  }
2269
2264
  setCounter(newValue) {
@@ -2319,7 +2314,7 @@ class MountFiber extends RootFiber {
2319
2314
  }
2320
2315
  }
2321
2316
  catch (e) {
2322
- this.node.app.handleError({ fiber: current, error: e });
2317
+ handleError({ fiber: current, error: e });
2323
2318
  }
2324
2319
  }
2325
2320
  }
@@ -2397,7 +2392,7 @@ class ComponentNode {
2397
2392
  await Promise.all(promises);
2398
2393
  }
2399
2394
  catch (e) {
2400
- this.app.handleError({ node: this, error: e });
2395
+ handleError({ node: this, error: e });
2401
2396
  return;
2402
2397
  }
2403
2398
  if (this.status === 0 /* STATUS.NEW */ && this.fiber === fiber) {
@@ -2487,7 +2482,7 @@ class ComponentNode {
2487
2482
  }
2488
2483
  }
2489
2484
  catch (e) {
2490
- this.app.handleError({ error: e, node: this });
2485
+ handleError({ error: e, node: this });
2491
2486
  }
2492
2487
  }
2493
2488
  for (const computation of this.computations) {
@@ -5670,7 +5665,7 @@ function compile(template, options = {
5670
5665
  }
5671
5666
 
5672
5667
  // do not modify manually. This file is generated by the release script.
5673
- const version = "3.0.0-alpha.21";
5668
+ const version = "3.0.0-alpha.23";
5674
5669
 
5675
5670
  function effect(fn) {
5676
5671
  const computation = createComputation(() => {
@@ -5868,8 +5863,33 @@ class Scheduler {
5868
5863
  node._destroy();
5869
5864
  }
5870
5865
  this.cancelledNodes.clear();
5871
- for (let task of this.tasks) {
5872
- this.processFiber(task);
5866
+ for (let fiber of this.tasks) {
5867
+ if (fiber.root !== fiber) {
5868
+ this.tasks.delete(fiber);
5869
+ continue;
5870
+ }
5871
+ const hasError = fibersInError.has(fiber);
5872
+ if (hasError && fiber.counter !== 0) {
5873
+ this.tasks.delete(fiber);
5874
+ continue;
5875
+ }
5876
+ if (fiber.node.status === 3 /* STATUS.DESTROYED */) {
5877
+ this.tasks.delete(fiber);
5878
+ continue;
5879
+ }
5880
+ if (fiber.counter === 0) {
5881
+ if (!hasError) {
5882
+ fiber.complete();
5883
+ }
5884
+ // at this point, the fiber should have been applied to the DOM, so we can
5885
+ // remove it from the task list. If it is not the case, it means that there
5886
+ // was an error and an error handler triggered a new rendering that recycled
5887
+ // the fiber, so in that case, we actually want to keep the fiber around,
5888
+ // otherwise it will just be ignored.
5889
+ if (fiber.appliedToDom) {
5890
+ this.tasks.delete(fiber);
5891
+ }
5892
+ }
5873
5893
  }
5874
5894
  for (let task of this.tasks) {
5875
5895
  if (task.node.status === 3 /* STATUS.DESTROYED */) {
@@ -5878,34 +5898,6 @@ class Scheduler {
5878
5898
  }
5879
5899
  this.processing = false;
5880
5900
  }
5881
- processFiber(fiber) {
5882
- if (fiber.root !== fiber) {
5883
- this.tasks.delete(fiber);
5884
- return;
5885
- }
5886
- const hasError = fibersInError.has(fiber);
5887
- if (hasError && fiber.counter !== 0) {
5888
- this.tasks.delete(fiber);
5889
- return;
5890
- }
5891
- if (fiber.node.status === 3 /* STATUS.DESTROYED */) {
5892
- this.tasks.delete(fiber);
5893
- return;
5894
- }
5895
- if (fiber.counter === 0) {
5896
- if (!hasError) {
5897
- fiber.complete();
5898
- }
5899
- // at this point, the fiber should have been applied to the DOM, so we can
5900
- // remove it from the task list. If it is not the case, it means that there
5901
- // was an error and an error handler triggered a new rendering that recycled
5902
- // the fiber, so in that case, we actually want to keep the fiber around,
5903
- // otherwise it will just be ignored.
5904
- if (fiber.appliedToDom) {
5905
- this.tasks.delete(fiber);
5906
- }
5907
- }
5908
- }
5909
5901
  }
5910
5902
 
5911
5903
  let hasBeenLogged = false;
@@ -6005,8 +5997,8 @@ class App extends TemplateSet {
6005
5997
  this.scheduler.processTasks();
6006
5998
  apps.delete(this);
6007
5999
  }
6008
- handleError(...args) {
6009
- return handleError(...args);
6000
+ _handleError(error) {
6001
+ throw error;
6010
6002
  }
6011
6003
  }
6012
6004
  async function mount(C, target, config = {}) {
@@ -6064,14 +6056,20 @@ const mainEventHandler = (data, ev, currentTarget) => {
6064
6056
  // hooks
6065
6057
  // -----------------------------------------------------------------------------
6066
6058
  function decorate(node, f, hookName) {
6067
- const result = f.bind(node.component);
6068
6059
  if (node.app.dev) {
6069
- const suffix = f.name ? ` <${f.name}>` : "";
6070
- Reflect.defineProperty(result, "name", {
6071
- value: hookName + suffix,
6072
- });
6060
+ const component = node.component;
6061
+ const componentName = component ? component.constructor.name : "Component";
6062
+ const name = `${componentName}.${hookName}`;
6063
+ // Create a named wrapper so the name appears in stack traces.
6064
+ // V8 uses computed property keys as inferred function names.
6065
+ const wrapper = {
6066
+ [name]() {
6067
+ return f.call(component);
6068
+ },
6069
+ };
6070
+ return wrapper[name];
6073
6071
  }
6074
- return result;
6072
+ return f.bind(node.component);
6075
6073
  }
6076
6074
  function onWillStart(fn) {
6077
6075
  const { node } = getContext("component");
@@ -6329,22 +6327,30 @@ class Registry {
6329
6327
  }
6330
6328
  }
6331
6329
 
6332
- const anyType = function validateAny() { };
6333
- const booleanType = function validateBoolean(context) {
6334
- if (typeof context.value !== "boolean") {
6335
- context.addIssue({ message: "value is not a boolean" });
6336
- }
6337
- };
6338
- const numberType = function validateNumber(context) {
6339
- if (typeof context.value !== "number") {
6340
- context.addIssue({ message: "value is not a number" });
6341
- }
6342
- };
6343
- const stringType = function validateString(context) {
6344
- if (typeof context.value !== "string") {
6345
- context.addIssue({ message: "value is not a string" });
6346
- }
6347
- };
6330
+ function anyType() {
6331
+ return function validateAny() { };
6332
+ }
6333
+ function booleanType() {
6334
+ return function validateBoolean(context) {
6335
+ if (typeof context.value !== "boolean") {
6336
+ context.addIssue({ message: "value is not a boolean" });
6337
+ }
6338
+ };
6339
+ }
6340
+ function numberType() {
6341
+ return function validateNumber(context) {
6342
+ if (typeof context.value !== "number") {
6343
+ context.addIssue({ message: "value is not a number" });
6344
+ }
6345
+ };
6346
+ }
6347
+ function stringType() {
6348
+ return function validateString(context) {
6349
+ if (typeof context.value !== "string") {
6350
+ context.addIssue({ message: "value is not a string" });
6351
+ }
6352
+ };
6353
+ }
6348
6354
  function arrayType(elementType) {
6349
6355
  return function validateArray(context) {
6350
6356
  if (!Array.isArray(context.value)) {
@@ -6535,6 +6541,9 @@ function reactiveValueType(type) {
6535
6541
  }
6536
6542
  };
6537
6543
  }
6544
+ function componentType() {
6545
+ return constructorType(Component);
6546
+ }
6538
6547
  function ref(type) {
6539
6548
  return union([literalType(null), instanceType(type)]);
6540
6549
  }
@@ -6543,6 +6552,7 @@ const types = {
6543
6552
  any: anyType,
6544
6553
  array: arrayType,
6545
6554
  boolean: booleanType,
6555
+ component: componentType,
6546
6556
  constructor: constructorType,
6547
6557
  customValidator: customValidator,
6548
6558
  function: functionType,
@@ -6769,6 +6779,6 @@ TemplateSet.prototype._compileTemplate = function _compileTemplate(name, templat
6769
6779
  export { App, Component, EventBus, OwlError, Plugin, Registry, Resource, __info__, assertType, batched, blockDom, computed, config, effect, htmlEscape, markRaw, markup, mount, onError, onMounted, onPatched, onWillDestroy, onWillPatch, onWillStart, onWillUnmount, onWillUpdateProps, plugin, props, providePlugins, proxy, signal, status, toRaw, types, untrack, useApp, useContext, useEffect, useListener, useResource, validateType, whenReady, xml };
6770
6780
 
6771
6781
 
6772
- __info__.date = '2026-04-02T11:14:58.432Z';
6773
- __info__.hash = '9ca35d8';
6782
+ __info__.date = '2026-04-10T07:28:23.029Z';
6783
+ __info__.hash = 'e5e6d92';
6774
6784
  __info__.url = 'https://github.com/odoo/owl';