@odoo/o-spreadsheet 18.4.0-alpha.8 → 18.4.0-alpha.9
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/o-spreadsheet.cjs.js +758 -514
- package/dist/o-spreadsheet.d.ts +25 -3
- package/dist/o-spreadsheet.esm.js +758 -514
- package/dist/o-spreadsheet.iife.js +758 -514
- package/dist/o-spreadsheet.iife.min.js +394 -394
- package/dist/o_spreadsheet.xml +25 -6
- package/package.json +1 -1
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* This file is generated by o-spreadsheet build tools. Do not edit it.
|
|
4
4
|
* @see https://github.com/odoo/o-spreadsheet
|
|
5
|
-
* @version 18.4.0-alpha.
|
|
6
|
-
* @date 2025-06-
|
|
7
|
-
* @hash
|
|
5
|
+
* @version 18.4.0-alpha.9
|
|
6
|
+
* @date 2025-06-19T18:23:22.025Z
|
|
7
|
+
* @hash 6d4d685
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { useEnv, useSubEnv, onWillUnmount, useComponent, status, Component, useRef, onMounted, useEffect, App, blockDom, useState, onPatched, useExternalListener, onWillUpdateProps, onWillStart, onWillPatch, xml, useChildSubEnv, markRaw, toRaw } from '@odoo/owl';
|
|
@@ -20,13 +20,21 @@ function createAction(item) {
|
|
|
20
20
|
const icon = item.icon;
|
|
21
21
|
const secondaryIcon = item.secondaryIcon;
|
|
22
22
|
const itemId = item.id || nextItemId++;
|
|
23
|
+
const isEnabled = item.isEnabled ? item.isEnabled : () => true;
|
|
23
24
|
return {
|
|
24
25
|
id: itemId.toString(),
|
|
25
26
|
name: typeof name === "function" ? name : () => name,
|
|
26
27
|
isVisible: item.isVisible ? item.isVisible : () => true,
|
|
27
|
-
isEnabled:
|
|
28
|
+
isEnabled: isEnabled,
|
|
28
29
|
isActive: item.isActive,
|
|
29
|
-
execute: item.execute
|
|
30
|
+
execute: item.execute
|
|
31
|
+
? (env, isMiddleClick) => {
|
|
32
|
+
if (isEnabled(env)) {
|
|
33
|
+
return item.execute(env, isMiddleClick);
|
|
34
|
+
}
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
: undefined,
|
|
30
38
|
children: children
|
|
31
39
|
? (env) => {
|
|
32
40
|
return children
|
|
@@ -297,6 +305,7 @@ const GROUP_LAYER_WIDTH = 21;
|
|
|
297
305
|
const GRID_ICON_MARGIN = 2;
|
|
298
306
|
const GRID_ICON_EDGE_LENGTH = 17;
|
|
299
307
|
const FOOTER_HEIGHT = 2 * DEFAULT_CELL_HEIGHT;
|
|
308
|
+
const DATA_VALIDATION_CHIP_MARGIN = 5;
|
|
300
309
|
// 768px is a common breakpoint for small screens
|
|
301
310
|
// Typically inside Odoo, it is the threshold for switching to mobile view
|
|
302
311
|
const MOBILE_WIDTH_BREAKPOINT = 768;
|
|
@@ -642,9 +651,6 @@ function parseSheetUrl(sheetLink) {
|
|
|
642
651
|
function isDefined(argument) {
|
|
643
652
|
return argument !== undefined;
|
|
644
653
|
}
|
|
645
|
-
function isNotNull(argument) {
|
|
646
|
-
return argument !== null;
|
|
647
|
-
}
|
|
648
654
|
/**
|
|
649
655
|
* Check if all the values of an object, and all the values of the objects inside of it, are undefined.
|
|
650
656
|
*/
|
|
@@ -1355,9 +1361,16 @@ function darkenColor(color, percentage) {
|
|
|
1355
1361
|
if (percentage === 1) {
|
|
1356
1362
|
return "#000";
|
|
1357
1363
|
}
|
|
1364
|
+
// increase saturation to compensate and make it more vivid
|
|
1365
|
+
hsla.s = Math.min(100, percentage * hsla.s + hsla.s);
|
|
1358
1366
|
hsla.l = hsla.l - percentage * hsla.l;
|
|
1359
1367
|
return hslaToHex(hsla);
|
|
1360
1368
|
}
|
|
1369
|
+
function chipTextColor(chipBackgroundColor) {
|
|
1370
|
+
return relativeLuminance(chipBackgroundColor) < 0.6
|
|
1371
|
+
? lightenColor(chipBackgroundColor, 0.9)
|
|
1372
|
+
: darkenColor(chipBackgroundColor, 0.75);
|
|
1373
|
+
}
|
|
1361
1374
|
const COLORS_SM = [
|
|
1362
1375
|
"#4EA7F2", // Blue
|
|
1363
1376
|
"#EA6175", // Red
|
|
@@ -21686,6 +21699,7 @@ function drawLineOrBarOrRadarChartValues(chart, options, ctx) {
|
|
|
21686
21699
|
if (isTrendLineAxis(dataset.xAxisID) || dataset.hidden) {
|
|
21687
21700
|
continue;
|
|
21688
21701
|
}
|
|
21702
|
+
const yAxisScale = chart.scales[dataset.yAxisID];
|
|
21689
21703
|
for (let i = 0; i < dataset._parsed.length; i++) {
|
|
21690
21704
|
const parsedValue = dataset._parsed[i];
|
|
21691
21705
|
const value = Number(chart.config.type === "radar" ? parsedValue.r : parsedValue.y);
|
|
@@ -21696,10 +21710,18 @@ function drawLineOrBarOrRadarChartValues(chart, options, ctx) {
|
|
|
21696
21710
|
const xPosition = point.x;
|
|
21697
21711
|
let yPosition = 0;
|
|
21698
21712
|
if (chart.config.type === "line" || chart.config.type === "radar") {
|
|
21699
|
-
yPosition = point.y - 10;
|
|
21713
|
+
yPosition = value < 0 ? point.y + 10 : point.y - 10;
|
|
21700
21714
|
}
|
|
21701
21715
|
else {
|
|
21702
|
-
|
|
21716
|
+
const yZeroLine = yAxisScale.getPixelForValue(0);
|
|
21717
|
+
const distanceFromAxisOrigin = Math.abs(yZeroLine - point.y);
|
|
21718
|
+
const textHeight = 12; // ChartJS default text height
|
|
21719
|
+
if (distanceFromAxisOrigin < textHeight) {
|
|
21720
|
+
yPosition = value < 0 ? yZeroLine + textHeight / 2 : yZeroLine - textHeight / 2;
|
|
21721
|
+
}
|
|
21722
|
+
else {
|
|
21723
|
+
yPosition = value < 0 ? point.y - point.height / 2 : point.y + point.height / 2;
|
|
21724
|
+
}
|
|
21703
21725
|
}
|
|
21704
21726
|
yPosition = Math.min(yPosition, yMax);
|
|
21705
21727
|
yPosition = Math.max(yPosition, yMin);
|
|
@@ -21709,7 +21731,7 @@ function drawLineOrBarOrRadarChartValues(chart, options, ctx) {
|
|
|
21709
21731
|
}
|
|
21710
21732
|
for (const otherPosition of textsPositions[xPosition] || []) {
|
|
21711
21733
|
if (Math.abs(otherPosition - yPosition) < 13) {
|
|
21712
|
-
yPosition = otherPosition - 13;
|
|
21734
|
+
yPosition = value < 0 ? otherPosition + 13 : otherPosition - 13;
|
|
21713
21735
|
}
|
|
21714
21736
|
}
|
|
21715
21737
|
textsPositions[xPosition].push(yPosition);
|
|
@@ -21728,6 +21750,8 @@ function drawHorizontalBarChartValues(chart, options, ctx) {
|
|
|
21728
21750
|
if (isTrendLineAxis(dataset.xAxisID)) {
|
|
21729
21751
|
return; // ignore trend lines
|
|
21730
21752
|
}
|
|
21753
|
+
const xAxisScale = chart.scales[dataset.xAxisID];
|
|
21754
|
+
const xZeroLine = xAxisScale.getPixelForValue(0);
|
|
21731
21755
|
for (let i = 0; i < dataset._parsed.length; i++) {
|
|
21732
21756
|
const value = Number(dataset._parsed[i].x);
|
|
21733
21757
|
if (isNaN(value)) {
|
|
@@ -21736,17 +21760,27 @@ function drawHorizontalBarChartValues(chart, options, ctx) {
|
|
|
21736
21760
|
const displayValue = options.callback(value, dataset, i);
|
|
21737
21761
|
const point = dataset.data[i];
|
|
21738
21762
|
const yPosition = point.y;
|
|
21739
|
-
|
|
21740
|
-
|
|
21741
|
-
|
|
21763
|
+
const textWidth = computeTextWidth(ctx, displayValue, { fontSize: 12 }, "px");
|
|
21764
|
+
const distanceFromAxisOrigin = Math.abs(point.x - xZeroLine);
|
|
21765
|
+
const PADDING = 3;
|
|
21766
|
+
let xPosition;
|
|
21767
|
+
if (distanceFromAxisOrigin < textWidth) {
|
|
21768
|
+
xPosition =
|
|
21769
|
+
value < 0 ? xZeroLine - textWidth / 2 - PADDING : xZeroLine + textWidth / 2 + PADDING;
|
|
21770
|
+
}
|
|
21771
|
+
else {
|
|
21772
|
+
xPosition = value < 0 ? point.x + point.width / 2 : point.x - point.width / 2;
|
|
21773
|
+
xPosition = Math.min(xPosition, xMax);
|
|
21774
|
+
xPosition = Math.max(xPosition, xMin);
|
|
21775
|
+
}
|
|
21742
21776
|
// Avoid overlapping texts with same Y
|
|
21743
21777
|
if (!textsPositions[yPosition]) {
|
|
21744
21778
|
textsPositions[yPosition] = [];
|
|
21745
21779
|
}
|
|
21746
|
-
const textWidth = computeTextWidth(ctx, displayValue, { fontSize: 12 }, "px");
|
|
21747
21780
|
for (const otherPosition of textsPositions[yPosition]) {
|
|
21748
21781
|
if (Math.abs(otherPosition - xPosition) < textWidth) {
|
|
21749
|
-
xPosition =
|
|
21782
|
+
xPosition =
|
|
21783
|
+
value < 0 ? otherPosition - textWidth - PADDING : otherPosition + textWidth + PADDING;
|
|
21750
21784
|
}
|
|
21751
21785
|
}
|
|
21752
21786
|
textsPositions[yPosition].push(xPosition);
|
|
@@ -25680,7 +25714,9 @@ function getPyramidChartShowValues(definition, args) {
|
|
|
25680
25714
|
background: definition.background,
|
|
25681
25715
|
callback: (value, dataset) => {
|
|
25682
25716
|
value = Math.abs(Number(value));
|
|
25683
|
-
return
|
|
25717
|
+
return value === 0
|
|
25718
|
+
? ""
|
|
25719
|
+
: formatChartDatasetValue(axisFormats, locale)(value, dataset.xAxisID || "x");
|
|
25684
25720
|
},
|
|
25685
25721
|
};
|
|
25686
25722
|
}
|
|
@@ -29341,6 +29377,12 @@ class Menu extends Component {
|
|
|
29341
29377
|
menu.onStopHover?.(this.env);
|
|
29342
29378
|
this.props.onMouseLeave?.(menu, ev);
|
|
29343
29379
|
}
|
|
29380
|
+
onClickMenu(menu, ev) {
|
|
29381
|
+
if (!this.isEnabled(menu)) {
|
|
29382
|
+
return;
|
|
29383
|
+
}
|
|
29384
|
+
this.props.onClickMenu?.(menu, ev);
|
|
29385
|
+
}
|
|
29344
29386
|
}
|
|
29345
29387
|
|
|
29346
29388
|
/**
|
|
@@ -29839,9 +29881,6 @@ class MenuPopover extends Component {
|
|
|
29839
29881
|
this.subMenu.parentMenu = undefined;
|
|
29840
29882
|
}
|
|
29841
29883
|
onClickMenu(menu, ev) {
|
|
29842
|
-
if (!this.isEnabled(menu)) {
|
|
29843
|
-
return;
|
|
29844
|
-
}
|
|
29845
29884
|
if (this.isRoot(menu)) {
|
|
29846
29885
|
this.openSubMenu(menu, ev.currentTarget);
|
|
29847
29886
|
}
|
|
@@ -31092,11 +31131,9 @@ criterionEvaluatorRegistry.add("isValueInRange", {
|
|
|
31092
31131
|
if (!value) {
|
|
31093
31132
|
return false;
|
|
31094
31133
|
}
|
|
31095
|
-
const
|
|
31096
|
-
const criterionValues = getters.getRangeValues(range);
|
|
31134
|
+
const criterionValues = getters.getDataValidationRangeValues(sheetId, criterion);
|
|
31097
31135
|
return criterionValues
|
|
31098
|
-
.
|
|
31099
|
-
.map((value) => value.toString().toLowerCase())
|
|
31136
|
+
.map((value) => value.toLowerCase())
|
|
31100
31137
|
.includes(value.toString().toLowerCase());
|
|
31101
31138
|
},
|
|
31102
31139
|
getErrorString: (criterion) => _t("The value must be a value in the range %s", String(criterion.values[0])),
|
|
@@ -31268,6 +31305,12 @@ class TextValueProvider extends Component {
|
|
|
31268
31305
|
selectedElement?.scrollIntoView?.({ block: "nearest" });
|
|
31269
31306
|
}, () => [this.props.selectedIndex, this.autoCompleteListRef.el]);
|
|
31270
31307
|
}
|
|
31308
|
+
getCss(html) {
|
|
31309
|
+
return cssPropertiesToCss({
|
|
31310
|
+
color: html.color || "#000000",
|
|
31311
|
+
background: html.backgroundColor,
|
|
31312
|
+
});
|
|
31313
|
+
}
|
|
31271
31314
|
}
|
|
31272
31315
|
|
|
31273
31316
|
class ContentEditableHelper {
|
|
@@ -31406,7 +31449,6 @@ class ContentEditableHelper {
|
|
|
31406
31449
|
// We can only modify a node in place if it has the same type as the content
|
|
31407
31450
|
// that we would insert, which are spans.
|
|
31408
31451
|
// Otherwise, it means that the node has been input by the user, through the keyboard or a copy/paste
|
|
31409
|
-
// @ts-ignore (somehow required because jest does not like child.tagName despite the prior check)
|
|
31410
31452
|
const childIsSpan = child && "tagName" in child && child.tagName === "SPAN";
|
|
31411
31453
|
if (childIsSpan && compareContentToSpanElement(content, child)) {
|
|
31412
31454
|
continue;
|
|
@@ -31441,9 +31483,7 @@ class ContentEditableHelper {
|
|
|
31441
31483
|
}
|
|
31442
31484
|
// Empty line
|
|
31443
31485
|
if (!p.hasChildNodes()) {
|
|
31444
|
-
|
|
31445
|
-
span.appendChild(document.createElement("br"));
|
|
31446
|
-
p.appendChild(span);
|
|
31486
|
+
p.appendChild(document.createElement("span"));
|
|
31447
31487
|
}
|
|
31448
31488
|
// replace p if necessary
|
|
31449
31489
|
if (newChild) {
|
|
@@ -31490,13 +31530,10 @@ class ContentEditableHelper {
|
|
|
31490
31530
|
}
|
|
31491
31531
|
getText() {
|
|
31492
31532
|
let text = "";
|
|
31493
|
-
const it = iterateChildren(this.el);
|
|
31494
|
-
let current = it.next();
|
|
31495
31533
|
let isFirstParagraph = true;
|
|
31496
|
-
|
|
31497
|
-
|
|
31498
|
-
|
|
31499
|
-
}
|
|
31534
|
+
let emptyParagraph = false;
|
|
31535
|
+
const it = iterateChildren(this.el);
|
|
31536
|
+
for (let current = it.next(); !current.done; current = it.next()) {
|
|
31500
31537
|
if (current.value.nodeName === "P" ||
|
|
31501
31538
|
(current.value.nodeName === "DIV" && current.value !== this.el) // On paste, the HTML may contain <div> instead of <p>
|
|
31502
31539
|
) {
|
|
@@ -31506,8 +31543,15 @@ class ContentEditableHelper {
|
|
|
31506
31543
|
else {
|
|
31507
31544
|
text += NEWLINE;
|
|
31508
31545
|
}
|
|
31546
|
+
emptyParagraph = ["<br>", "<span><br></span>"].includes(current.value.innerHTML);
|
|
31547
|
+
continue;
|
|
31548
|
+
}
|
|
31549
|
+
if (!current.value.hasChildNodes()) {
|
|
31550
|
+
if (current.value.nodeName === "BR" && !emptyParagraph) {
|
|
31551
|
+
text += NEWLINE;
|
|
31552
|
+
}
|
|
31553
|
+
text += current.value.textContent;
|
|
31509
31554
|
}
|
|
31510
|
-
current = it.next();
|
|
31511
31555
|
}
|
|
31512
31556
|
return text;
|
|
31513
31557
|
}
|
|
@@ -32857,6 +32901,12 @@ class Composer extends Component {
|
|
|
32857
32901
|
useEffect(() => {
|
|
32858
32902
|
this.processTokenAtCursor();
|
|
32859
32903
|
}, () => [this.props.composerStore.editionMode !== "inactive"]);
|
|
32904
|
+
useEffect(() => {
|
|
32905
|
+
this.contentHelper.scrollSelectionIntoView();
|
|
32906
|
+
}, () => [
|
|
32907
|
+
this.props.composerStore.composerSelection.start,
|
|
32908
|
+
this.props.composerStore.composerSelection.end,
|
|
32909
|
+
]);
|
|
32860
32910
|
}
|
|
32861
32911
|
// ---------------------------------------------------------------------------
|
|
32862
32912
|
// Handlers
|
|
@@ -33067,6 +33117,7 @@ class Composer extends Component {
|
|
|
33067
33117
|
if (this.env.isMobile() && !isIOS()) {
|
|
33068
33118
|
return;
|
|
33069
33119
|
}
|
|
33120
|
+
this.debouncedHover.stopDebounce();
|
|
33070
33121
|
this.contentHelper.removeSelection();
|
|
33071
33122
|
}
|
|
33072
33123
|
onMouseup() {
|
|
@@ -33145,7 +33196,6 @@ class Composer extends Component {
|
|
|
33145
33196
|
const { start, end } = this.props.composerStore.composerSelection;
|
|
33146
33197
|
this.contentHelper.selectRange(start, end);
|
|
33147
33198
|
}
|
|
33148
|
-
this.contentHelper.scrollSelectionIntoView();
|
|
33149
33199
|
}
|
|
33150
33200
|
this.shouldProcessInputEvents = true;
|
|
33151
33201
|
}
|
|
@@ -33621,6 +33671,414 @@ class SingleInputCriterionForm extends CriterionForm {
|
|
|
33621
33671
|
}
|
|
33622
33672
|
}
|
|
33623
33673
|
|
|
33674
|
+
/**
|
|
33675
|
+
* Start listening to pointer events and apply the given callbacks.
|
|
33676
|
+
*
|
|
33677
|
+
* @returns A function to remove the listeners.
|
|
33678
|
+
*/
|
|
33679
|
+
function startDnd(onPointerMove, onPointerUp) {
|
|
33680
|
+
const removeListeners = () => {
|
|
33681
|
+
window.removeEventListener("pointerup", _onPointerUp, { capture: true });
|
|
33682
|
+
window.removeEventListener("dragstart", _onDragStart);
|
|
33683
|
+
window.removeEventListener("pointermove", onPointerMove);
|
|
33684
|
+
window.removeEventListener("wheel", onPointerMove);
|
|
33685
|
+
};
|
|
33686
|
+
const _onPointerUp = (ev) => {
|
|
33687
|
+
onPointerUp(ev);
|
|
33688
|
+
removeListeners();
|
|
33689
|
+
};
|
|
33690
|
+
function _onDragStart(ev) {
|
|
33691
|
+
ev.preventDefault();
|
|
33692
|
+
}
|
|
33693
|
+
window.addEventListener("pointerup", _onPointerUp, { capture: true });
|
|
33694
|
+
window.addEventListener("dragstart", _onDragStart);
|
|
33695
|
+
window.addEventListener("pointermove", onPointerMove);
|
|
33696
|
+
// mouse wheel on window is by default a passive event.
|
|
33697
|
+
// preventDefault() is not allowed in passive event handler.
|
|
33698
|
+
// https://chromestatus.com/feature/6662647093133312
|
|
33699
|
+
window.addEventListener("wheel", onPointerMove, { passive: false });
|
|
33700
|
+
return removeListeners;
|
|
33701
|
+
}
|
|
33702
|
+
|
|
33703
|
+
const LINE_VERTICAL_PADDING = 1;
|
|
33704
|
+
const PICKER_PADDING = 8;
|
|
33705
|
+
const ITEM_BORDER_WIDTH = 1;
|
|
33706
|
+
const ITEM_EDGE_LENGTH = 18;
|
|
33707
|
+
const ITEMS_PER_LINE = 10;
|
|
33708
|
+
const MAGNIFIER_EDGE = 16;
|
|
33709
|
+
const ITEM_GAP = 2;
|
|
33710
|
+
const CONTENT_WIDTH = ITEMS_PER_LINE * (ITEM_EDGE_LENGTH + 2 * ITEM_BORDER_WIDTH) + (ITEMS_PER_LINE - 1) * ITEM_GAP;
|
|
33711
|
+
const INNER_GRADIENT_WIDTH = CONTENT_WIDTH - 2 * ITEM_BORDER_WIDTH;
|
|
33712
|
+
const INNER_GRADIENT_HEIGHT = CONTENT_WIDTH - 30 - 2 * ITEM_BORDER_WIDTH;
|
|
33713
|
+
const CONTAINER_WIDTH = CONTENT_WIDTH + 2 * PICKER_PADDING;
|
|
33714
|
+
css /* scss */ `
|
|
33715
|
+
.o-color-picker {
|
|
33716
|
+
padding: ${PICKER_PADDING}px 0;
|
|
33717
|
+
/* FIXME: this is useless, overiden by the popover container */
|
|
33718
|
+
box-shadow: 1px 2px 5px 2px rgba(51, 51, 51, 0.15);
|
|
33719
|
+
background-color: white;
|
|
33720
|
+
line-height: 1.2;
|
|
33721
|
+
overflow-y: auto;
|
|
33722
|
+
overflow-x: hidden;
|
|
33723
|
+
width: ${CONTAINER_WIDTH}px;
|
|
33724
|
+
|
|
33725
|
+
.o-color-picker-section-name {
|
|
33726
|
+
margin: 0px ${ITEM_BORDER_WIDTH}px;
|
|
33727
|
+
padding: 4px ${PICKER_PADDING}px;
|
|
33728
|
+
}
|
|
33729
|
+
.colors-grid {
|
|
33730
|
+
display: grid;
|
|
33731
|
+
padding: ${LINE_VERTICAL_PADDING}px ${PICKER_PADDING}px;
|
|
33732
|
+
grid-template-columns: repeat(${ITEMS_PER_LINE}, 1fr);
|
|
33733
|
+
grid-gap: ${ITEM_GAP}px;
|
|
33734
|
+
}
|
|
33735
|
+
.o-color-picker-toggler-button {
|
|
33736
|
+
display: flex;
|
|
33737
|
+
.o-color-picker-toggler-sign {
|
|
33738
|
+
display: flex;
|
|
33739
|
+
margin: auto auto;
|
|
33740
|
+
width: 55%;
|
|
33741
|
+
height: 55%;
|
|
33742
|
+
.o-icon {
|
|
33743
|
+
width: 100%;
|
|
33744
|
+
height: 100%;
|
|
33745
|
+
}
|
|
33746
|
+
}
|
|
33747
|
+
}
|
|
33748
|
+
.o-color-picker-line-item {
|
|
33749
|
+
width: ${ITEM_EDGE_LENGTH + 2 * ITEM_BORDER_WIDTH}px;
|
|
33750
|
+
height: ${ITEM_EDGE_LENGTH + 2 * ITEM_BORDER_WIDTH}px;
|
|
33751
|
+
margin: 0px;
|
|
33752
|
+
border-radius: 50px;
|
|
33753
|
+
border: ${ITEM_BORDER_WIDTH}px solid #666666;
|
|
33754
|
+
padding: 0px;
|
|
33755
|
+
font-size: 16px;
|
|
33756
|
+
background: white;
|
|
33757
|
+
&:hover {
|
|
33758
|
+
background-color: rgba(0, 0, 0, 0.08);
|
|
33759
|
+
outline: 1px solid gray;
|
|
33760
|
+
cursor: pointer;
|
|
33761
|
+
}
|
|
33762
|
+
}
|
|
33763
|
+
.o-buttons {
|
|
33764
|
+
padding: ${PICKER_PADDING}px;
|
|
33765
|
+
display: flex;
|
|
33766
|
+
.o-cancel {
|
|
33767
|
+
border: ${ITEM_BORDER_WIDTH}px solid #c0c0c0;
|
|
33768
|
+
width: 100%;
|
|
33769
|
+
padding: 5px;
|
|
33770
|
+
font-size: 14px;
|
|
33771
|
+
background: white;
|
|
33772
|
+
border-radius: 4px;
|
|
33773
|
+
&:hover:enabled {
|
|
33774
|
+
background-color: rgba(0, 0, 0, 0.08);
|
|
33775
|
+
}
|
|
33776
|
+
}
|
|
33777
|
+
}
|
|
33778
|
+
.o-add-button {
|
|
33779
|
+
border: ${ITEM_BORDER_WIDTH}px solid #c0c0c0;
|
|
33780
|
+
padding: 4px;
|
|
33781
|
+
background: white;
|
|
33782
|
+
border-radius: 4px;
|
|
33783
|
+
&:hover:enabled {
|
|
33784
|
+
background-color: rgba(0, 0, 0, 0.08);
|
|
33785
|
+
}
|
|
33786
|
+
}
|
|
33787
|
+
.o-separator {
|
|
33788
|
+
border-bottom: ${MENU_SEPARATOR_BORDER_WIDTH}px solid ${SEPARATOR_COLOR};
|
|
33789
|
+
margin-top: ${MENU_SEPARATOR_PADDING}px;
|
|
33790
|
+
margin-bottom: ${MENU_SEPARATOR_PADDING}px;
|
|
33791
|
+
}
|
|
33792
|
+
|
|
33793
|
+
.o-custom-selector {
|
|
33794
|
+
padding: ${PICKER_PADDING + 2}px ${PICKER_PADDING}px;
|
|
33795
|
+
position: relative;
|
|
33796
|
+
.o-gradient {
|
|
33797
|
+
margin-bottom: ${MAGNIFIER_EDGE / 2}px;
|
|
33798
|
+
border: ${ITEM_BORDER_WIDTH}px solid #c0c0c0;
|
|
33799
|
+
width: ${INNER_GRADIENT_WIDTH + 2 * ITEM_BORDER_WIDTH}px;
|
|
33800
|
+
height: ${INNER_GRADIENT_HEIGHT + 2 * ITEM_BORDER_WIDTH}px;
|
|
33801
|
+
position: relative;
|
|
33802
|
+
}
|
|
33803
|
+
|
|
33804
|
+
.magnifier {
|
|
33805
|
+
height: ${MAGNIFIER_EDGE}px;
|
|
33806
|
+
width: ${MAGNIFIER_EDGE}px;
|
|
33807
|
+
border-radius: 50%;
|
|
33808
|
+
border: 2px solid #fff;
|
|
33809
|
+
box-shadow: 0px 0px 3px #c0c0c0;
|
|
33810
|
+
position: absolute;
|
|
33811
|
+
z-index: 2;
|
|
33812
|
+
}
|
|
33813
|
+
.saturation {
|
|
33814
|
+
background: linear-gradient(to right, #fff 0%, transparent 100%);
|
|
33815
|
+
}
|
|
33816
|
+
.lightness {
|
|
33817
|
+
background: linear-gradient(to top, #000 0%, transparent 100%);
|
|
33818
|
+
}
|
|
33819
|
+
.o-hue-picker {
|
|
33820
|
+
border: ${ITEM_BORDER_WIDTH}px solid #c0c0c0;
|
|
33821
|
+
width: 100%;
|
|
33822
|
+
height: 12px;
|
|
33823
|
+
border-radius: 4px;
|
|
33824
|
+
background: linear-gradient(
|
|
33825
|
+
to right,
|
|
33826
|
+
hsl(0 100% 50%) 0%,
|
|
33827
|
+
hsl(0.2turn 100% 50%) 20%,
|
|
33828
|
+
hsl(0.3turn 100% 50%) 30%,
|
|
33829
|
+
hsl(0.4turn 100% 50%) 40%,
|
|
33830
|
+
hsl(0.5turn 100% 50%) 50%,
|
|
33831
|
+
hsl(0.6turn 100% 50%) 60%,
|
|
33832
|
+
hsl(0.7turn 100% 50%) 70%,
|
|
33833
|
+
hsl(0.8turn 100% 50%) 80%,
|
|
33834
|
+
hsl(0.9turn 100% 50%) 90%,
|
|
33835
|
+
hsl(1turn 100% 50%) 100%
|
|
33836
|
+
);
|
|
33837
|
+
position: relative;
|
|
33838
|
+
cursor: crosshair;
|
|
33839
|
+
}
|
|
33840
|
+
.o-hue-slider {
|
|
33841
|
+
margin-top: -3px;
|
|
33842
|
+
}
|
|
33843
|
+
.o-custom-input-preview {
|
|
33844
|
+
padding: 2px 0px;
|
|
33845
|
+
display: flex;
|
|
33846
|
+
input {
|
|
33847
|
+
width: 50%;
|
|
33848
|
+
border-radius: 4px;
|
|
33849
|
+
padding: 4px 23px 4px 10px;
|
|
33850
|
+
height: 24px;
|
|
33851
|
+
border: 1px solid #c0c0c0;
|
|
33852
|
+
margin-right: 2px;
|
|
33853
|
+
}
|
|
33854
|
+
.o-wrong-color {
|
|
33855
|
+
/* FIXME bootstrap class instead? */
|
|
33856
|
+
outline-color: red;
|
|
33857
|
+
border-color: red;
|
|
33858
|
+
&:focus {
|
|
33859
|
+
outline-style: solid;
|
|
33860
|
+
outline-width: 1px;
|
|
33861
|
+
}
|
|
33862
|
+
}
|
|
33863
|
+
}
|
|
33864
|
+
.o-custom-input-buttons {
|
|
33865
|
+
padding: 2px 0px;
|
|
33866
|
+
display: flex;
|
|
33867
|
+
justify-content: end;
|
|
33868
|
+
}
|
|
33869
|
+
.o-color-preview {
|
|
33870
|
+
border: 1px solid #c0c0c0;
|
|
33871
|
+
border-radius: 4px;
|
|
33872
|
+
width: 50%;
|
|
33873
|
+
}
|
|
33874
|
+
}
|
|
33875
|
+
}
|
|
33876
|
+
`;
|
|
33877
|
+
class ColorPicker extends Component {
|
|
33878
|
+
static template = "o-spreadsheet-ColorPicker";
|
|
33879
|
+
static props = {
|
|
33880
|
+
onColorPicked: Function,
|
|
33881
|
+
currentColor: { type: String, optional: true },
|
|
33882
|
+
maxHeight: { type: Number, optional: true },
|
|
33883
|
+
anchorRect: Object,
|
|
33884
|
+
disableNoColor: { type: Boolean, optional: true },
|
|
33885
|
+
};
|
|
33886
|
+
static defaultProps = { currentColor: "" };
|
|
33887
|
+
static components = { Popover };
|
|
33888
|
+
COLORS = COLOR_PICKER_DEFAULTS;
|
|
33889
|
+
state = useState({
|
|
33890
|
+
showGradient: false,
|
|
33891
|
+
currentHslaColor: isColorValid(this.props.currentColor)
|
|
33892
|
+
? { ...hexToHSLA(this.props.currentColor), a: 1 }
|
|
33893
|
+
: { h: 0, s: 100, l: 100, a: 1 },
|
|
33894
|
+
customHexColor: isColorValid(this.props.currentColor) ? toHex(this.props.currentColor) : "",
|
|
33895
|
+
});
|
|
33896
|
+
get colorPickerStyle() {
|
|
33897
|
+
if (this.props.maxHeight !== undefined && this.props.maxHeight <= 0) {
|
|
33898
|
+
return cssPropertiesToCss({ display: "none" });
|
|
33899
|
+
}
|
|
33900
|
+
return "";
|
|
33901
|
+
}
|
|
33902
|
+
get popoverProps() {
|
|
33903
|
+
return {
|
|
33904
|
+
anchorRect: this.props.anchorRect,
|
|
33905
|
+
maxHeight: this.props.maxHeight,
|
|
33906
|
+
positioning: "bottom-left",
|
|
33907
|
+
verticalOffset: 0,
|
|
33908
|
+
};
|
|
33909
|
+
}
|
|
33910
|
+
get gradientHueStyle() {
|
|
33911
|
+
const hue = this.state.currentHslaColor?.h || 0;
|
|
33912
|
+
return cssPropertiesToCss({
|
|
33913
|
+
background: `hsl(${hue} 100% 50%)`,
|
|
33914
|
+
});
|
|
33915
|
+
}
|
|
33916
|
+
get sliderStyle() {
|
|
33917
|
+
const hue = this.state.currentHslaColor?.h || 0;
|
|
33918
|
+
const delta = Math.round((hue / 360) * INNER_GRADIENT_WIDTH);
|
|
33919
|
+
const left = clip(delta, 1, INNER_GRADIENT_WIDTH) - ICON_EDGE_LENGTH / 2;
|
|
33920
|
+
return cssPropertiesToCss({
|
|
33921
|
+
"margin-left": `${left}px`,
|
|
33922
|
+
});
|
|
33923
|
+
}
|
|
33924
|
+
get pointerStyle() {
|
|
33925
|
+
const { s, l } = this.state.currentHslaColor || { s: 0, l: 0 };
|
|
33926
|
+
const left = Math.round(INNER_GRADIENT_WIDTH * clip(s / 100, 0, 1));
|
|
33927
|
+
const top = Math.round(INNER_GRADIENT_HEIGHT * clip(1 - (2 * l) / (200 - s), 0, 1));
|
|
33928
|
+
return cssPropertiesToCss({
|
|
33929
|
+
left: `${-MAGNIFIER_EDGE / 2 + left}px`,
|
|
33930
|
+
top: `${-MAGNIFIER_EDGE / 2 + top}px`,
|
|
33931
|
+
background: hslaToHex(this.state.currentHslaColor),
|
|
33932
|
+
});
|
|
33933
|
+
}
|
|
33934
|
+
get colorPreviewStyle() {
|
|
33935
|
+
return cssPropertiesToCss({
|
|
33936
|
+
"background-color": hslaToHex(this.state.currentHslaColor),
|
|
33937
|
+
});
|
|
33938
|
+
}
|
|
33939
|
+
get checkmarkColor() {
|
|
33940
|
+
return chartFontColor(this.props.currentColor);
|
|
33941
|
+
}
|
|
33942
|
+
get isHexColorInputValid() {
|
|
33943
|
+
return !this.state.customHexColor || isColorValid(this.state.customHexColor);
|
|
33944
|
+
}
|
|
33945
|
+
setCustomGradient({ x, y }) {
|
|
33946
|
+
const offsetX = clip(x, 0, INNER_GRADIENT_WIDTH);
|
|
33947
|
+
const offsetY = clip(y, 0, INNER_GRADIENT_HEIGHT);
|
|
33948
|
+
const deltaX = offsetX / INNER_GRADIENT_WIDTH;
|
|
33949
|
+
const deltaY = offsetY / INNER_GRADIENT_HEIGHT;
|
|
33950
|
+
const s = 100 * deltaX;
|
|
33951
|
+
const l = 100 * (1 - deltaY) * (1 - 0.5 * deltaX);
|
|
33952
|
+
this.updateColor({ s, l });
|
|
33953
|
+
}
|
|
33954
|
+
setCustomHue(x) {
|
|
33955
|
+
// needs to be capped such that h is in [0°, 359°]
|
|
33956
|
+
const h = Math.round(clip((360 * x) / INNER_GRADIENT_WIDTH, 0, 359));
|
|
33957
|
+
this.updateColor({ h });
|
|
33958
|
+
}
|
|
33959
|
+
updateColor(newHsl) {
|
|
33960
|
+
this.state.currentHslaColor = { ...this.state.currentHslaColor, ...newHsl };
|
|
33961
|
+
this.state.customHexColor = hslaToHex(this.state.currentHslaColor);
|
|
33962
|
+
}
|
|
33963
|
+
onColorClick(color) {
|
|
33964
|
+
if (color) {
|
|
33965
|
+
this.props.onColorPicked(toHex(color));
|
|
33966
|
+
}
|
|
33967
|
+
}
|
|
33968
|
+
resetColor() {
|
|
33969
|
+
this.props.onColorPicked("");
|
|
33970
|
+
}
|
|
33971
|
+
toggleColorPicker() {
|
|
33972
|
+
this.state.showGradient = !this.state.showGradient;
|
|
33973
|
+
}
|
|
33974
|
+
dragGradientPointer(ev) {
|
|
33975
|
+
const initialGradientCoordinates = { x: ev.offsetX, y: ev.offsetY };
|
|
33976
|
+
this.setCustomGradient(initialGradientCoordinates);
|
|
33977
|
+
const initialMousePosition = { x: ev.clientX, y: ev.clientY };
|
|
33978
|
+
const onMouseMove = (ev) => {
|
|
33979
|
+
const currentMousePosition = { x: ev.clientX, y: ev.clientY };
|
|
33980
|
+
const deltaX = currentMousePosition.x - initialMousePosition.x;
|
|
33981
|
+
const deltaY = currentMousePosition.y - initialMousePosition.y;
|
|
33982
|
+
const currentGradientCoordinates = {
|
|
33983
|
+
x: initialGradientCoordinates.x + deltaX,
|
|
33984
|
+
y: initialGradientCoordinates.y + deltaY,
|
|
33985
|
+
};
|
|
33986
|
+
this.setCustomGradient(currentGradientCoordinates);
|
|
33987
|
+
};
|
|
33988
|
+
startDnd(onMouseMove, () => { });
|
|
33989
|
+
}
|
|
33990
|
+
dragHuePointer(ev) {
|
|
33991
|
+
const initialX = ev.offsetX;
|
|
33992
|
+
const initialMouseX = ev.clientX;
|
|
33993
|
+
this.setCustomHue(initialX);
|
|
33994
|
+
const onMouseMove = (ev) => {
|
|
33995
|
+
const currentMouseX = ev.clientX;
|
|
33996
|
+
const deltaX = currentMouseX - initialMouseX;
|
|
33997
|
+
const x = initialX + deltaX;
|
|
33998
|
+
this.setCustomHue(x);
|
|
33999
|
+
};
|
|
34000
|
+
startDnd(onMouseMove, () => { });
|
|
34001
|
+
}
|
|
34002
|
+
setHexColor(ev) {
|
|
34003
|
+
// only support HEX code input
|
|
34004
|
+
const val = ev.target.value.replace("##", "#").slice(0, 7);
|
|
34005
|
+
this.state.customHexColor = val;
|
|
34006
|
+
if (!isColorValid(val)) ;
|
|
34007
|
+
else {
|
|
34008
|
+
this.state.currentHslaColor = { ...hexToHSLA(val), a: 1 };
|
|
34009
|
+
}
|
|
34010
|
+
}
|
|
34011
|
+
addCustomColor(ev) {
|
|
34012
|
+
if (!isHSLAValid(this.state.currentHslaColor) || !isColorValid(this.state.customHexColor)) {
|
|
34013
|
+
return;
|
|
34014
|
+
}
|
|
34015
|
+
this.props.onColorPicked(toHex(this.state.customHexColor));
|
|
34016
|
+
}
|
|
34017
|
+
isSameColor(color1, color2) {
|
|
34018
|
+
return isSameColor(color1, color2);
|
|
34019
|
+
}
|
|
34020
|
+
}
|
|
34021
|
+
|
|
34022
|
+
class Section extends Component {
|
|
34023
|
+
static template = "o_spreadsheet.Section";
|
|
34024
|
+
static props = {
|
|
34025
|
+
class: { type: String, optional: true },
|
|
34026
|
+
title: { type: String, optional: true },
|
|
34027
|
+
slots: Object,
|
|
34028
|
+
};
|
|
34029
|
+
}
|
|
34030
|
+
|
|
34031
|
+
const TRANSPARENT_BACKGROUND_SVG = /*xml*/ `
|
|
34032
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10">
|
|
34033
|
+
<path fill="#d9d9d9" d="M5 5h5v5H5zH0V0h5"/>
|
|
34034
|
+
</svg>
|
|
34035
|
+
`;
|
|
34036
|
+
css /* scss */ `
|
|
34037
|
+
.o-round-color-picker-button {
|
|
34038
|
+
width: 20px;
|
|
34039
|
+
height: 20px;
|
|
34040
|
+
cursor: pointer;
|
|
34041
|
+
border: 1px solid ${GRAY_300};
|
|
34042
|
+
background-position: 1px 1px;
|
|
34043
|
+
background-image: url("data:image/svg+xml,${encodeURIComponent(TRANSPARENT_BACKGROUND_SVG)}");
|
|
34044
|
+
}
|
|
34045
|
+
`;
|
|
34046
|
+
class RoundColorPicker extends Component {
|
|
34047
|
+
static template = "o-spreadsheet.RoundColorPicker";
|
|
34048
|
+
static components = { Section, ColorPicker };
|
|
34049
|
+
static props = {
|
|
34050
|
+
currentColor: { type: String, optional: true },
|
|
34051
|
+
title: { type: String, optional: true },
|
|
34052
|
+
onColorPicked: Function,
|
|
34053
|
+
disableNoColor: { type: Boolean, optional: true },
|
|
34054
|
+
};
|
|
34055
|
+
colorPickerButtonRef = useRef("colorPickerButton");
|
|
34056
|
+
state;
|
|
34057
|
+
setup() {
|
|
34058
|
+
this.state = useState({ pickerOpened: false });
|
|
34059
|
+
useExternalListener(window, "click", this.closePicker);
|
|
34060
|
+
}
|
|
34061
|
+
closePicker() {
|
|
34062
|
+
this.state.pickerOpened = false;
|
|
34063
|
+
}
|
|
34064
|
+
togglePicker() {
|
|
34065
|
+
this.state.pickerOpened = !this.state.pickerOpened;
|
|
34066
|
+
}
|
|
34067
|
+
onColorPicked(color) {
|
|
34068
|
+
this.props.onColorPicked(color);
|
|
34069
|
+
this.state.pickerOpened = false;
|
|
34070
|
+
}
|
|
34071
|
+
get colorPickerAnchorRect() {
|
|
34072
|
+
const button = this.colorPickerButtonRef.el;
|
|
34073
|
+
return getBoundingRectAsPOJO(button);
|
|
34074
|
+
}
|
|
34075
|
+
get buttonStyle() {
|
|
34076
|
+
return cssPropertiesToCss({
|
|
34077
|
+
background: this.props.currentColor,
|
|
34078
|
+
});
|
|
34079
|
+
}
|
|
34080
|
+
}
|
|
34081
|
+
|
|
33624
34082
|
css /* scss */ `
|
|
33625
34083
|
.o-dv-list-item-delete {
|
|
33626
34084
|
color: #666666;
|
|
@@ -33629,7 +34087,7 @@ css /* scss */ `
|
|
|
33629
34087
|
`;
|
|
33630
34088
|
class ListCriterionForm extends CriterionForm {
|
|
33631
34089
|
static template = "o-spreadsheet-ListCriterionForm";
|
|
33632
|
-
static components = { CriterionInput };
|
|
34090
|
+
static components = { CriterionInput, RoundColorPicker };
|
|
33633
34091
|
state = useState({
|
|
33634
34092
|
numberOfValues: Math.max(this.props.criterion.values.length, 2),
|
|
33635
34093
|
});
|
|
@@ -33637,7 +34095,7 @@ class ListCriterionForm extends CriterionForm {
|
|
|
33637
34095
|
super.setup();
|
|
33638
34096
|
const setupDefault = (props) => {
|
|
33639
34097
|
if (props.criterion.displayStyle === undefined) {
|
|
33640
|
-
this.updateCriterion({ displayStyle: "
|
|
34098
|
+
this.updateCriterion({ displayStyle: "chip" });
|
|
33641
34099
|
}
|
|
33642
34100
|
};
|
|
33643
34101
|
onWillUpdateProps(setupDefault);
|
|
@@ -33648,6 +34106,11 @@ class ListCriterionForm extends CriterionForm {
|
|
|
33648
34106
|
values[index] = value;
|
|
33649
34107
|
this.updateCriterion({ values });
|
|
33650
34108
|
}
|
|
34109
|
+
onColorChanged(color, value) {
|
|
34110
|
+
const colors = { ...this.props.criterion.colors };
|
|
34111
|
+
colors[value] = color || undefined;
|
|
34112
|
+
this.updateCriterion({ colors });
|
|
34113
|
+
}
|
|
33651
34114
|
onAddAnotherValue() {
|
|
33652
34115
|
this.state.numberOfValues++;
|
|
33653
34116
|
}
|
|
@@ -33683,35 +34146,6 @@ class ListCriterionForm extends CriterionForm {
|
|
|
33683
34146
|
}
|
|
33684
34147
|
}
|
|
33685
34148
|
|
|
33686
|
-
/**
|
|
33687
|
-
* Start listening to pointer events and apply the given callbacks.
|
|
33688
|
-
*
|
|
33689
|
-
* @returns A function to remove the listeners.
|
|
33690
|
-
*/
|
|
33691
|
-
function startDnd(onPointerMove, onPointerUp) {
|
|
33692
|
-
const removeListeners = () => {
|
|
33693
|
-
window.removeEventListener("pointerup", _onPointerUp, { capture: true });
|
|
33694
|
-
window.removeEventListener("dragstart", _onDragStart);
|
|
33695
|
-
window.removeEventListener("pointermove", onPointerMove);
|
|
33696
|
-
window.removeEventListener("wheel", onPointerMove);
|
|
33697
|
-
};
|
|
33698
|
-
const _onPointerUp = (ev) => {
|
|
33699
|
-
onPointerUp(ev);
|
|
33700
|
-
removeListeners();
|
|
33701
|
-
};
|
|
33702
|
-
function _onDragStart(ev) {
|
|
33703
|
-
ev.preventDefault();
|
|
33704
|
-
}
|
|
33705
|
-
window.addEventListener("pointerup", _onPointerUp, { capture: true });
|
|
33706
|
-
window.addEventListener("dragstart", _onDragStart);
|
|
33707
|
-
window.addEventListener("pointermove", onPointerMove);
|
|
33708
|
-
// mouse wheel on window is by default a passive event.
|
|
33709
|
-
// preventDefault() is not allowed in passive event handler.
|
|
33710
|
-
// https://chromestatus.com/feature/6662647093133312
|
|
33711
|
-
window.addEventListener("wheel", onPointerMove, { passive: false });
|
|
33712
|
-
return removeListeners;
|
|
33713
|
-
}
|
|
33714
|
-
|
|
33715
34149
|
function useDragAndDropListItems() {
|
|
33716
34150
|
let dndHelper;
|
|
33717
34151
|
const previousCursor = document.body.style.cursor;
|
|
@@ -34571,12 +35005,12 @@ class SelectionInput extends Component {
|
|
|
34571
35005
|
|
|
34572
35006
|
class ValueInRangeCriterionForm extends CriterionForm {
|
|
34573
35007
|
static template = "o-spreadsheet-ValueInRangeCriterionForm";
|
|
34574
|
-
static components = { SelectionInput };
|
|
35008
|
+
static components = { RoundColorPicker, SelectionInput };
|
|
34575
35009
|
setup() {
|
|
34576
35010
|
super.setup();
|
|
34577
35011
|
const setupDefault = (props) => {
|
|
34578
35012
|
if (props.criterion.displayStyle === undefined) {
|
|
34579
|
-
this.updateCriterion({ displayStyle: "
|
|
35013
|
+
this.updateCriterion({ displayStyle: "chip" });
|
|
34580
35014
|
}
|
|
34581
35015
|
};
|
|
34582
35016
|
onWillUpdateProps(setupDefault);
|
|
@@ -34589,6 +35023,16 @@ class ValueInRangeCriterionForm extends CriterionForm {
|
|
|
34589
35023
|
const displayStyle = ev.target.value;
|
|
34590
35024
|
this.updateCriterion({ displayStyle });
|
|
34591
35025
|
}
|
|
35026
|
+
onColorChanged(color, value) {
|
|
35027
|
+
const colors = { ...this.props.criterion.colors };
|
|
35028
|
+
colors[value] = color || undefined;
|
|
35029
|
+
this.updateCriterion({ colors });
|
|
35030
|
+
}
|
|
35031
|
+
get values() {
|
|
35032
|
+
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
35033
|
+
const values = this.env.model.getters.getDataValidationRangeValues(sheetId, this.props.criterion);
|
|
35034
|
+
return new Set(values);
|
|
35035
|
+
}
|
|
34592
35036
|
}
|
|
34593
35037
|
|
|
34594
35038
|
const criterionCategoriesSequences = {
|
|
@@ -36167,19 +36611,44 @@ const RED_DOT = {
|
|
|
36167
36611
|
height: 512,
|
|
36168
36612
|
paths: [{ fillColor: "#E06666", path: DOT_PATH }],
|
|
36169
36613
|
};
|
|
36170
|
-
|
|
36171
|
-
|
|
36172
|
-
|
|
36173
|
-
|
|
36174
|
-
}
|
|
36175
|
-
|
|
36176
|
-
|
|
36177
|
-
|
|
36178
|
-
|
|
36179
|
-
|
|
36180
|
-
|
|
36181
|
-
|
|
36182
|
-
}
|
|
36614
|
+
function getCaretDownSvg(color) {
|
|
36615
|
+
return {
|
|
36616
|
+
width: 512,
|
|
36617
|
+
height: 512,
|
|
36618
|
+
paths: [{ fillColor: color.textColor || TEXT_BODY_MUTED, path: "M120 195 h270 l-135 130" }],
|
|
36619
|
+
};
|
|
36620
|
+
}
|
|
36621
|
+
function getHoveredCaretDownSvg(color) {
|
|
36622
|
+
return {
|
|
36623
|
+
width: 512,
|
|
36624
|
+
height: 512,
|
|
36625
|
+
paths: [
|
|
36626
|
+
{ fillColor: color.textColor || TEXT_BODY_MUTED, path: "M15 15 h482 v482 h-482" },
|
|
36627
|
+
{ fillColor: color.fillColor || "#fff", path: "M120 195 h270 l-135 130" },
|
|
36628
|
+
],
|
|
36629
|
+
};
|
|
36630
|
+
}
|
|
36631
|
+
const CHIP_CARET_DOWN_PATH = "M40 185 h270 l-135 128";
|
|
36632
|
+
function getChipSvg(chipStyle) {
|
|
36633
|
+
return {
|
|
36634
|
+
width: 512,
|
|
36635
|
+
height: 512,
|
|
36636
|
+
paths: [{ fillColor: chipStyle.textColor || TEXT_BODY_MUTED, path: CHIP_CARET_DOWN_PATH }],
|
|
36637
|
+
};
|
|
36638
|
+
}
|
|
36639
|
+
function getHoveredChipSvg(chipStyle) {
|
|
36640
|
+
return {
|
|
36641
|
+
width: 512,
|
|
36642
|
+
height: 512,
|
|
36643
|
+
paths: [
|
|
36644
|
+
{
|
|
36645
|
+
fillColor: chipStyle.textColor || TEXT_BODY_MUTED,
|
|
36646
|
+
path: "M0,225 A175,175 0 1,0 350,225 A175,175 0 1,0 0,225",
|
|
36647
|
+
},
|
|
36648
|
+
{ fillColor: chipStyle.fillColor || TEXT_BODY_MUTED, path: CHIP_CARET_DOWN_PATH },
|
|
36649
|
+
],
|
|
36650
|
+
};
|
|
36651
|
+
}
|
|
36183
36652
|
const CHECKBOX_UNCHECKED = {
|
|
36184
36653
|
width: 512,
|
|
36185
36654
|
height: 512,
|
|
@@ -41087,6 +41556,10 @@ const REMOVE_ROWS_ACTION = (env) => {
|
|
|
41087
41556
|
});
|
|
41088
41557
|
};
|
|
41089
41558
|
const CAN_REMOVE_COLUMNS_ROWS = (dimension, env) => {
|
|
41559
|
+
if ((dimension === "COL" && env.model.getters.getActiveRows().size > 0) ||
|
|
41560
|
+
(dimension === "ROW" && env.model.getters.getActiveCols().size > 0)) {
|
|
41561
|
+
return false;
|
|
41562
|
+
}
|
|
41090
41563
|
const sheetId = env.model.getters.getActiveSheetId();
|
|
41091
41564
|
const selectedElements = env.model.getters.getElementsFromSelection(dimension);
|
|
41092
41565
|
const includesAllVisibleHeaders = env.model.getters.checkElementsIncludeAllVisibleHeaders(sheetId, dimension, selectedElements);
|
|
@@ -42641,7 +43114,7 @@ const insertDropdown = {
|
|
|
42641
43114
|
criterion: {
|
|
42642
43115
|
type: "isValueInList",
|
|
42643
43116
|
values: [],
|
|
42644
|
-
displayStyle: "
|
|
43117
|
+
displayStyle: "chip",
|
|
42645
43118
|
},
|
|
42646
43119
|
},
|
|
42647
43120
|
});
|
|
@@ -44556,6 +45029,11 @@ class GridComposer extends Component {
|
|
|
44556
45029
|
rect = this.defaultRect;
|
|
44557
45030
|
isEditing = false;
|
|
44558
45031
|
isCellReferenceVisible = false;
|
|
45032
|
+
currentEditedCell = {
|
|
45033
|
+
col: 0,
|
|
45034
|
+
row: 0,
|
|
45035
|
+
sheetId: this.env.model.getters.getActiveSheetId(),
|
|
45036
|
+
};
|
|
44559
45037
|
composerStore;
|
|
44560
45038
|
composerFocusStore;
|
|
44561
45039
|
composerInterface;
|
|
@@ -44680,12 +45158,17 @@ class GridComposer extends Component {
|
|
|
44680
45158
|
if (!isEditing && this.composerFocusStore.activeComposer !== this.composerInterface) {
|
|
44681
45159
|
this.composerFocusStore.focusComposer(this.composerInterface, { focusMode: "inactive" });
|
|
44682
45160
|
}
|
|
45161
|
+
let shouldRecomputeRect = !deepEquals(this.currentEditedCell, this.composerStore.currentEditedCell);
|
|
44683
45162
|
if (this.isEditing !== isEditing) {
|
|
44684
45163
|
this.isEditing = isEditing;
|
|
44685
45164
|
if (!isEditing) {
|
|
44686
45165
|
this.rect = this.defaultRect;
|
|
44687
45166
|
return;
|
|
44688
45167
|
}
|
|
45168
|
+
this.currentEditedCell = this.composerStore.currentEditedCell;
|
|
45169
|
+
shouldRecomputeRect = true;
|
|
45170
|
+
}
|
|
45171
|
+
if (shouldRecomputeRect) {
|
|
44689
45172
|
const position = this.env.model.getters.getActivePosition();
|
|
44690
45173
|
const zone = this.env.model.getters.expandZone(position.sheetId, positionToZone(position));
|
|
44691
45174
|
this.rect = this.env.model.getters.getVisibleRect(zone);
|
|
@@ -45791,11 +46274,14 @@ class GridOverlay extends Component {
|
|
|
45791
46274
|
onCellClicked(ev) {
|
|
45792
46275
|
const openedPopover = this.cellPopovers.persistentCellPopover;
|
|
45793
46276
|
const [col, row] = this.getCartesianCoordinates(ev);
|
|
46277
|
+
const clickedIcon = this.getInteractiveIconAtEvent(ev);
|
|
46278
|
+
if (clickedIcon) {
|
|
46279
|
+
this.env.model.selection.getBackToDefault();
|
|
46280
|
+
}
|
|
45794
46281
|
this.props.onCellClicked(col, row, {
|
|
45795
46282
|
expandZone: ev.shiftKey,
|
|
45796
46283
|
addZone: isCtrlKey(ev),
|
|
45797
46284
|
}, ev);
|
|
45798
|
-
const clickedIcon = this.getInteractiveIconAtEvent(ev);
|
|
45799
46285
|
if (clickedIcon?.onClick) {
|
|
45800
46286
|
clickedIcon.onClick(clickedIcon.position, this.env);
|
|
45801
46287
|
}
|
|
@@ -46660,6 +47146,19 @@ class GridRenderer {
|
|
|
46660
47146
|
const width = box.width * (percentage / 100);
|
|
46661
47147
|
ctx.fillRect(box.x, box.y, width, box.height);
|
|
46662
47148
|
}
|
|
47149
|
+
if (box?.chip) {
|
|
47150
|
+
ctx.save();
|
|
47151
|
+
ctx.beginPath();
|
|
47152
|
+
ctx.rect(box.x, box.y, box.width, box.height);
|
|
47153
|
+
ctx.clip();
|
|
47154
|
+
const chip = box.chip;
|
|
47155
|
+
ctx.fillStyle = chip.color;
|
|
47156
|
+
const radius = 10;
|
|
47157
|
+
ctx.beginPath();
|
|
47158
|
+
ctx.roundRect(chip.x, chip.y, chip.width, chip.height, radius);
|
|
47159
|
+
ctx.fill();
|
|
47160
|
+
ctx.restore();
|
|
47161
|
+
}
|
|
46663
47162
|
if (box.overlayColor) {
|
|
46664
47163
|
ctx.fillStyle = box.overlayColor;
|
|
46665
47164
|
ctx.fillRect(box.x, box.y, box.width, box.height);
|
|
@@ -46799,19 +47298,6 @@ class GridRenderer {
|
|
|
46799
47298
|
ctx.font = font;
|
|
46800
47299
|
}
|
|
46801
47300
|
ctx.fillStyle = style.textColor || "#000";
|
|
46802
|
-
// compute horizontal align start point parameter
|
|
46803
|
-
let x = box.x;
|
|
46804
|
-
if (align === "left") {
|
|
46805
|
-
const leftIconSize = box.icons.left ? box.icons.left.size + box.icons.left.margin : 0;
|
|
46806
|
-
x += MIN_CELL_TEXT_MARGIN + leftIconSize;
|
|
46807
|
-
}
|
|
46808
|
-
else if (align === "right") {
|
|
46809
|
-
const rightIconSize = box.icons.right ? box.icons.right.size + box.icons.right.margin : 0;
|
|
46810
|
-
x += box.width - MIN_CELL_TEXT_MARGIN - rightIconSize;
|
|
46811
|
-
}
|
|
46812
|
-
else {
|
|
46813
|
-
x += box.width / 2;
|
|
46814
|
-
}
|
|
46815
47301
|
// horizontal align text direction
|
|
46816
47302
|
ctx.textAlign = align;
|
|
46817
47303
|
// clip rect if needed
|
|
@@ -46822,15 +47308,13 @@ class GridRenderer {
|
|
|
46822
47308
|
ctx.rect(x, y, width, height);
|
|
46823
47309
|
ctx.clip();
|
|
46824
47310
|
}
|
|
46825
|
-
|
|
46826
|
-
|
|
46827
|
-
const numberOfLines = box.content.textLines.length;
|
|
46828
|
-
let y = this.getters.computeTextYCoordinate(box, textLineHeight, style.verticalAlign, numberOfLines);
|
|
47311
|
+
const x = box.content.x;
|
|
47312
|
+
let y = box.content.y;
|
|
46829
47313
|
// use the horizontal and the vertical start points to:
|
|
46830
47314
|
// fill text / fill strikethrough / fill underline
|
|
46831
47315
|
for (const brokenLine of box.content.textLines) {
|
|
46832
|
-
drawDecoratedText(ctx, brokenLine, { x
|
|
46833
|
-
y += MIN_CELL_TEXT_MARGIN +
|
|
47316
|
+
drawDecoratedText(ctx, brokenLine, { x, y }, style.underline, style.strikethrough);
|
|
47317
|
+
y += MIN_CELL_TEXT_MARGIN + box.content.fontSizePx;
|
|
46834
47318
|
}
|
|
46835
47319
|
if (box.clipRect) {
|
|
46836
47320
|
ctx.restore();
|
|
@@ -47065,11 +47549,15 @@ class GridRenderer {
|
|
|
47065
47549
|
const showFormula = this.getters.shouldShowFormulas();
|
|
47066
47550
|
const { x, y, width, height } = this.getters.getRect(zone);
|
|
47067
47551
|
const { verticalAlign } = this.getters.getCellStyle(position);
|
|
47552
|
+
const chipStyle = this.getters.getDataValidationChipStyle(position);
|
|
47068
47553
|
let style = this.getters.getCellComputedStyle(position);
|
|
47069
47554
|
if (this.fingerprints.isEnabled) {
|
|
47070
47555
|
const fingerprintColor = this.fingerprints.colors.get(position);
|
|
47071
47556
|
style = { ...style, fillColor: fingerprintColor };
|
|
47072
47557
|
}
|
|
47558
|
+
if (chipStyle?.textColor) {
|
|
47559
|
+
style = { ...style, textColor: chipStyle.textColor };
|
|
47560
|
+
}
|
|
47073
47561
|
const dataBarFill = this.fingerprints.isEnabled
|
|
47074
47562
|
? undefined
|
|
47075
47563
|
: this.getters.getConditionalDataBar(position);
|
|
@@ -47103,22 +47591,55 @@ class GridRenderer {
|
|
|
47103
47591
|
const maxWidth = width - 2 * MIN_CELL_TEXT_MARGIN;
|
|
47104
47592
|
const multiLineText = this.getters.getCellMultiLineText(position, { maxWidth, wrapText });
|
|
47105
47593
|
const textWidth = Math.max(...multiLineText.map((line) => this.getters.getTextWidth(line, style) + MIN_CELL_TEXT_MARGIN));
|
|
47594
|
+
const chipMargin = chipStyle ? DATA_VALIDATION_CHIP_MARGIN : 0;
|
|
47106
47595
|
const leftIconWidth = box.icons.left ? box.icons.left.size + box.icons.left.margin : 0;
|
|
47596
|
+
const leftMargin = leftIconWidth + chipMargin;
|
|
47107
47597
|
const rightIconWidth = box.icons.right ? box.icons.right.size + box.icons.right.margin : 0;
|
|
47108
|
-
const
|
|
47598
|
+
const rightMargin = rightIconWidth + chipMargin;
|
|
47599
|
+
const contentWidth = leftMargin + textWidth + rightMargin;
|
|
47109
47600
|
const align = this.computeCellAlignment(position, contentWidth > width);
|
|
47601
|
+
// compute vertical align start point parameter:
|
|
47602
|
+
const numberOfLines = multiLineText.length;
|
|
47603
|
+
const contentY = Math.round(this.getters.computeTextYCoordinate(box, fontSizePX, style.verticalAlign, numberOfLines));
|
|
47604
|
+
// compute horizontal align start point parameter
|
|
47605
|
+
let contentX = box.x;
|
|
47606
|
+
if (align === "left") {
|
|
47607
|
+
contentX += MIN_CELL_TEXT_MARGIN + leftMargin;
|
|
47608
|
+
}
|
|
47609
|
+
else if (align === "right") {
|
|
47610
|
+
contentX += box.width - MIN_CELL_TEXT_MARGIN - rightMargin;
|
|
47611
|
+
}
|
|
47612
|
+
else {
|
|
47613
|
+
contentX += box.width / 2;
|
|
47614
|
+
}
|
|
47615
|
+
contentX = Math.round(contentX);
|
|
47616
|
+
const textHeight = computeTextLinesHeight(fontSizePX, numberOfLines);
|
|
47110
47617
|
box.content = {
|
|
47111
47618
|
textLines: multiLineText,
|
|
47112
47619
|
width: wrapping === "overflow" ? textWidth : width,
|
|
47113
47620
|
align,
|
|
47621
|
+
x: contentX,
|
|
47622
|
+
y: contentY,
|
|
47623
|
+
fontSizePx: fontSizePX,
|
|
47114
47624
|
};
|
|
47625
|
+
if (chipStyle?.fillColor) {
|
|
47626
|
+
const chipMarginLeft = leftMargin;
|
|
47627
|
+
const chipMarginRight = DATA_VALIDATION_CHIP_MARGIN;
|
|
47628
|
+
box.chip = {
|
|
47629
|
+
color: chipStyle.fillColor,
|
|
47630
|
+
width: box.width - chipMarginLeft - chipMarginRight,
|
|
47631
|
+
height: textHeight + 2,
|
|
47632
|
+
x: box.x + chipMarginLeft,
|
|
47633
|
+
y: contentY - 2,
|
|
47634
|
+
};
|
|
47635
|
+
}
|
|
47115
47636
|
/** ClipRect */
|
|
47116
47637
|
const isOverflowing = contentWidth > width || fontSizePX > height;
|
|
47117
|
-
if (box.icons.left || box.icons.right) {
|
|
47638
|
+
if (box.icons.left || box.icons.right || box.chip) {
|
|
47118
47639
|
box.clipRect = {
|
|
47119
|
-
x: box.x +
|
|
47640
|
+
x: box.x + leftMargin,
|
|
47120
47641
|
y: box.y,
|
|
47121
|
-
width: Math.max(0, width -
|
|
47642
|
+
width: Math.max(0, width - leftMargin - rightMargin),
|
|
47122
47643
|
height,
|
|
47123
47644
|
};
|
|
47124
47645
|
}
|
|
@@ -47818,15 +48339,6 @@ class Selection extends Component {
|
|
|
47818
48339
|
}
|
|
47819
48340
|
}
|
|
47820
48341
|
|
|
47821
|
-
class Section extends Component {
|
|
47822
|
-
static template = "o_spreadsheet.Section";
|
|
47823
|
-
static props = {
|
|
47824
|
-
class: { type: String, optional: true },
|
|
47825
|
-
title: { type: String, optional: true },
|
|
47826
|
-
slots: Object,
|
|
47827
|
-
};
|
|
47828
|
-
}
|
|
47829
|
-
|
|
47830
48342
|
class ChartDataSeries extends Component {
|
|
47831
48343
|
static template = "o-spreadsheet.ChartDataSeries";
|
|
47832
48344
|
static components = { SelectionInput, Section };
|
|
@@ -48375,325 +48887,6 @@ class ActionButton extends Component {
|
|
|
48375
48887
|
}
|
|
48376
48888
|
}
|
|
48377
48889
|
|
|
48378
|
-
const LINE_VERTICAL_PADDING = 1;
|
|
48379
|
-
const PICKER_PADDING = 8;
|
|
48380
|
-
const ITEM_BORDER_WIDTH = 1;
|
|
48381
|
-
const ITEM_EDGE_LENGTH = 18;
|
|
48382
|
-
const ITEMS_PER_LINE = 10;
|
|
48383
|
-
const MAGNIFIER_EDGE = 16;
|
|
48384
|
-
const ITEM_GAP = 2;
|
|
48385
|
-
const CONTENT_WIDTH = ITEMS_PER_LINE * (ITEM_EDGE_LENGTH + 2 * ITEM_BORDER_WIDTH) + (ITEMS_PER_LINE - 1) * ITEM_GAP;
|
|
48386
|
-
const INNER_GRADIENT_WIDTH = CONTENT_WIDTH - 2 * ITEM_BORDER_WIDTH;
|
|
48387
|
-
const INNER_GRADIENT_HEIGHT = CONTENT_WIDTH - 30 - 2 * ITEM_BORDER_WIDTH;
|
|
48388
|
-
const CONTAINER_WIDTH = CONTENT_WIDTH + 2 * PICKER_PADDING;
|
|
48389
|
-
css /* scss */ `
|
|
48390
|
-
.o-color-picker {
|
|
48391
|
-
padding: ${PICKER_PADDING}px 0;
|
|
48392
|
-
/* FIXME: this is useless, overiden by the popover container */
|
|
48393
|
-
box-shadow: 1px 2px 5px 2px rgba(51, 51, 51, 0.15);
|
|
48394
|
-
background-color: white;
|
|
48395
|
-
line-height: 1.2;
|
|
48396
|
-
overflow-y: auto;
|
|
48397
|
-
overflow-x: hidden;
|
|
48398
|
-
width: ${CONTAINER_WIDTH}px;
|
|
48399
|
-
|
|
48400
|
-
.o-color-picker-section-name {
|
|
48401
|
-
margin: 0px ${ITEM_BORDER_WIDTH}px;
|
|
48402
|
-
padding: 4px ${PICKER_PADDING}px;
|
|
48403
|
-
}
|
|
48404
|
-
.colors-grid {
|
|
48405
|
-
display: grid;
|
|
48406
|
-
padding: ${LINE_VERTICAL_PADDING}px ${PICKER_PADDING}px;
|
|
48407
|
-
grid-template-columns: repeat(${ITEMS_PER_LINE}, 1fr);
|
|
48408
|
-
grid-gap: ${ITEM_GAP}px;
|
|
48409
|
-
}
|
|
48410
|
-
.o-color-picker-toggler-button {
|
|
48411
|
-
display: flex;
|
|
48412
|
-
.o-color-picker-toggler-sign {
|
|
48413
|
-
display: flex;
|
|
48414
|
-
margin: auto auto;
|
|
48415
|
-
width: 55%;
|
|
48416
|
-
height: 55%;
|
|
48417
|
-
.o-icon {
|
|
48418
|
-
width: 100%;
|
|
48419
|
-
height: 100%;
|
|
48420
|
-
}
|
|
48421
|
-
}
|
|
48422
|
-
}
|
|
48423
|
-
.o-color-picker-line-item {
|
|
48424
|
-
width: ${ITEM_EDGE_LENGTH + 2 * ITEM_BORDER_WIDTH}px;
|
|
48425
|
-
height: ${ITEM_EDGE_LENGTH + 2 * ITEM_BORDER_WIDTH}px;
|
|
48426
|
-
margin: 0px;
|
|
48427
|
-
border-radius: 50px;
|
|
48428
|
-
border: ${ITEM_BORDER_WIDTH}px solid #666666;
|
|
48429
|
-
padding: 0px;
|
|
48430
|
-
font-size: 16px;
|
|
48431
|
-
background: white;
|
|
48432
|
-
&:hover {
|
|
48433
|
-
background-color: rgba(0, 0, 0, 0.08);
|
|
48434
|
-
outline: 1px solid gray;
|
|
48435
|
-
cursor: pointer;
|
|
48436
|
-
}
|
|
48437
|
-
}
|
|
48438
|
-
.o-buttons {
|
|
48439
|
-
padding: ${PICKER_PADDING}px;
|
|
48440
|
-
display: flex;
|
|
48441
|
-
.o-cancel {
|
|
48442
|
-
border: ${ITEM_BORDER_WIDTH}px solid #c0c0c0;
|
|
48443
|
-
width: 100%;
|
|
48444
|
-
padding: 5px;
|
|
48445
|
-
font-size: 14px;
|
|
48446
|
-
background: white;
|
|
48447
|
-
border-radius: 4px;
|
|
48448
|
-
&:hover:enabled {
|
|
48449
|
-
background-color: rgba(0, 0, 0, 0.08);
|
|
48450
|
-
}
|
|
48451
|
-
}
|
|
48452
|
-
}
|
|
48453
|
-
.o-add-button {
|
|
48454
|
-
border: ${ITEM_BORDER_WIDTH}px solid #c0c0c0;
|
|
48455
|
-
padding: 4px;
|
|
48456
|
-
background: white;
|
|
48457
|
-
border-radius: 4px;
|
|
48458
|
-
&:hover:enabled {
|
|
48459
|
-
background-color: rgba(0, 0, 0, 0.08);
|
|
48460
|
-
}
|
|
48461
|
-
}
|
|
48462
|
-
.o-separator {
|
|
48463
|
-
border-bottom: ${MENU_SEPARATOR_BORDER_WIDTH}px solid ${SEPARATOR_COLOR};
|
|
48464
|
-
margin-top: ${MENU_SEPARATOR_PADDING}px;
|
|
48465
|
-
margin-bottom: ${MENU_SEPARATOR_PADDING}px;
|
|
48466
|
-
}
|
|
48467
|
-
|
|
48468
|
-
.o-custom-selector {
|
|
48469
|
-
padding: ${PICKER_PADDING + 2}px ${PICKER_PADDING}px;
|
|
48470
|
-
position: relative;
|
|
48471
|
-
.o-gradient {
|
|
48472
|
-
margin-bottom: ${MAGNIFIER_EDGE / 2}px;
|
|
48473
|
-
border: ${ITEM_BORDER_WIDTH}px solid #c0c0c0;
|
|
48474
|
-
width: ${INNER_GRADIENT_WIDTH + 2 * ITEM_BORDER_WIDTH}px;
|
|
48475
|
-
height: ${INNER_GRADIENT_HEIGHT + 2 * ITEM_BORDER_WIDTH}px;
|
|
48476
|
-
position: relative;
|
|
48477
|
-
}
|
|
48478
|
-
|
|
48479
|
-
.magnifier {
|
|
48480
|
-
height: ${MAGNIFIER_EDGE}px;
|
|
48481
|
-
width: ${MAGNIFIER_EDGE}px;
|
|
48482
|
-
border-radius: 50%;
|
|
48483
|
-
border: 2px solid #fff;
|
|
48484
|
-
box-shadow: 0px 0px 3px #c0c0c0;
|
|
48485
|
-
position: absolute;
|
|
48486
|
-
z-index: 2;
|
|
48487
|
-
}
|
|
48488
|
-
.saturation {
|
|
48489
|
-
background: linear-gradient(to right, #fff 0%, transparent 100%);
|
|
48490
|
-
}
|
|
48491
|
-
.lightness {
|
|
48492
|
-
background: linear-gradient(to top, #000 0%, transparent 100%);
|
|
48493
|
-
}
|
|
48494
|
-
.o-hue-picker {
|
|
48495
|
-
border: ${ITEM_BORDER_WIDTH}px solid #c0c0c0;
|
|
48496
|
-
width: 100%;
|
|
48497
|
-
height: 12px;
|
|
48498
|
-
border-radius: 4px;
|
|
48499
|
-
background: linear-gradient(
|
|
48500
|
-
to right,
|
|
48501
|
-
hsl(0 100% 50%) 0%,
|
|
48502
|
-
hsl(0.2turn 100% 50%) 20%,
|
|
48503
|
-
hsl(0.3turn 100% 50%) 30%,
|
|
48504
|
-
hsl(0.4turn 100% 50%) 40%,
|
|
48505
|
-
hsl(0.5turn 100% 50%) 50%,
|
|
48506
|
-
hsl(0.6turn 100% 50%) 60%,
|
|
48507
|
-
hsl(0.7turn 100% 50%) 70%,
|
|
48508
|
-
hsl(0.8turn 100% 50%) 80%,
|
|
48509
|
-
hsl(0.9turn 100% 50%) 90%,
|
|
48510
|
-
hsl(1turn 100% 50%) 100%
|
|
48511
|
-
);
|
|
48512
|
-
position: relative;
|
|
48513
|
-
cursor: crosshair;
|
|
48514
|
-
}
|
|
48515
|
-
.o-hue-slider {
|
|
48516
|
-
margin-top: -3px;
|
|
48517
|
-
}
|
|
48518
|
-
.o-custom-input-preview {
|
|
48519
|
-
padding: 2px 0px;
|
|
48520
|
-
display: flex;
|
|
48521
|
-
input {
|
|
48522
|
-
width: 50%;
|
|
48523
|
-
border-radius: 4px;
|
|
48524
|
-
padding: 4px 23px 4px 10px;
|
|
48525
|
-
height: 24px;
|
|
48526
|
-
border: 1px solid #c0c0c0;
|
|
48527
|
-
margin-right: 2px;
|
|
48528
|
-
}
|
|
48529
|
-
.o-wrong-color {
|
|
48530
|
-
/* FIXME bootstrap class instead? */
|
|
48531
|
-
outline-color: red;
|
|
48532
|
-
border-color: red;
|
|
48533
|
-
&:focus {
|
|
48534
|
-
outline-style: solid;
|
|
48535
|
-
outline-width: 1px;
|
|
48536
|
-
}
|
|
48537
|
-
}
|
|
48538
|
-
}
|
|
48539
|
-
.o-custom-input-buttons {
|
|
48540
|
-
padding: 2px 0px;
|
|
48541
|
-
display: flex;
|
|
48542
|
-
justify-content: end;
|
|
48543
|
-
}
|
|
48544
|
-
.o-color-preview {
|
|
48545
|
-
border: 1px solid #c0c0c0;
|
|
48546
|
-
border-radius: 4px;
|
|
48547
|
-
width: 50%;
|
|
48548
|
-
}
|
|
48549
|
-
}
|
|
48550
|
-
}
|
|
48551
|
-
`;
|
|
48552
|
-
class ColorPicker extends Component {
|
|
48553
|
-
static template = "o-spreadsheet-ColorPicker";
|
|
48554
|
-
static props = {
|
|
48555
|
-
onColorPicked: Function,
|
|
48556
|
-
currentColor: { type: String, optional: true },
|
|
48557
|
-
maxHeight: { type: Number, optional: true },
|
|
48558
|
-
anchorRect: Object,
|
|
48559
|
-
disableNoColor: { type: Boolean, optional: true },
|
|
48560
|
-
};
|
|
48561
|
-
static defaultProps = { currentColor: "" };
|
|
48562
|
-
static components = { Popover };
|
|
48563
|
-
COLORS = COLOR_PICKER_DEFAULTS;
|
|
48564
|
-
state = useState({
|
|
48565
|
-
showGradient: false,
|
|
48566
|
-
currentHslaColor: isColorValid(this.props.currentColor)
|
|
48567
|
-
? { ...hexToHSLA(this.props.currentColor), a: 1 }
|
|
48568
|
-
: { h: 0, s: 100, l: 100, a: 1 },
|
|
48569
|
-
customHexColor: isColorValid(this.props.currentColor) ? toHex(this.props.currentColor) : "",
|
|
48570
|
-
});
|
|
48571
|
-
get colorPickerStyle() {
|
|
48572
|
-
if (this.props.maxHeight !== undefined && this.props.maxHeight <= 0) {
|
|
48573
|
-
return cssPropertiesToCss({ display: "none" });
|
|
48574
|
-
}
|
|
48575
|
-
return "";
|
|
48576
|
-
}
|
|
48577
|
-
get popoverProps() {
|
|
48578
|
-
return {
|
|
48579
|
-
anchorRect: this.props.anchorRect,
|
|
48580
|
-
maxHeight: this.props.maxHeight,
|
|
48581
|
-
positioning: "bottom-left",
|
|
48582
|
-
verticalOffset: 0,
|
|
48583
|
-
};
|
|
48584
|
-
}
|
|
48585
|
-
get gradientHueStyle() {
|
|
48586
|
-
const hue = this.state.currentHslaColor?.h || 0;
|
|
48587
|
-
return cssPropertiesToCss({
|
|
48588
|
-
background: `hsl(${hue} 100% 50%)`,
|
|
48589
|
-
});
|
|
48590
|
-
}
|
|
48591
|
-
get sliderStyle() {
|
|
48592
|
-
const hue = this.state.currentHslaColor?.h || 0;
|
|
48593
|
-
const delta = Math.round((hue / 360) * INNER_GRADIENT_WIDTH);
|
|
48594
|
-
const left = clip(delta, 1, INNER_GRADIENT_WIDTH) - ICON_EDGE_LENGTH / 2;
|
|
48595
|
-
return cssPropertiesToCss({
|
|
48596
|
-
"margin-left": `${left}px`,
|
|
48597
|
-
});
|
|
48598
|
-
}
|
|
48599
|
-
get pointerStyle() {
|
|
48600
|
-
const { s, l } = this.state.currentHslaColor || { s: 0, l: 0 };
|
|
48601
|
-
const left = Math.round(INNER_GRADIENT_WIDTH * clip(s / 100, 0, 1));
|
|
48602
|
-
const top = Math.round(INNER_GRADIENT_HEIGHT * clip(1 - (2 * l) / (200 - s), 0, 1));
|
|
48603
|
-
return cssPropertiesToCss({
|
|
48604
|
-
left: `${-MAGNIFIER_EDGE / 2 + left}px`,
|
|
48605
|
-
top: `${-MAGNIFIER_EDGE / 2 + top}px`,
|
|
48606
|
-
background: hslaToHex(this.state.currentHslaColor),
|
|
48607
|
-
});
|
|
48608
|
-
}
|
|
48609
|
-
get colorPreviewStyle() {
|
|
48610
|
-
return cssPropertiesToCss({
|
|
48611
|
-
"background-color": hslaToHex(this.state.currentHslaColor),
|
|
48612
|
-
});
|
|
48613
|
-
}
|
|
48614
|
-
get checkmarkColor() {
|
|
48615
|
-
return chartFontColor(this.props.currentColor);
|
|
48616
|
-
}
|
|
48617
|
-
get isHexColorInputValid() {
|
|
48618
|
-
return !this.state.customHexColor || isColorValid(this.state.customHexColor);
|
|
48619
|
-
}
|
|
48620
|
-
setCustomGradient({ x, y }) {
|
|
48621
|
-
const offsetX = clip(x, 0, INNER_GRADIENT_WIDTH);
|
|
48622
|
-
const offsetY = clip(y, 0, INNER_GRADIENT_HEIGHT);
|
|
48623
|
-
const deltaX = offsetX / INNER_GRADIENT_WIDTH;
|
|
48624
|
-
const deltaY = offsetY / INNER_GRADIENT_HEIGHT;
|
|
48625
|
-
const s = 100 * deltaX;
|
|
48626
|
-
const l = 100 * (1 - deltaY) * (1 - 0.5 * deltaX);
|
|
48627
|
-
this.updateColor({ s, l });
|
|
48628
|
-
}
|
|
48629
|
-
setCustomHue(x) {
|
|
48630
|
-
// needs to be capped such that h is in [0°, 359°]
|
|
48631
|
-
const h = Math.round(clip((360 * x) / INNER_GRADIENT_WIDTH, 0, 359));
|
|
48632
|
-
this.updateColor({ h });
|
|
48633
|
-
}
|
|
48634
|
-
updateColor(newHsl) {
|
|
48635
|
-
this.state.currentHslaColor = { ...this.state.currentHslaColor, ...newHsl };
|
|
48636
|
-
this.state.customHexColor = hslaToHex(this.state.currentHslaColor);
|
|
48637
|
-
}
|
|
48638
|
-
onColorClick(color) {
|
|
48639
|
-
if (color) {
|
|
48640
|
-
this.props.onColorPicked(toHex(color));
|
|
48641
|
-
}
|
|
48642
|
-
}
|
|
48643
|
-
resetColor() {
|
|
48644
|
-
this.props.onColorPicked("");
|
|
48645
|
-
}
|
|
48646
|
-
toggleColorPicker() {
|
|
48647
|
-
this.state.showGradient = !this.state.showGradient;
|
|
48648
|
-
}
|
|
48649
|
-
dragGradientPointer(ev) {
|
|
48650
|
-
const initialGradientCoordinates = { x: ev.offsetX, y: ev.offsetY };
|
|
48651
|
-
this.setCustomGradient(initialGradientCoordinates);
|
|
48652
|
-
const initialMousePosition = { x: ev.clientX, y: ev.clientY };
|
|
48653
|
-
const onMouseMove = (ev) => {
|
|
48654
|
-
const currentMousePosition = { x: ev.clientX, y: ev.clientY };
|
|
48655
|
-
const deltaX = currentMousePosition.x - initialMousePosition.x;
|
|
48656
|
-
const deltaY = currentMousePosition.y - initialMousePosition.y;
|
|
48657
|
-
const currentGradientCoordinates = {
|
|
48658
|
-
x: initialGradientCoordinates.x + deltaX,
|
|
48659
|
-
y: initialGradientCoordinates.y + deltaY,
|
|
48660
|
-
};
|
|
48661
|
-
this.setCustomGradient(currentGradientCoordinates);
|
|
48662
|
-
};
|
|
48663
|
-
startDnd(onMouseMove, () => { });
|
|
48664
|
-
}
|
|
48665
|
-
dragHuePointer(ev) {
|
|
48666
|
-
const initialX = ev.offsetX;
|
|
48667
|
-
const initialMouseX = ev.clientX;
|
|
48668
|
-
this.setCustomHue(initialX);
|
|
48669
|
-
const onMouseMove = (ev) => {
|
|
48670
|
-
const currentMouseX = ev.clientX;
|
|
48671
|
-
const deltaX = currentMouseX - initialMouseX;
|
|
48672
|
-
const x = initialX + deltaX;
|
|
48673
|
-
this.setCustomHue(x);
|
|
48674
|
-
};
|
|
48675
|
-
startDnd(onMouseMove, () => { });
|
|
48676
|
-
}
|
|
48677
|
-
setHexColor(ev) {
|
|
48678
|
-
// only support HEX code input
|
|
48679
|
-
const val = ev.target.value.replace("##", "#").slice(0, 7);
|
|
48680
|
-
this.state.customHexColor = val;
|
|
48681
|
-
if (!isColorValid(val)) ;
|
|
48682
|
-
else {
|
|
48683
|
-
this.state.currentHslaColor = { ...hexToHSLA(val), a: 1 };
|
|
48684
|
-
}
|
|
48685
|
-
}
|
|
48686
|
-
addCustomColor(ev) {
|
|
48687
|
-
if (!isHSLAValid(this.state.currentHslaColor) || !isColorValid(this.state.customHexColor)) {
|
|
48688
|
-
return;
|
|
48689
|
-
}
|
|
48690
|
-
this.props.onColorPicked(toHex(this.state.customHexColor));
|
|
48691
|
-
}
|
|
48692
|
-
isSameColor(color1, color2) {
|
|
48693
|
-
return isSameColor(color1, color2);
|
|
48694
|
-
}
|
|
48695
|
-
}
|
|
48696
|
-
|
|
48697
48890
|
css /* scss */ `
|
|
48698
48891
|
.o-color-picker-widget {
|
|
48699
48892
|
display: flex;
|
|
@@ -49161,57 +49354,6 @@ class RadioSelection extends Component {
|
|
|
49161
49354
|
};
|
|
49162
49355
|
}
|
|
49163
49356
|
|
|
49164
|
-
const TRANSPARENT_BACKGROUND_SVG = /*xml*/ `
|
|
49165
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10">
|
|
49166
|
-
<path fill="#d9d9d9" d="M5 5h5v5H5zH0V0h5"/>
|
|
49167
|
-
</svg>
|
|
49168
|
-
`;
|
|
49169
|
-
css /* scss */ `
|
|
49170
|
-
.o-round-color-picker-button {
|
|
49171
|
-
width: 20px;
|
|
49172
|
-
height: 20px;
|
|
49173
|
-
cursor: pointer;
|
|
49174
|
-
border: 1px solid ${GRAY_300};
|
|
49175
|
-
background-position: 1px 1px;
|
|
49176
|
-
background-image: url("data:image/svg+xml,${encodeURIComponent(TRANSPARENT_BACKGROUND_SVG)}");
|
|
49177
|
-
}
|
|
49178
|
-
`;
|
|
49179
|
-
class RoundColorPicker extends Component {
|
|
49180
|
-
static template = "o-spreadsheet.RoundColorPicker";
|
|
49181
|
-
static components = { Section, ColorPicker };
|
|
49182
|
-
static props = {
|
|
49183
|
-
currentColor: { type: String, optional: true },
|
|
49184
|
-
title: { type: String, optional: true },
|
|
49185
|
-
onColorPicked: Function,
|
|
49186
|
-
disableNoColor: { type: Boolean, optional: true },
|
|
49187
|
-
};
|
|
49188
|
-
colorPickerButtonRef = useRef("colorPickerButton");
|
|
49189
|
-
state;
|
|
49190
|
-
setup() {
|
|
49191
|
-
this.state = useState({ pickerOpened: false });
|
|
49192
|
-
useExternalListener(window, "click", this.closePicker);
|
|
49193
|
-
}
|
|
49194
|
-
closePicker() {
|
|
49195
|
-
this.state.pickerOpened = false;
|
|
49196
|
-
}
|
|
49197
|
-
togglePicker() {
|
|
49198
|
-
this.state.pickerOpened = !this.state.pickerOpened;
|
|
49199
|
-
}
|
|
49200
|
-
onColorPicked(color) {
|
|
49201
|
-
this.props.onColorPicked(color);
|
|
49202
|
-
this.state.pickerOpened = false;
|
|
49203
|
-
}
|
|
49204
|
-
get colorPickerAnchorRect() {
|
|
49205
|
-
const button = this.colorPickerButtonRef.el;
|
|
49206
|
-
return getBoundingRectAsPOJO(button);
|
|
49207
|
-
}
|
|
49208
|
-
get buttonStyle() {
|
|
49209
|
-
return cssPropertiesToCss({
|
|
49210
|
-
background: this.props.currentColor,
|
|
49211
|
-
});
|
|
49212
|
-
}
|
|
49213
|
-
}
|
|
49214
|
-
|
|
49215
49357
|
class GeneralDesignEditor extends Component {
|
|
49216
49358
|
static template = "o-spreadsheet-GeneralDesignEditor";
|
|
49217
49359
|
static components = {
|
|
@@ -59542,7 +59684,7 @@ class DataValidationPlugin extends CorePlugin {
|
|
|
59542
59684
|
if (!rule)
|
|
59543
59685
|
return false;
|
|
59544
59686
|
return ((rule.criterion.type === "isValueInList" || rule.criterion.type === "isValueInRange") &&
|
|
59545
|
-
rule.criterion.displayStyle === "arrow");
|
|
59687
|
+
(rule.criterion.displayStyle === "arrow" || rule.criterion.displayStyle === "chip"));
|
|
59546
59688
|
}
|
|
59547
59689
|
addDataValidationRule(sheetId, newRule) {
|
|
59548
59690
|
const rules = this.rules[sheetId];
|
|
@@ -65908,7 +66050,10 @@ class EvaluationDataValidationPlugin extends CoreViewPlugin {
|
|
|
65908
66050
|
"getDataValidationInvalidCriterionValueMessage",
|
|
65909
66051
|
"getInvalidDataValidationMessage",
|
|
65910
66052
|
"getValidationResultForCellValue",
|
|
66053
|
+
"getDataValidationRangeValues",
|
|
65911
66054
|
"isCellValidCheckbox",
|
|
66055
|
+
"getDataValidationCellStyle",
|
|
66056
|
+
"getDataValidationChipStyle",
|
|
65912
66057
|
"isDataValidationInvalid",
|
|
65913
66058
|
];
|
|
65914
66059
|
validationResults = {};
|
|
@@ -65929,6 +66074,18 @@ class EvaluationDataValidationPlugin extends CoreViewPlugin {
|
|
|
65929
66074
|
isDataValidationInvalid(cellPosition) {
|
|
65930
66075
|
return !this.getValidationResultForCell(cellPosition).isValid;
|
|
65931
66076
|
}
|
|
66077
|
+
getDataValidationCellStyle(position) {
|
|
66078
|
+
if (this.hasChip(position)) {
|
|
66079
|
+
return undefined; // The style is not applied on the cell if it's a chip
|
|
66080
|
+
}
|
|
66081
|
+
return this.getDataValidationStyle(position);
|
|
66082
|
+
}
|
|
66083
|
+
getDataValidationChipStyle(position) {
|
|
66084
|
+
if (this.hasChip(position)) {
|
|
66085
|
+
return this.getDataValidationStyle(position) ?? { fillColor: GRAY_200 };
|
|
66086
|
+
}
|
|
66087
|
+
return undefined;
|
|
66088
|
+
}
|
|
65932
66089
|
getInvalidDataValidationMessage(cellPosition) {
|
|
65933
66090
|
const validationResult = this.getValidationResultForCell(cellPosition);
|
|
65934
66091
|
return validationResult.isValid ? undefined : validationResult.error;
|
|
@@ -65951,6 +66108,11 @@ class EvaluationDataValidationPlugin extends CoreViewPlugin {
|
|
|
65951
66108
|
}
|
|
65952
66109
|
return evaluator.isCriterionValueValid(value) ? undefined : evaluator.criterionValueErrorString;
|
|
65953
66110
|
}
|
|
66111
|
+
getDataValidationRangeValues(sheetId, criterion) {
|
|
66112
|
+
const range = this.getters.getRangeFromSheetXC(sheetId, String(criterion.values[0]));
|
|
66113
|
+
const criterionValues = this.getters.getRangeValues(range);
|
|
66114
|
+
return criterionValues.map((value) => value?.toString()).filter(isDefined);
|
|
66115
|
+
}
|
|
65954
66116
|
isCellValidCheckbox(cellPosition) {
|
|
65955
66117
|
if (!this.getters.isMainCellPosition(cellPosition)) {
|
|
65956
66118
|
return false;
|
|
@@ -65970,6 +66132,38 @@ class EvaluationDataValidationPlugin extends CoreViewPlugin {
|
|
|
65970
66132
|
const error = this.getRuleErrorForCellValue(cellValue, cellPosition, rule);
|
|
65971
66133
|
return error ? { error, rule, isValid: false } : VALID_RESULT;
|
|
65972
66134
|
}
|
|
66135
|
+
hasChip(position) {
|
|
66136
|
+
const rule = this.getters.getValidationRuleForCell(position);
|
|
66137
|
+
return ((rule?.criterion.type === "isValueInList" || rule?.criterion.type === "isValueInRange") &&
|
|
66138
|
+
rule.criterion.displayStyle === "chip");
|
|
66139
|
+
}
|
|
66140
|
+
getDataValidationStyle(position) {
|
|
66141
|
+
const rule = this.getters.getValidationRuleForCell(position);
|
|
66142
|
+
if (!rule || this.isDataValidationInvalid(position)) {
|
|
66143
|
+
return undefined;
|
|
66144
|
+
}
|
|
66145
|
+
const evaluatedCell = this.getters.getEvaluatedCell(position);
|
|
66146
|
+
const color = this.getValueColor(rule, evaluatedCell.value);
|
|
66147
|
+
if (!color) {
|
|
66148
|
+
return undefined;
|
|
66149
|
+
}
|
|
66150
|
+
const style = {
|
|
66151
|
+
fillColor: color,
|
|
66152
|
+
textColor: chipTextColor(color),
|
|
66153
|
+
};
|
|
66154
|
+
return style;
|
|
66155
|
+
}
|
|
66156
|
+
getValueColor(rule, value) {
|
|
66157
|
+
if (rule.criterion.type !== "isValueInList" && rule.criterion.type !== "isValueInRange") {
|
|
66158
|
+
return undefined;
|
|
66159
|
+
}
|
|
66160
|
+
for (const criterionValue in rule.criterion.colors) {
|
|
66161
|
+
if (criterionValue.toLowerCase() === String(value).toLowerCase()) {
|
|
66162
|
+
return rule.criterion.colors[criterionValue];
|
|
66163
|
+
}
|
|
66164
|
+
}
|
|
66165
|
+
return undefined;
|
|
66166
|
+
}
|
|
65973
66167
|
isValidFormula(value) {
|
|
65974
66168
|
return !compile(value).isBadExpression;
|
|
65975
66169
|
}
|
|
@@ -66066,12 +66260,35 @@ iconsOnCellRegistry.add("data_validation_checkbox", (getters, position) => {
|
|
|
66066
66260
|
}
|
|
66067
66261
|
return undefined;
|
|
66068
66262
|
});
|
|
66263
|
+
iconsOnCellRegistry.add("data_validation_chip_icon", (getters, position) => {
|
|
66264
|
+
const chipStyle = getters.getDataValidationChipStyle(position);
|
|
66265
|
+
if (chipStyle) {
|
|
66266
|
+
const cellStyle = getters.getCellComputedStyle(position);
|
|
66267
|
+
return {
|
|
66268
|
+
svg: getChipSvg(chipStyle),
|
|
66269
|
+
hoverSvg: getHoveredChipSvg(chipStyle),
|
|
66270
|
+
priority: 10,
|
|
66271
|
+
horizontalAlign: "right",
|
|
66272
|
+
size: computeTextFontSizeInPixels(cellStyle),
|
|
66273
|
+
margin: 4,
|
|
66274
|
+
position,
|
|
66275
|
+
onClick: (position, env) => {
|
|
66276
|
+
const { col, row } = position;
|
|
66277
|
+
env.model.selection.selectCell(col, row);
|
|
66278
|
+
env.startCellEdition();
|
|
66279
|
+
},
|
|
66280
|
+
type: "data_validation_chip_icon",
|
|
66281
|
+
};
|
|
66282
|
+
}
|
|
66283
|
+
return undefined;
|
|
66284
|
+
});
|
|
66069
66285
|
iconsOnCellRegistry.add("data_validation_list_icon", (getters, position) => {
|
|
66070
66286
|
const hasIcon = !getters.isReadonly() && getters.cellHasListDataValidationIcon(position);
|
|
66071
66287
|
if (hasIcon) {
|
|
66288
|
+
const cellStyle = getters.getCellComputedStyle(position);
|
|
66072
66289
|
return {
|
|
66073
|
-
svg:
|
|
66074
|
-
hoverSvg:
|
|
66290
|
+
svg: getCaretDownSvg(cellStyle),
|
|
66291
|
+
hoverSvg: getHoveredCaretDownSvg(cellStyle),
|
|
66075
66292
|
priority: 2,
|
|
66076
66293
|
horizontalAlign: "right",
|
|
66077
66294
|
size: GRID_ICON_EDGE_LENGTH,
|
|
@@ -68613,11 +68830,11 @@ class OTRegistry extends Registry {
|
|
|
68613
68830
|
* transformation function given
|
|
68614
68831
|
*/
|
|
68615
68832
|
addTransformation(executed, toTransforms, fn) {
|
|
68833
|
+
if (!this.content[executed]) {
|
|
68834
|
+
this.content[executed] = new Map();
|
|
68835
|
+
}
|
|
68616
68836
|
for (const toTransform of toTransforms) {
|
|
68617
|
-
|
|
68618
|
-
this.content[toTransform] = new Map();
|
|
68619
|
-
}
|
|
68620
|
-
this.content[toTransform].set(executed, fn);
|
|
68837
|
+
this.content[executed].set(toTransform, fn);
|
|
68621
68838
|
}
|
|
68622
68839
|
return this;
|
|
68623
68840
|
}
|
|
@@ -68626,7 +68843,7 @@ class OTRegistry extends Registry {
|
|
|
68626
68843
|
* that the executed command happened.
|
|
68627
68844
|
*/
|
|
68628
68845
|
getTransformation(toTransform, executed) {
|
|
68629
|
-
return this.content[
|
|
68846
|
+
return this.content[executed] && this.content[executed].get(toTransform);
|
|
68630
68847
|
}
|
|
68631
68848
|
}
|
|
68632
68849
|
const otRegistry = new OTRegistry();
|
|
@@ -68956,10 +69173,20 @@ function adaptTransform(toTransform, executed) {
|
|
|
68956
69173
|
*/
|
|
68957
69174
|
function transformAll(toTransform, executed) {
|
|
68958
69175
|
let transformedCommands = [...toTransform];
|
|
69176
|
+
const possibleTransformations = new Set(otRegistry.getKeys());
|
|
68959
69177
|
for (const executedCommand of executed) {
|
|
68960
|
-
|
|
68961
|
-
|
|
68962
|
-
|
|
69178
|
+
// If the executed command is not in the registry, we skip it
|
|
69179
|
+
// because we know there won't be any transformation impacting the
|
|
69180
|
+
// commands to transform.
|
|
69181
|
+
if (possibleTransformations.has(executedCommand.type)) {
|
|
69182
|
+
transformedCommands = transformedCommands.reduce((acc, cmd) => {
|
|
69183
|
+
const transformed = transform(cmd, executedCommand);
|
|
69184
|
+
if (transformed) {
|
|
69185
|
+
acc.push(transformed);
|
|
69186
|
+
}
|
|
69187
|
+
return acc;
|
|
69188
|
+
}, []);
|
|
69189
|
+
}
|
|
68963
69190
|
}
|
|
68964
69191
|
return transformedCommands;
|
|
68965
69192
|
}
|
|
@@ -70516,6 +70743,9 @@ class SheetUIPlugin extends UIPlugin {
|
|
|
70516
70743
|
for (const icon of this.getters.getCellIcons(position)) {
|
|
70517
70744
|
contentWidth += icon.margin + icon.size;
|
|
70518
70745
|
}
|
|
70746
|
+
if (this.getters.getDataValidationChipStyle(position)) {
|
|
70747
|
+
contentWidth += DATA_VALIDATION_CHIP_MARGIN * 2;
|
|
70748
|
+
}
|
|
70519
70749
|
if (contentWidth === 0) {
|
|
70520
70750
|
return 0;
|
|
70521
70751
|
}
|
|
@@ -70673,7 +70903,7 @@ class SheetUIPlugin extends UIPlugin {
|
|
|
70673
70903
|
}
|
|
70674
70904
|
const position = this.getters.getCellPosition(cell.id);
|
|
70675
70905
|
const colSize = this.getters.getColSize(sheetId, position.col);
|
|
70676
|
-
if (cell.isFormula) {
|
|
70906
|
+
if (cell.isFormula || this.getters.getArrayFormulaSpreadingOn(position)) {
|
|
70677
70907
|
const content = this.getters.getEvaluatedCell(position).formattedValue;
|
|
70678
70908
|
const evaluatedSize = getCellContentHeight(this.ctx, content, cell?.style, colSize);
|
|
70679
70909
|
if (evaluatedSize > evaluatedRowSize && evaluatedSize > DEFAULT_CELL_HEIGHT) {
|
|
@@ -70876,6 +71106,8 @@ class CellComputedStylePlugin extends UIPlugin {
|
|
|
70876
71106
|
if (invalidateEvaluationCommands.has(cmd.type) ||
|
|
70877
71107
|
cmd.type === "UPDATE_CELL" ||
|
|
70878
71108
|
cmd.type === "SET_FORMATTING" ||
|
|
71109
|
+
cmd.type === "ADD_DATA_VALIDATION_RULE" ||
|
|
71110
|
+
cmd.type === "REMOVE_DATA_VALIDATION_RULE" ||
|
|
70879
71111
|
cmd.type === "EVALUATE_CELLS") {
|
|
70880
71112
|
this.styles = {};
|
|
70881
71113
|
this.borders = {};
|
|
@@ -70947,8 +71179,10 @@ class CellComputedStylePlugin extends UIPlugin {
|
|
|
70947
71179
|
const cell = this.getters.getCell(position);
|
|
70948
71180
|
const cfStyle = this.getters.getCellConditionalFormatStyle(position);
|
|
70949
71181
|
const tableStyle = this.getters.getCellTableStyle(position);
|
|
71182
|
+
const dataValidationStyle = this.getters.getDataValidationCellStyle(position);
|
|
70950
71183
|
const computedStyle = {
|
|
70951
71184
|
...removeFalsyAttributes(tableStyle),
|
|
71185
|
+
...removeFalsyAttributes(dataValidationStyle),
|
|
70952
71186
|
...removeFalsyAttributes(cell?.style),
|
|
70953
71187
|
...removeFalsyAttributes(cfStyle),
|
|
70954
71188
|
};
|
|
@@ -74510,19 +74744,29 @@ autoCompleteProviders.add("dataValidation", {
|
|
|
74510
74744
|
(rule.criterion.type !== "isValueInList" && rule.criterion.type !== "isValueInRange")) {
|
|
74511
74745
|
return [];
|
|
74512
74746
|
}
|
|
74513
|
-
|
|
74514
|
-
|
|
74515
|
-
|
|
74516
|
-
|
|
74517
|
-
|
|
74518
|
-
|
|
74519
|
-
values
|
|
74520
|
-
|
|
74521
|
-
|
|
74522
|
-
|
|
74523
|
-
|
|
74524
|
-
|
|
74525
|
-
|
|
74747
|
+
const sheetId = this.composer.currentEditedCell.sheetId;
|
|
74748
|
+
const values = rule.criterion.type === "isValueInRange"
|
|
74749
|
+
? Array.from(new Set(this.getters.getDataValidationRangeValues(sheetId, rule.criterion)))
|
|
74750
|
+
: rule.criterion.values;
|
|
74751
|
+
const isChip = rule.criterion.displayStyle === "chip";
|
|
74752
|
+
if (!isChip) {
|
|
74753
|
+
return values.map((value) => ({ text: value }));
|
|
74754
|
+
}
|
|
74755
|
+
const colors = rule.criterion.colors;
|
|
74756
|
+
return values.map((value) => {
|
|
74757
|
+
const color = colors?.[value];
|
|
74758
|
+
return {
|
|
74759
|
+
text: value,
|
|
74760
|
+
htmlContent: [
|
|
74761
|
+
{
|
|
74762
|
+
value,
|
|
74763
|
+
color: color ? chipTextColor(color) : undefined,
|
|
74764
|
+
backgroundColor: color || GRAY_200,
|
|
74765
|
+
classes: ["badge rounded-pill fs-6 fw-normal w-100 mt-1 text-start"],
|
|
74766
|
+
},
|
|
74767
|
+
],
|
|
74768
|
+
};
|
|
74769
|
+
});
|
|
74526
74770
|
},
|
|
74527
74771
|
selectProposal(tokenAtCursor, value) {
|
|
74528
74772
|
this.composer.setCurrentContent(value);
|
|
@@ -83342,6 +83586,6 @@ const chartHelpers = { ...CHART_HELPERS, ...CHART_RUNTIME_HELPERS };
|
|
|
83342
83586
|
export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, ClientDisconnectedError, CommandResult, CorePlugin, CoreViewPlugin, DispatchResult, EvaluationError, LocalTransportService, Model, PivotRuntimeDefinition, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, SpreadsheetPivotTable, UIPlugin, __info__, addFunction, addRenderingLayer, astToFormula, chartHelpers, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateChartEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, stores, tokenColors, tokenize };
|
|
83343
83587
|
|
|
83344
83588
|
|
|
83345
|
-
__info__.version = "18.4.0-alpha.
|
|
83346
|
-
__info__.date = "2025-06-
|
|
83347
|
-
__info__.hash = "
|
|
83589
|
+
__info__.version = "18.4.0-alpha.9";
|
|
83590
|
+
__info__.date = "2025-06-19T18:23:22.025Z";
|
|
83591
|
+
__info__.hash = "6d4d685";
|