@odoo/o-spreadsheet 16.4.0-alpha.2 → 16.4.0-alpha.3

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.
@@ -5222,14 +5222,6 @@ function* iterateChildren(el) {
5222
5222
  }
5223
5223
  }
5224
5224
  }
5225
- function getElementScrollTop(el) {
5226
- return el?.scrollTop || 0;
5227
- }
5228
- function setElementScrollTop(el, scroll) {
5229
- if (!el)
5230
- return;
5231
- el.scrollTop = scroll;
5232
- }
5233
5225
  function getOpenedMenus() {
5234
5226
  return Array.from(document.querySelectorAll(".o-spreadsheet .o-menu"));
5235
5227
  }
@@ -17947,7 +17939,7 @@ class LineBarPieConfigPanel extends owl.Component {
17947
17939
  return !!this.state.labelsDispatchResult?.isCancelledBecause(33 /* CommandResult.InvalidLabelRange */);
17948
17940
  }
17949
17941
  onUpdateDataSetsHaveTitle(ev) {
17950
- this.props.updateChart({
17942
+ this.props.updateChart(this.props.figureId, {
17951
17943
  dataSetsHaveTitle: ev.target.checked,
17952
17944
  });
17953
17945
  }
@@ -17960,7 +17952,7 @@ class LineBarPieConfigPanel extends owl.Component {
17960
17952
  }
17961
17953
  onDataSeriesConfirmed() {
17962
17954
  this.dataSeriesRanges = spreadRange(this.dataSeriesRanges);
17963
- this.state.datasetDispatchResult = this.props.updateChart({
17955
+ this.state.datasetDispatchResult = this.props.updateChart(this.props.figureId, {
17964
17956
  dataSets: this.dataSeriesRanges,
17965
17957
  });
17966
17958
  }
@@ -17975,7 +17967,7 @@ class LineBarPieConfigPanel extends owl.Component {
17975
17967
  this.labelRange = ranges[0];
17976
17968
  }
17977
17969
  onLabelRangeConfirmed() {
17978
- this.state.labelsDispatchResult = this.props.updateChart({
17970
+ this.state.labelsDispatchResult = this.props.updateChart(this.props.figureId, {
17979
17971
  labelRange: this.labelRange,
17980
17972
  });
17981
17973
  }
@@ -17983,7 +17975,7 @@ class LineBarPieConfigPanel extends owl.Component {
17983
17975
  return this.labelRange || "";
17984
17976
  }
17985
17977
  onUpdateAggregated(ev) {
17986
- this.props.updateChart({
17978
+ this.props.updateChart(this.props.figureId, {
17987
17979
  aggregated: ev.target.checked,
17988
17980
  });
17989
17981
  }
@@ -18013,12 +18005,12 @@ LineBarPieConfigPanel.props = {
18013
18005
  class BarConfigPanel extends LineBarPieConfigPanel {
18014
18006
  static template = "o-spreadsheet-BarConfigPanel";
18015
18007
  onUpdateStacked(ev) {
18016
- this.props.updateChart({
18008
+ this.props.updateChart(this.props.figureId, {
18017
18009
  stacked: ev.target.checked,
18018
18010
  });
18019
18011
  }
18020
18012
  onUpdateAggregated(ev) {
18021
- this.props.updateChart({
18013
+ this.props.updateChart(this.props.figureId, {
18022
18014
  aggregated: ev.target.checked,
18023
18015
  });
18024
18016
  }
@@ -18355,17 +18347,17 @@ class LineBarPieDesignPanel extends owl.Component {
18355
18347
  this.state.fillColorTool = !this.state.fillColorTool;
18356
18348
  }
18357
18349
  updateBackgroundColor(color) {
18358
- this.props.updateChart({
18350
+ this.props.updateChart(this.props.figureId, {
18359
18351
  background: color,
18360
18352
  });
18361
18353
  }
18362
18354
  updateTitle(ev) {
18363
- this.props.updateChart({
18355
+ this.props.updateChart(this.props.figureId, {
18364
18356
  title: ev.target.value,
18365
18357
  });
18366
18358
  }
18367
18359
  updateSelect(attr, ev) {
18368
- this.props.updateChart({
18360
+ this.props.updateChart(this.props.figureId, {
18369
18361
  [attr]: ev.target.value,
18370
18362
  });
18371
18363
  }
@@ -18398,7 +18390,7 @@ class GaugeChartConfigPanel extends owl.Component {
18398
18390
  this.dataRange = ranges[0];
18399
18391
  }
18400
18392
  updateDataRange() {
18401
- this.state.dataRangeDispatchResult = this.props.updateChart({
18393
+ this.state.dataRangeDispatchResult = this.props.updateChart(this.props.figureId, {
18402
18394
  dataRange: this.dataRange,
18403
18395
  });
18404
18396
  }
@@ -18459,12 +18451,12 @@ class GaugeChartDesignPanel extends owl.Component {
18459
18451
  }
18460
18452
  updateBackgroundColor(color) {
18461
18453
  this.state.openedMenu = undefined;
18462
- this.props.updateChart({
18454
+ this.props.updateChart(this.props.figureId, {
18463
18455
  background: color,
18464
18456
  });
18465
18457
  }
18466
18458
  updateTitle(ev) {
18467
- this.props.updateChart({
18459
+ this.props.updateChart(this.props.figureId, {
18468
18460
  title: ev.target.value,
18469
18461
  });
18470
18462
  }
@@ -18529,7 +18521,7 @@ class GaugeChartDesignPanel extends owl.Component {
18529
18521
  }
18530
18522
  }
18531
18523
  updateSectionRule(sectionRule) {
18532
- this.state.sectionRuleDispatchResult = this.props.updateChart({
18524
+ this.state.sectionRuleDispatchResult = this.props.updateChart(this.props.figureId, {
18533
18525
  sectionRule,
18534
18526
  });
18535
18527
  }
@@ -18553,17 +18545,17 @@ class LineConfigPanel extends LineBarPieConfigPanel {
18553
18545
  return false;
18554
18546
  }
18555
18547
  onUpdateLabelsAsText(ev) {
18556
- this.props.updateChart({
18548
+ this.props.updateChart(this.props.figureId, {
18557
18549
  labelsAsText: ev.target.checked,
18558
18550
  });
18559
18551
  }
18560
18552
  onUpdateStacked(ev) {
18561
- this.props.updateChart({
18553
+ this.props.updateChart(this.props.figureId, {
18562
18554
  stacked: ev.target.checked,
18563
18555
  });
18564
18556
  }
18565
18557
  onUpdateAggregated(ev) {
18566
- this.props.updateChart({
18558
+ this.props.updateChart(this.props.figureId, {
18567
18559
  aggregated: ev.target.checked,
18568
18560
  });
18569
18561
  }
@@ -18599,7 +18591,7 @@ class ScorecardChartConfigPanel extends owl.Component {
18599
18591
  this.keyValue = ranges[0];
18600
18592
  }
18601
18593
  updateKeyValueRange() {
18602
- this.state.keyValueDispatchResult = this.props.updateChart({
18594
+ this.state.keyValueDispatchResult = this.props.updateChart(this.props.figureId, {
18603
18595
  keyValue: this.keyValue,
18604
18596
  });
18605
18597
  }
@@ -18610,7 +18602,7 @@ class ScorecardChartConfigPanel extends owl.Component {
18610
18602
  this.baseline = ranges[0];
18611
18603
  }
18612
18604
  updateBaselineRange() {
18613
- this.state.baselineDispatchResult = this.props.updateChart({
18605
+ this.state.baselineDispatchResult = this.props.updateChart(this.props.figureId, {
18614
18606
  baseline: this.baseline,
18615
18607
  });
18616
18608
  }
@@ -18618,7 +18610,7 @@ class ScorecardChartConfigPanel extends owl.Component {
18618
18610
  return this.baseline || "";
18619
18611
  }
18620
18612
  updateBaselineMode(ev) {
18621
- this.props.updateChart({ baselineMode: ev.target.value });
18613
+ this.props.updateChart(this.props.figureId, { baselineMode: ev.target.value });
18622
18614
  }
18623
18615
  }
18624
18616
  ScorecardChartConfigPanel.props = {
@@ -18637,12 +18629,12 @@ class ScorecardChartDesignPanel extends owl.Component {
18637
18629
  owl.useExternalListener(window, "click", this.closeMenus);
18638
18630
  }
18639
18631
  updateTitle(ev) {
18640
- this.props.updateChart({
18632
+ this.props.updateChart(this.props.figureId, {
18641
18633
  title: ev.target.value,
18642
18634
  });
18643
18635
  }
18644
18636
  updateBaselineDescr(ev) {
18645
- this.props.updateChart({ baselineDescr: ev.target.value });
18637
+ this.props.updateChart(this.props.figureId, { baselineDescr: ev.target.value });
18646
18638
  }
18647
18639
  toggleColorPicker(colorPickerId) {
18648
18640
  if (this.state.openedColorPicker === colorPickerId) {
@@ -18655,13 +18647,13 @@ class ScorecardChartDesignPanel extends owl.Component {
18655
18647
  setColor(color, colorPickerId) {
18656
18648
  switch (colorPickerId) {
18657
18649
  case "backgroundColor":
18658
- this.props.updateChart({ background: color });
18650
+ this.props.updateChart(this.props.figureId, { background: color });
18659
18651
  break;
18660
18652
  case "baselineColorDown":
18661
- this.props.updateChart({ baselineColorDown: color });
18653
+ this.props.updateChart(this.props.figureId, { baselineColorDown: color });
18662
18654
  break;
18663
18655
  case "baselineColorUp":
18664
- this.props.updateChart({ baselineColorUp: color });
18656
+ this.props.updateChart(this.props.figureId, { baselineColorUp: color });
18665
18657
  break;
18666
18658
  }
18667
18659
  this.closeMenus();
@@ -18726,13 +18718,9 @@ css /* scss */ `
18726
18718
  class ChartPanel extends owl.Component {
18727
18719
  static template = "o-spreadsheet-ChartPanel";
18728
18720
  state;
18729
- shouldUpdateChart = true;
18730
18721
  get figureId() {
18731
18722
  return this.state.figureId;
18732
18723
  }
18733
- get sheetId() {
18734
- return this.state.sheetId;
18735
- }
18736
18724
  setup() {
18737
18725
  const selectedFigureId = this.env.model.getters.getSelectedFigureId();
18738
18726
  if (!selectedFigureId) {
@@ -18742,17 +18730,11 @@ class ChartPanel extends owl.Component {
18742
18730
  this.state = owl.useState({
18743
18731
  panel: "configuration",
18744
18732
  figureId: selectedFigureId,
18745
- sheetId: this.env.model.getters.getActiveSheetId(),
18746
18733
  });
18747
18734
  owl.onWillUpdateProps(() => {
18748
18735
  const selectedFigureId = this.env.model.getters.getSelectedFigureId();
18749
18736
  if (selectedFigureId && selectedFigureId !== this.state.figureId) {
18750
18737
  this.state.figureId = selectedFigureId;
18751
- this.state.sheetId = this.env.model.getters.getActiveSheetId();
18752
- this.shouldUpdateChart = false;
18753
- }
18754
- else {
18755
- this.shouldUpdateChart = true;
18756
18738
  }
18757
18739
  if (!this.env.model.getters.isChartDefined(this.figureId)) {
18758
18740
  this.props.onCloseSidePanel();
@@ -18760,8 +18742,8 @@ class ChartPanel extends owl.Component {
18760
18742
  }
18761
18743
  });
18762
18744
  }
18763
- updateChart(updateDefinition) {
18764
- if (!this.shouldUpdateChart) {
18745
+ updateChart(figureId, updateDefinition) {
18746
+ if (figureId !== this.figureId) {
18765
18747
  return;
18766
18748
  }
18767
18749
  const definition = {
@@ -18770,8 +18752,8 @@ class ChartPanel extends owl.Component {
18770
18752
  };
18771
18753
  return this.env.model.dispatch("UPDATE_CHART", {
18772
18754
  definition,
18773
- id: this.figureId,
18774
- sheetId: this.sheetId,
18755
+ id: figureId,
18756
+ sheetId: this.env.model.getters.getFigureSheetId(figureId),
18775
18757
  });
18776
18758
  }
18777
18759
  onTypeChange(type) {
@@ -18783,7 +18765,7 @@ class ChartPanel extends owl.Component {
18783
18765
  this.env.model.dispatch("UPDATE_CHART", {
18784
18766
  definition,
18785
18767
  id: this.figureId,
18786
- sheetId: this.sheetId,
18768
+ sheetId: this.env.model.getters.getFigureSheetId(this.figureId),
18787
18769
  });
18788
18770
  }
18789
18771
  get chartPanel() {
@@ -20579,12 +20561,23 @@ class ContentEditableHelper {
20579
20561
  */
20580
20562
  selectRange(start, end) {
20581
20563
  let selection = window.getSelection();
20582
- this.removeSelection();
20583
- let range = document.createRange();
20564
+ const { start: currentStart, end: currentEnd } = this.getCurrentSelection();
20565
+ if (currentStart === start && currentEnd === end) {
20566
+ return;
20567
+ }
20568
+ const currentRange = selection.getRangeAt(0);
20569
+ let range;
20570
+ if (this.el.contains(currentRange.startContainer)) {
20571
+ range = currentRange;
20572
+ }
20573
+ else {
20574
+ range = document.createRange();
20575
+ selection.removeAllRanges();
20576
+ selection.addRange(range);
20577
+ }
20584
20578
  if (start == end && start === 0) {
20585
20579
  range.setStart(this.el, 0);
20586
20580
  range.setEnd(this.el, 0);
20587
- selection.addRange(range);
20588
20581
  }
20589
20582
  else {
20590
20583
  const textLength = this.getText().length;
@@ -20600,7 +20593,6 @@ class ContentEditableHelper {
20600
20593
  let startNode = this.findChildAtCharacterIndex(start);
20601
20594
  let endNode = this.findChildAtCharacterIndex(end);
20602
20595
  range.setStart(startNode.node, startNode.offset);
20603
- selection.addRange(range);
20604
20596
  selection.extend(endNode.node, endNode.offset);
20605
20597
  }
20606
20598
  }
@@ -20640,26 +20632,54 @@ class ContentEditableHelper {
20640
20632
  return { node: previous, offset: usedCharacters };
20641
20633
  }
20642
20634
  /**
20643
- * Sets (or Replaces all) the text inside the root element in the form of distinctive
20635
+ * Sets (or Replaces all) the text inside the root element in the form of distinctive paragraphs and
20644
20636
  * span for each element provided in `contents`.
20645
20637
  *
20638
+ * The function will apply the diff between the current content and the new content to avoid the systematic
20639
+ * destruction of DOM elements which interferes with IME[1]
20640
+ *
20641
+ * Each line of text will be encapsulated in a paragraph element.
20646
20642
  * Each span will have its own fontcolor and specific class if provided in the HtmlContent object.
20643
+ *
20644
+ * [1] https://developer.mozilla.org/en-US/docs/Glossary/Input_method_editor
20647
20645
  */
20648
20646
  setText(contents) {
20649
- this.el.innerHTML = "";
20650
20647
  if (contents.length === 0) {
20648
+ this.removeAll();
20651
20649
  return;
20652
20650
  }
20653
- for (const line of contents) {
20654
- const p = document.createElement("p");
20655
- // Empty line
20656
- if (line.length === 0 || line.every((content) => !content.value && !content.class)) {
20657
- p.appendChild(document.createElement("br"));
20658
- this.el.appendChild(p);
20659
- continue;
20651
+ const childElements = Array.from(this.el.childNodes);
20652
+ const contentLength = contents.length;
20653
+ for (let i = 0; i < contentLength; i++) {
20654
+ const line = contents[i];
20655
+ const childElement = childElements[i];
20656
+ let newChild = false;
20657
+ let p;
20658
+ if (childElement && childElement.nodeName === "P") {
20659
+ p = childElement;
20660
20660
  }
20661
- for (const content of line) {
20661
+ else {
20662
+ newChild = true;
20663
+ p = document.createElement("p");
20664
+ }
20665
+ const lineLength = line.length;
20666
+ const existingChildren = Array.from(p.childNodes);
20667
+ for (let j = 0; j < lineLength; j++) {
20668
+ const content = line[j];
20669
+ const child = existingChildren[j];
20670
+ // child nodes can be multiple types of nodes: Span, Text, Div, etc...
20671
+ // We can only modify a node in place if it has the same type as the content
20672
+ // that we would insert, which are spans.
20673
+ // Otherwise, it means that the node has been input by the user, through the keyboard or a copy/paste
20674
+ // @ts-ignore (somehow required because jest does not like child.tagName despite the prior check)
20675
+ const childIsSpan = child && "tagName" in child && child.tagName === "SPAN";
20676
+ if (childIsSpan && compareContentToSpanElement(content, child)) {
20677
+ continue;
20678
+ }
20679
+ // this is an empty line in the content
20662
20680
  if (!content.value && !content.class) {
20681
+ if (child)
20682
+ p.removeChild(child);
20663
20683
  continue;
20664
20684
  }
20665
20685
  const span = document.createElement("span");
@@ -20668,9 +20688,38 @@ class ContentEditableHelper {
20668
20688
  if (content.class) {
20669
20689
  span.classList.add(content.class);
20670
20690
  }
20691
+ if (child) {
20692
+ p.replaceChild(span, child);
20693
+ }
20694
+ else {
20695
+ p.appendChild(span);
20696
+ }
20697
+ }
20698
+ if (existingChildren.length > lineLength) {
20699
+ for (let i = lineLength; i < existingChildren.length; i++) {
20700
+ p.removeChild(existingChildren[i]);
20701
+ }
20702
+ }
20703
+ // Empty line
20704
+ if (!p.hasChildNodes()) {
20705
+ const span = document.createElement("span");
20706
+ span.appendChild(document.createElement("br"));
20671
20707
  p.appendChild(span);
20672
20708
  }
20673
- this.el.appendChild(p);
20709
+ // replace p if necessary
20710
+ if (newChild) {
20711
+ if (childElement) {
20712
+ this.el.replaceChild(p, childElement);
20713
+ }
20714
+ else {
20715
+ this.el.appendChild(p);
20716
+ }
20717
+ }
20718
+ }
20719
+ if (childElements.length > contentLength) {
20720
+ for (let i = contentLength; i < childElements.length; i++) {
20721
+ this.el.removeChild(childElements[i]);
20722
+ }
20674
20723
  }
20675
20724
  }
20676
20725
  scrollSelectionIntoView() {
@@ -20680,13 +20729,6 @@ class ContentEditableHelper {
20680
20729
  const element = focusedNode instanceof HTMLElement ? focusedNode : focusedNode.parentElement;
20681
20730
  element?.scrollIntoView({ block: "nearest" });
20682
20731
  }
20683
- /**
20684
- * remove the current selection of the user
20685
- * */
20686
- removeSelection() {
20687
- let selection = window.getSelection();
20688
- selection.removeAllRanges();
20689
- }
20690
20732
  removeAll() {
20691
20733
  if (this.el) {
20692
20734
  while (this.el.firstChild) {
@@ -20816,6 +20858,14 @@ class ContentEditableHelper {
20816
20858
  }
20817
20859
  return text;
20818
20860
  }
20861
+ }
20862
+ function compareContentToSpanElement(content, node) {
20863
+ const contentColor = content.color ? toHex(content.color) : "";
20864
+ const nodeColor = node.style?.color ? toHex(node.style.color) : "";
20865
+ const sameColor = contentColor === nodeColor;
20866
+ const sameClass = deepEquals([content.class], [...node.classList]);
20867
+ const sameContent = node.innerText === content.value;
20868
+ return sameColor && sameClass && sameContent;
20819
20869
  }
20820
20870
 
20821
20871
  // -----------------------------------------------------------------------------
@@ -20961,7 +21011,6 @@ class Composer extends owl.Component {
20961
21011
  functionDescription: {},
20962
21012
  argToFocus: 0,
20963
21013
  });
20964
- isKeyStillDown = false;
20965
21014
  compositionActive = false;
20966
21015
  get assistantStyle() {
20967
21016
  if (this.props.delimitation && this.props.rect) {
@@ -20996,21 +21045,18 @@ class Composer extends owl.Component {
20996
21045
  F2: () => console.warn("Not implemented"),
20997
21046
  F4: this.processF4Key,
20998
21047
  Tab: (ev) => this.processTabKey(ev),
21048
+ " ": (ev) => this.processSpaceKey(ev),
20999
21049
  };
21000
21050
  setup() {
21001
21051
  owl.onMounted(() => {
21002
21052
  const el = this.composerRef.el;
21003
21053
  this.contentHelper.updateEl(el);
21004
- this.processContent();
21005
- this.contentHelper.scrollSelectionIntoView();
21006
21054
  });
21007
21055
  owl.onWillUnmount(() => {
21008
21056
  this.props.onComposerUnmounted?.();
21009
21057
  });
21010
- owl.onPatched(() => {
21011
- if (!this.isKeyStillDown) {
21012
- this.processContent();
21013
- }
21058
+ owl.useEffect(() => {
21059
+ this.processContent();
21014
21060
  });
21015
21061
  }
21016
21062
  // ---------------------------------------------------------------------------
@@ -21063,32 +21109,25 @@ class Composer extends owl.Component {
21063
21109
  return;
21064
21110
  }
21065
21111
  }
21066
- else {
21067
- // when completing with tab, if there is no value to complete, the active cell will be moved to the right.
21068
- // we can't let the model think that it is for a ref selection.
21069
- // todo: check if this can be removed someday
21070
- this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
21071
- }
21072
21112
  const direction = ev.shiftKey ? "left" : "right";
21073
21113
  this.env.model.dispatch("STOP_EDITION");
21074
21114
  this.env.model.selection.moveAnchorCell(direction, 1);
21075
21115
  }
21116
+ processSpaceKey(ev) {
21117
+ if (ev.ctrlKey) {
21118
+ ev.preventDefault();
21119
+ ev.stopPropagation();
21120
+ this.showAutocomplete("");
21121
+ this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
21122
+ }
21123
+ }
21076
21124
  processEnterKey(ev) {
21077
21125
  ev.preventDefault();
21078
21126
  ev.stopPropagation();
21079
21127
  if (ev.altKey || ev.ctrlKey) {
21080
- const selection = this.contentHelper.getCurrentSelection();
21081
- const currentContent = this.env.model.getters.getCurrentContent();
21082
- const content = currentContent.slice(0, selection.start) + NEWLINE + currentContent.slice(selection.end);
21083
- this.env.model.dispatch("SET_CURRENT_CONTENT", {
21084
- content,
21085
- selection: { start: selection.start + 1, end: selection.start + 1 },
21086
- });
21087
- this.processContent();
21088
- this.contentHelper.scrollSelectionIntoView();
21128
+ this.composerRef.el?.dispatchEvent(new InputEvent("input", { inputType: "insertParagraph", bubbles: true, isComposing: false }));
21089
21129
  return;
21090
21130
  }
21091
- this.isKeyStillDown = false;
21092
21131
  if (this.autoCompleteState.showProvider) {
21093
21132
  const autoCompleteValue = this.autoCompleteState.values[this.autoCompleteState.selectedIndex]?.text;
21094
21133
  if (autoCompleteValue) {
@@ -21121,56 +21160,42 @@ class Composer extends owl.Component {
21121
21160
  else {
21122
21161
  ev.stopPropagation();
21123
21162
  }
21124
- const { start, end } = this.contentHelper.getCurrentSelection();
21125
- if (!this.env.model.getters.isSelectingForComposer() &&
21126
- !(ev.key === "Enter" && (ev.altKey || ev.ctrlKey))) {
21127
- this.env.model.dispatch("CHANGE_COMPOSER_CURSOR_SELECTION", { start, end });
21128
- this.isKeyStillDown = true;
21129
- }
21130
21163
  }
21131
21164
  /*
21132
21165
  * Triggered automatically by the content-editable between the keydown and key up
21133
21166
  * */
21134
- onInput() {
21167
+ onInput(ev) {
21135
21168
  if (this.props.focus === "inactive" || !this.shouldProcessInputEvents) {
21136
21169
  return;
21137
21170
  }
21171
+ let content = this.contentHelper.getText();
21172
+ let selection = this.contentHelper.getCurrentSelection();
21173
+ if (ev.inputType === "insertParagraph") {
21174
+ const start = Math.min(selection.start, selection.end);
21175
+ const end = Math.max(selection.start, selection.end);
21176
+ content = content.slice(0, start) + NEWLINE + content.slice(end);
21177
+ selection = { start: start + 1, end: start + 1 };
21178
+ }
21138
21179
  this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
21139
21180
  this.env.model.dispatch("SET_CURRENT_CONTENT", {
21140
- content: this.contentHelper.getText(),
21141
- selection: this.contentHelper.getCurrentSelection(),
21181
+ content,
21182
+ selection,
21142
21183
  });
21184
+ this.processTokenAtCursor();
21143
21185
  }
21144
- onKeyup(ev) {
21145
- this.isKeyStillDown = false;
21146
- if (this.props.focus === "inactive" ||
21147
- ["Control", "Alt", "Shift", "Tab", "Enter", "F4"].includes(ev.key)) {
21148
- return;
21149
- }
21150
- if (this.autoCompleteState.showProvider && ["ArrowUp", "ArrowDown"].includes(ev.key)) {
21151
- return; // already processed in keydown
21152
- }
21153
- if (this.env.model.getters.isSelectingForComposer() &&
21154
- ["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"].includes(ev.key)) {
21155
- return; // already processed in keydown
21156
- }
21157
- ev.preventDefault();
21158
- ev.stopPropagation();
21159
- this.autoCompleteState.showProvider = false;
21160
- if (ev.ctrlKey && ev.key === " ") {
21161
- this.showAutocomplete("");
21162
- this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
21163
- return;
21164
- }
21165
- const { start: oldStart, end: oldEnd } = this.env.model.getters.getComposerSelection();
21166
- const { start, end } = this.contentHelper.getCurrentSelection();
21167
- if (start !== oldStart || end !== oldEnd) {
21168
- this.env.model.dispatch("CHANGE_COMPOSER_CURSOR_SELECTION", this.contentHelper.getCurrentSelection());
21186
+ onKeyup() {
21187
+ if (this.contentHelper.el === document.activeElement) {
21188
+ const { start: oldStart, end: oldEnd } = this.env.model.getters.getComposerSelection();
21189
+ const { start, end } = this.contentHelper.getCurrentSelection();
21190
+ if (start !== oldStart || end !== oldEnd) {
21191
+ this.env.model.dispatch("CHANGE_COMPOSER_CURSOR_SELECTION", { start, end });
21192
+ }
21169
21193
  }
21170
- this.processTokenAtCursor();
21171
- this.processContent();
21172
21194
  }
21173
21195
  showAutocomplete(searchTerm) {
21196
+ if (!this.env.model.getters.getCurrentContent().startsWith("=")) {
21197
+ return;
21198
+ }
21174
21199
  this.autoCompleteState.showProvider = true;
21175
21200
  let values = Object.entries(functionRegistry.content)
21176
21201
  .filter(([_, { hidden }]) => !hidden)
@@ -21190,13 +21215,6 @@ class Composer extends owl.Component {
21190
21215
  this.autoCompleteState.values = values.slice(0, 10);
21191
21216
  this.autoCompleteState.selectedIndex = 0;
21192
21217
  }
21193
- onMousedown(ev) {
21194
- if (ev.button > 0) {
21195
- // not main button, probably a context menu
21196
- return;
21197
- }
21198
- this.contentHelper.removeSelection();
21199
- }
21200
21218
  onClick() {
21201
21219
  if (this.env.model.getters.isReadonly()) {
21202
21220
  return;
@@ -21209,9 +21227,6 @@ class Composer extends owl.Component {
21209
21227
  this.env.model.dispatch("CHANGE_COMPOSER_CURSOR_SELECTION", newSelection);
21210
21228
  this.processTokenAtCursor();
21211
21229
  }
21212
- onBlur() {
21213
- this.isKeyStillDown = false;
21214
- }
21215
21230
  // ---------------------------------------------------------------------------
21216
21231
  // Private
21217
21232
  // ---------------------------------------------------------------------------
@@ -21219,22 +21234,19 @@ class Composer extends owl.Component {
21219
21234
  if (this.compositionActive) {
21220
21235
  return;
21221
21236
  }
21222
- const oldScroll = getElementScrollTop(this.composerRef.el);
21223
- this.contentHelper.removeAll(); // removes the content of the composer, to be added just after
21224
21237
  this.shouldProcessInputEvents = false;
21225
21238
  if (this.props.focus !== "inactive") {
21226
21239
  this.contentHelper.el.focus();
21227
- this.contentHelper.selectRange(0, 0); // move the cursor inside the composer at 0 0.
21228
21240
  }
21229
21241
  const content = this.getContentLines();
21242
+ this.contentHelper.setText(content);
21230
21243
  if (content.length !== 0 && content.length[0] !== 0) {
21231
- this.contentHelper.setText(content);
21232
- const { start, end } = this.env.model.getters.getComposerSelection();
21233
21244
  if (this.props.focus !== "inactive") {
21234
21245
  // Put the cursor back where it was before the rendering
21246
+ const { start, end } = this.env.model.getters.getComposerSelection();
21235
21247
  this.contentHelper.selectRange(start, end);
21236
21248
  }
21237
- setElementScrollTop(this.composerRef.el, oldScroll);
21249
+ this.contentHelper.scrollSelectionIntoView();
21238
21250
  }
21239
21251
  this.shouldProcessInputEvents = true;
21240
21252
  }
@@ -21489,8 +21501,8 @@ class GridComposer extends owl.Component {
21489
21501
  height: el.clientHeight,
21490
21502
  };
21491
21503
  this.composerState.delimitation = {
21492
- width: el.parentElement.clientWidth,
21493
- height: el.parentElement.clientHeight,
21504
+ width: this.props.gridDims.width,
21505
+ height: this.props.gridDims.height,
21494
21506
  };
21495
21507
  });
21496
21508
  owl.onWillUpdateProps(() => {
@@ -23208,7 +23220,7 @@ class Highlight extends owl.Component {
23208
23220
  shiftingMode: "none",
23209
23221
  });
23210
23222
  onResizeHighlight(isLeft, isTop) {
23211
- const activeSheet = this.env.model.getters.getActiveSheet();
23223
+ const activeSheetId = this.env.model.getters.getActiveSheetId();
23212
23224
  this.highlightState.shiftingMode = "isResizing";
23213
23225
  const z = this.props.zone;
23214
23226
  const pivotCol = isLeft ? z.right : z.left;
@@ -23217,11 +23229,10 @@ class Highlight extends owl.Component {
23217
23229
  let lastRow = isTop ? z.top : z.bottom;
23218
23230
  let currentZone = z;
23219
23231
  this.env.model.dispatch("START_CHANGE_HIGHLIGHT", {
23220
- range: this.env.model.getters.getRangeDataFromZone(activeSheet.id, currentZone),
23232
+ range: this.env.model.getters.getRangeDataFromZone(activeSheetId, currentZone),
23221
23233
  });
23222
23234
  const mouseMove = (col, row) => {
23223
23235
  if (lastCol !== col || lastRow !== row) {
23224
- const activeSheetId = this.env.model.getters.getActiveSheetId();
23225
23236
  lastCol = clip(col === -1 ? lastCol : col, 0, this.env.model.getters.getNumberCols(activeSheetId) - 1);
23226
23237
  lastRow = clip(row === -1 ? lastRow : row, 0, this.env.model.getters.getNumberRows(activeSheetId) - 1);
23227
23238
  let newZone = {
@@ -23233,7 +23244,7 @@ class Highlight extends owl.Component {
23233
23244
  newZone = this.env.model.getters.expandZone(activeSheetId, newZone);
23234
23245
  if (!isEqual(newZone, currentZone)) {
23235
23246
  this.env.model.dispatch("CHANGE_HIGHLIGHT", {
23236
- range: this.env.model.getters.getRangeDataFromZone(activeSheet.id, newZone),
23247
+ range: this.env.model.getters.getRangeFromZone(activeSheetId, this.env.model.getters.getUnboundedZone(activeSheetId, newZone)).rangeData,
23237
23248
  });
23238
23249
  currentZone = newZone;
23239
23250
  }
@@ -23280,7 +23291,7 @@ class Highlight extends owl.Component {
23280
23291
  newZone = this.env.model.getters.expandZone(activeSheetId, newZone);
23281
23292
  if (!isEqual(newZone, currentZone)) {
23282
23293
  this.env.model.dispatch("CHANGE_HIGHLIGHT", {
23283
- range: this.env.model.getters.getRangeDataFromZone(activeSheetId, newZone),
23294
+ range: this.env.model.getters.getRangeFromZone(activeSheetId, this.env.model.getters.getUnboundedZone(activeSheetId, newZone)).rangeData,
23284
23295
  });
23285
23296
  currentZone = newZone;
23286
23297
  }
@@ -24602,6 +24613,16 @@ const XLSX_INDEXED_COLORS = {
24602
24613
  63: "333333",
24603
24614
  64: "000000",
24604
24615
  65: "FFFFFF", // system background
24616
+ };
24617
+ const IMAGE_MIMETYPE_EXTENSION_MAPPING = {
24618
+ "image/avif": "avif",
24619
+ "image/bmp": "bmp",
24620
+ "image/gif": "gif",
24621
+ "image/vnd.microsoft.icon": "ico",
24622
+ "image/jpeg": "jpeg",
24623
+ "image/png": "png",
24624
+ "image/tiff": "tiff",
24625
+ "image/webp": "webp",
24605
24626
  };
24606
24627
 
24607
24628
  /**
@@ -27084,6 +27105,11 @@ function createOverride(partName, contentType) {
27084
27105
  <Override ContentType="${contentType}" PartName="${partName}" />
27085
27106
  `;
27086
27107
  }
27108
+ function createDefaultXMLElement(extension, contentType) {
27109
+ return escapeXml /*xml*/ `
27110
+ <Default Extension="${extension}" ContentType="${contentType}" />
27111
+ `;
27112
+ }
27087
27113
  function joinXmlNodes(xmlNodes) {
27088
27114
  return new XMLString(xmlNodes.join("\n"));
27089
27115
  }
@@ -31525,6 +31551,7 @@ class MergePlugin extends CorePlugin {
31525
31551
  "getMerge",
31526
31552
  "getMergesInZone",
31527
31553
  "isSingleCellOrMerge",
31554
+ "getSelectionRangeString",
31528
31555
  ];
31529
31556
  nextId = 1;
31530
31557
  merges = {};
@@ -31612,6 +31639,26 @@ class MergePlugin extends CorePlugin {
31612
31639
  .map((mergeId) => this.getMergeById(sheetId, mergeId))
31613
31640
  .filter(isDefined$1);
31614
31641
  }
31642
+ /**
31643
+ * Same as `getRangeString` but add all necessary merge to the range to make it a valid selection
31644
+ */
31645
+ getSelectionRangeString(range, forSheetId) {
31646
+ const rangeImpl = RangeImpl.fromRange(range, this.getters);
31647
+ const expandedZone = this.getters.expandZone(rangeImpl.sheetId, rangeImpl.zone);
31648
+ const expandedRange = rangeImpl.clone({
31649
+ zone: {
31650
+ ...expandedZone,
31651
+ bottom: rangeImpl.isFullCol ? undefined : expandedZone.bottom,
31652
+ right: rangeImpl.isFullRow ? undefined : expandedZone.right,
31653
+ },
31654
+ });
31655
+ const rangeString = this.getters.getRangeString(expandedRange, forSheetId);
31656
+ if (this.isSingleCellOrMerge(rangeImpl.sheetId, rangeImpl.zone)) {
31657
+ const { sheetName, xc } = splitReference(rangeString);
31658
+ return `${sheetName !== undefined ? getCanonicalSheetName(sheetName) + "!" : ""}${xc.split(":")[0]}`;
31659
+ }
31660
+ return rangeString;
31661
+ }
31615
31662
  /**
31616
31663
  * Return true if the zone intersects an existing merge:
31617
31664
  * if they have at least a common cell
@@ -31944,12 +31991,12 @@ class RangeAdapter {
31944
31991
  }
31945
31992
  static getters = [
31946
31993
  "getRangeString",
31947
- "getSelectionRangeString",
31948
31994
  "getRangeFromSheetXC",
31949
31995
  "createAdaptedRanges",
31950
31996
  "getRangeDataFromXc",
31951
31997
  "getRangeDataFromZone",
31952
31998
  "getRangeFromRangeData",
31999
+ "getRangeFromZone",
31953
32000
  ];
31954
32001
  // ---------------------------------------------------------------------------
31955
32002
  // Command Handling
@@ -32198,21 +32245,6 @@ class RangeAdapter {
32198
32245
  const rangeInterface = { prefixSheet, zone, sheetId, invalidSheetName, parts };
32199
32246
  return new RangeImpl(rangeInterface, this.getters.getSheetSize).orderZone();
32200
32247
  }
32201
- /**
32202
- * Same as `getRangeString` but add all necessary merge to the range to make it a valid selection
32203
- */
32204
- getSelectionRangeString(range, forSheetId) {
32205
- const rangeImpl = RangeImpl.fromRange(range, this.getters);
32206
- const expandedZone = this.getters.expandZone(rangeImpl.sheetId, rangeImpl.zone);
32207
- const expandedRange = rangeImpl.clone({
32208
- zone: {
32209
- ...expandedZone,
32210
- bottom: rangeImpl.isFullCol ? undefined : expandedZone.bottom,
32211
- right: rangeImpl.isFullRow ? undefined : expandedZone.right,
32212
- },
32213
- });
32214
- return this.getRangeString(expandedRange, forSheetId);
32215
- }
32216
32248
  /**
32217
32249
  * Gets the string that represents the range as it is at the moment of the call.
32218
32250
  * The string will be prefixed with the sheet name if the call specified a sheet id in `forSheetId`
@@ -32269,6 +32301,17 @@ class RangeAdapter {
32269
32301
  getRangeDataFromZone(sheetId, zone) {
32270
32302
  return { _sheetId: sheetId, _zone: zone };
32271
32303
  }
32304
+ getRangeFromZone(sheetId, zone) {
32305
+ return new RangeImpl({
32306
+ sheetId,
32307
+ zone,
32308
+ parts: [
32309
+ { colFixed: false, rowFixed: false },
32310
+ { colFixed: false, rowFixed: false },
32311
+ ],
32312
+ prefixSheet: false,
32313
+ }, this.getters.getSheetSize);
32314
+ }
32272
32315
  getRangeFromRangeData(data) {
32273
32316
  const rangeInterface = {
32274
32317
  prefixSheet: false,
@@ -32354,6 +32397,7 @@ class SheetPlugin extends CorePlugin {
32354
32397
  "getPaneDivisions",
32355
32398
  "checkZonesExistInSheet",
32356
32399
  "getCommandZones",
32400
+ "getUnboundedZone",
32357
32401
  ];
32358
32402
  sheetIdsMapName = {};
32359
32403
  orderedSheetIds = [];
@@ -32679,6 +32723,16 @@ class SheetPlugin extends CorePlugin {
32679
32723
  right: this.getNumberCols(sheetId) - 1,
32680
32724
  };
32681
32725
  }
32726
+ getUnboundedZone(sheetId, zone) {
32727
+ const isFullRow = zone.left === 0 && zone.right === this.getNumberCols(sheetId) - 1;
32728
+ const isFullCol = zone.top === 0 && zone.bottom === this.getNumberRows(sheetId) - 1;
32729
+ return {
32730
+ ...zone,
32731
+ bottom: isFullCol ? undefined : zone.bottom,
32732
+ // cannot be unbounded in the 2 dimensions at once
32733
+ right: isFullRow && !isFullCol ? undefined : zone.right,
32734
+ };
32735
+ }
32682
32736
  getPaneDivisions(sheetId) {
32683
32737
  return this.getSheet(sheetId).panes;
32684
32738
  }
@@ -38729,11 +38783,11 @@ class SelectionInputPlugin extends UIPlugin {
38729
38783
  return 0 /* CommandResult.Success */;
38730
38784
  }
38731
38785
  handleEvent(event) {
38732
- const xc = zoneToXc(event.anchor.zone);
38733
38786
  const inputSheetId = this.activeSheet;
38734
38787
  const sheetId = this.getters.getActiveSheetId();
38735
- const sheetName = this.getters.getSheetName(sheetId);
38736
- this.add([sheetId === inputSheetId ? xc : `${getCanonicalSheetName(sheetName)}!${xc}`]);
38788
+ const zone = event.anchor.zone;
38789
+ const range = this.getters.getRangeFromZone(sheetId, event.type === "HeadersSelected" ? this.getters.getUnboundedZone(sheetId, zone) : zone);
38790
+ this.add([this.getters.getSelectionRangeString(range, inputSheetId)]);
38737
38791
  }
38738
38792
  handle(cmd) {
38739
38793
  switch (cmd.type) {
@@ -41191,12 +41245,20 @@ class EditionPlugin extends UIPlugin {
41191
41245
  if (this.mode !== "selecting") {
41192
41246
  return;
41193
41247
  }
41248
+ const sheetId = this.getters.getActiveSheetId();
41249
+ let unboundedZone;
41250
+ if (event.type === "HeadersSelected") {
41251
+ unboundedZone = this.getters.getUnboundedZone(sheetId, event.anchor.zone);
41252
+ }
41253
+ else {
41254
+ unboundedZone = event.anchor.zone;
41255
+ }
41194
41256
  switch (event.mode) {
41195
41257
  case "newAnchor":
41196
- this.insertSelectedRange(event.anchor.zone);
41258
+ this.insertSelectedRange(unboundedZone);
41197
41259
  break;
41198
41260
  default:
41199
- this.replaceSelectedRanges(event.anchor.zone);
41261
+ this.replaceSelectedRanges(unboundedZone);
41200
41262
  break;
41201
41263
  }
41202
41264
  }
@@ -41253,7 +41315,9 @@ class EditionPlugin extends UIPlugin {
41253
41315
  }
41254
41316
  break;
41255
41317
  case "START_CHANGE_HIGHLIGHT":
41318
+ // FIXME: thiws whole ordeal could be handled with the Selection Processor which would extend the feature to selection inputs
41256
41319
  this.dispatch("STOP_COMPOSER_RANGE_SELECTION");
41320
+ // FIXME: we should check range SheetId compared to this.activeSheetId r maybe not have a sheetId in the payload ??
41257
41321
  const range = this.getters.getRangeFromRangeData(cmd.range);
41258
41322
  const previousRefToken = this.currentTokens
41259
41323
  .filter((token) => token.type === "REFERENCE")
@@ -41607,14 +41671,11 @@ class EditionPlugin extends UIPlugin {
41607
41671
  const ref = this.getZoneReference(zone);
41608
41672
  this.replaceText(ref, this.selectionInitialStart, this.selectionEnd);
41609
41673
  }
41610
- getZoneReference(zone, fixedParts = [{ colFixed: false, rowFixed: false }]) {
41674
+ getZoneReference(zone) {
41675
+ const inputSheetId = this.getters.getCurrentEditedCell().sheetId;
41611
41676
  const sheetId = this.getters.getActiveSheetId();
41612
- let selectedXc = this.getters.zoneToXC(sheetId, zone, fixedParts);
41613
- if (this.getters.getCurrentEditedCell().sheetId !== this.getters.getActiveSheetId()) {
41614
- const sheetName = getCanonicalSheetName(this.getters.getSheetName(this.getters.getActiveSheetId()));
41615
- selectedXc = `${sheetName}!${selectedXc}`;
41616
- }
41617
- return selectedXc;
41677
+ const range = this.getters.getRangeFromZone(sheetId, zone);
41678
+ return this.getters.getSelectionRangeString(range, inputSheetId);
41618
41679
  }
41619
41680
  getRangeReference(range, fixedParts = [{ colFixed: false, rowFixed: false }]) {
41620
41681
  let _fixedParts = [...fixedParts];
@@ -42468,7 +42529,7 @@ class ImageProvider {
42468
42529
  const file = await this.getImageFromUser();
42469
42530
  const path = await this.fileStore.upload(file);
42470
42531
  const size = await this.getImageSize(path);
42471
- return { path, size };
42532
+ return { path, size, mimetype: file.type };
42472
42533
  }
42473
42534
  getImageFromUser() {
42474
42535
  return new Promise((resolve, reject) => {
@@ -47535,8 +47596,7 @@ function createWorksheets(data, construct) {
47535
47596
  // Figures and Charts
47536
47597
  let drawingNode = escapeXml ``;
47537
47598
  const drawingRelIds = [];
47538
- const charts = sheet.charts;
47539
- for (const chart of charts) {
47599
+ for (const chart of sheet.charts) {
47540
47600
  const xlsxChartId = convertChartId(chart.id);
47541
47601
  const chartRelId = addRelsToFile(construct.relsFiles, `xl/drawings/_rels/drawing${sheetIndex}.xml.rels`, {
47542
47602
  target: `../charts/chart${xlsxChartId}.xml`,
@@ -47545,20 +47605,27 @@ function createWorksheets(data, construct) {
47545
47605
  drawingRelIds.push(chartRelId);
47546
47606
  files.push(createXMLFile(createChart(chart, sheetIndex, data), `xl/charts/chart${xlsxChartId}.xml`, "chart"));
47547
47607
  }
47548
- const images = sheet.images;
47549
- for (const image of images) {
47608
+ for (const image of sheet.images) {
47609
+ const mimeType = image.data.mimetype;
47610
+ if (mimeType === undefined)
47611
+ continue;
47612
+ const extension = IMAGE_MIMETYPE_EXTENSION_MAPPING[mimeType];
47613
+ // only support exporting images with mimetypes specified in the mapping
47614
+ if (extension === undefined)
47615
+ continue;
47550
47616
  const xlsxImageId = convertImageId(image.id);
47617
+ let imageFileName = `image${xlsxImageId}.${extension}`;
47551
47618
  const imageRelId = addRelsToFile(construct.relsFiles, `xl/drawings/_rels/drawing${sheetIndex}.xml.rels`, {
47552
- target: `../media/image${xlsxImageId}`,
47619
+ target: `../media/${imageFileName}`,
47553
47620
  type: XLSX_RELATION_TYPE.image,
47554
47621
  });
47555
47622
  drawingRelIds.push(imageRelId);
47556
47623
  files.push({
47557
- path: `xl/media/image${xlsxImageId}`,
47558
- imagePath: image.data.path,
47624
+ path: `xl/media/${imageFileName}`,
47625
+ imageSrc: image.data.path,
47559
47626
  });
47560
47627
  }
47561
- const drawings = [...charts, ...images];
47628
+ const drawings = [...sheet.charts, ...sheet.images];
47562
47629
  if (drawings.length) {
47563
47630
  const drawingRelId = addRelsToFile(construct.relsFiles, `xl/worksheets/_rels/sheet${sheetIndex}.xml.rels`, {
47564
47631
  target: `../drawings/drawing${sheetIndex}.xml`,
@@ -47677,6 +47744,8 @@ function createRelsFiles(relsFiles) {
47677
47744
  }
47678
47745
  function createContentTypes(files) {
47679
47746
  const overrideNodes = [];
47747
+ // hard-code supported image mimetypes
47748
+ const imageDefaultNodes = Object.entries(IMAGE_MIMETYPE_EXTENSION_MAPPING).map(([mimetype, extension]) => createDefaultXMLElement(extension, mimetype));
47680
47749
  for (const file of files) {
47681
47750
  if ("contentType" in file && file.contentType) {
47682
47751
  overrideNodes.push(createOverride("/" + file.path, CONTENT_TYPES[file.contentType]));
@@ -47692,6 +47761,7 @@ function createContentTypes(files) {
47692
47761
  ];
47693
47762
  const xml = escapeXml /*xml*/ `
47694
47763
  <Types xmlns="${NAMESPACE["Types"]}">
47764
+ ${joinXmlNodes(Object.values(imageDefaultNodes))}
47695
47765
  <Default ${formatAttributes(relsAttributes)} />
47696
47766
  <Default ${formatAttributes(xmlAttributes)} />
47697
47767
  ${joinXmlNodes(overrideNodes)}
@@ -47783,7 +47853,7 @@ class Model extends EventBus {
47783
47853
  this.coreGetters.getRangeDataFromXc = this.range.getRangeDataFromXc.bind(this.range);
47784
47854
  this.coreGetters.getRangeDataFromZone = this.range.getRangeDataFromZone.bind(this.range);
47785
47855
  this.coreGetters.getRangeFromRangeData = this.range.getRangeFromRangeData.bind(this.range);
47786
- this.coreGetters.getSelectionRangeString = this.range.getSelectionRangeString.bind(this.range);
47856
+ this.coreGetters.getRangeFromZone = this.range.getRangeFromZone.bind(this.range);
47787
47857
  this.getters = {
47788
47858
  isReadonly: () => this.config.mode === "readonly" || this.config.mode === "dashboard",
47789
47859
  isDashboard: () => this.config.mode === "dashboard",
@@ -48304,6 +48374,6 @@ exports.setTranslationMethod = setTranslationMethod;
48304
48374
  exports.tokenize = tokenize;
48305
48375
 
48306
48376
 
48307
- __info__.version = '16.4.0-alpha.2';
48308
- __info__.date = '2023-05-26T13:40:49.561Z';
48309
- __info__.hash = '82328ad';
48377
+ __info__.version = '16.4.0-alpha.3';
48378
+ __info__.date = '2023-06-02T10:13:30.127Z';
48379
+ __info__.hash = '059d66a';