@rowsncolumns/utils 9.5.3 → 9.5.5

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.
@@ -16,5 +16,45 @@ export declare const hexToRgb: (hex: string) => {
16
16
  b: number;
17
17
  };
18
18
  export declare const rgbToHex: (r: number, g: number, b: number) => string;
19
+ /**
20
+ * Excel's colour variations for a chart palette that runs out of entries —
21
+ * the default chart colour style ("Colorful Palette 1", `colors1.xml`,
22
+ * `meth="cycle"`): the palette's entries are used as-is on the first pass,
23
+ * and every further pass reuses them with a luminance modification
24
+ * (`lumMod` scales each channel, `lumOff` adds toward white; 1 = 100%):
25
+ * darker, lighter, slightly darker, lighter still, … Nine passes, then the
26
+ * sequence repeats — 54 distinguishable shades over the six theme accents
27
+ * before any exact repeat. A pie with seven slices therefore gets accent 1
28
+ * darkened for slice 7, not accent 1 again.
29
+ */
30
+ export declare const CHART_PALETTE_VARIATIONS: ReadonlyArray<{
31
+ lumMod: number;
32
+ lumOff: number;
33
+ }>;
34
+ /**
35
+ * Apply DrawingML `lumMod` / `lumOff` (as fractions, 1 = 100%) to a colour:
36
+ * each channel becomes `c * lumMod + 255 * lumOff`, clamped — the arithmetic
37
+ * the xlsx importer uses for `<a:schemeClr>` modifiers, so a derived palette
38
+ * colour renders exactly as the same modifier read back from a file. A colour
39
+ * the normalizer cannot parse is returned unchanged; the result is `#RRGGBB`
40
+ * upper-case (the exporter's and importer's hex convention).
41
+ */
42
+ export declare const applyLumModOff: (color: string, lumMod: number, lumOff: number) => string;
43
+ /**
44
+ * The colour for point / series `index` of a chart palette: the palette
45
+ * cycles, and each pass past its length applies the next
46
+ * {@link CHART_PALETTE_VARIATIONS} entry to the base colour (Excel's
47
+ * `varyColors` behaviour). Indexing an empty palette behaves like
48
+ * `palette[i]` (undefined at runtime); callers pass a non-empty palette.
49
+ */
50
+ export declare const chartPaletteColorAt: (palette: readonly string[], index: number) => string;
51
+ /**
52
+ * The palette unrolled through every variation pass — what to hand a
53
+ * renderer that cycles a colour list itself (echarts' option-level `color`,
54
+ * plotly's `marker.colors`): the first `palette.length` entries are the
55
+ * palette, the rest its variations, so the renderer's own wrap-around only
56
+ * starts where Excel's does.
57
+ */
58
+ export declare const expandChartPalette: (palette: readonly string[]) => string[];
19
59
  export declare const getContrastColor: (backgroundColor: string, lightColor: string, darkColor: string) => string | undefined;
20
60
  //# sourceMappingURL=color.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"color.d.ts","sourceRoot":"","sources":["../../color.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,wBAAwB,GAAI,KAAK,MAAM,WAoCnD,CAAC;AAEF,MAAM,MAAM,IAAI,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAYnE,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAkBzD;AAED,eAAO,MAAM,aAAa,GAAI,gBAAoB,IAAI,WAUrD,CAAC;AAEF,eAAO,MAAM,WAAW,GACtB,QAAQ,MAAM,GAAG,SAAS,EAC1B,QAAQ,MAAM,GAAG,SAAS,wBAiB3B,CAAC;AAQF,eAAO,MAAM,gBAAgB,GAAI,OAAO,MAAM,GAAG,SAAS,uBAczD,CAAC;AAGF,eAAO,MAAM,YAAY,GAAI,wBAAU,EAAE,OAAO,MAAM,uBAGrD,CAAC;AAEF,eAAO,MAAM,QAAQ,GAAI,KAAK,MAAM;;;;CAOnC,CAAC;AAEF,eAAO,MAAM,QAAQ,GAAI,GAAG,MAAM,EAAE,GAAG,MAAM,EAAE,GAAG,MAAM,WAGvD,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAC3B,iBAAiB,MAAM,EACvB,YAAY,MAAM,EAClB,WAAW,MAAM,uBAUlB,CAAC"}
1
+ {"version":3,"file":"color.d.ts","sourceRoot":"","sources":["../../color.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,wBAAwB,GAAI,KAAK,MAAM,WAoCnD,CAAC;AAEF,MAAM,MAAM,IAAI,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAYnE,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAkBzD;AAED,eAAO,MAAM,aAAa,GAAI,gBAAoB,IAAI,WAUrD,CAAC;AAEF,eAAO,MAAM,WAAW,GACtB,QAAQ,MAAM,GAAG,SAAS,EAC1B,QAAQ,MAAM,GAAG,SAAS,wBAiB3B,CAAC;AAQF,eAAO,MAAM,gBAAgB,GAAI,OAAO,MAAM,GAAG,SAAS,uBAczD,CAAC;AAGF,eAAO,MAAM,YAAY,GAAI,wBAAU,EAAE,OAAO,MAAM,uBAGrD,CAAC;AAEF,eAAO,MAAM,QAAQ,GAAI,KAAK,MAAM;;;;CAOnC,CAAC;AAEF,eAAO,MAAM,QAAQ,GAAI,GAAG,MAAM,EAAE,GAAG,MAAM,EAAE,GAAG,MAAM,WAGvD,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,wBAAwB,EAAE,aAAa,CAAC;IACnD,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB,CAUA,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,GACzB,OAAO,MAAM,EACb,QAAQ,MAAM,EACd,QAAQ,MAAM,KACb,MAUF,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,GAC9B,SAAS,SAAS,MAAM,EAAE,EAC1B,OAAO,MAAM,KACZ,MAMF,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,GAAI,SAAS,SAAS,MAAM,EAAE,KAAG,MAAM,EAInE,CAAC;AAEJ,eAAO,MAAM,gBAAgB,GAC3B,iBAAiB,MAAM,EACvB,YAAY,MAAM,EAClB,WAAW,MAAM,uBAUlB,CAAC"}
package/dist/cjs/color.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getContrastColor = exports.rgbToHex = exports.hexToRgb = exports.lightenColor = exports.colorStringToHex = exports.isSameColor = exports.rgbaToArgbHex = exports.getSelectionColorAtIndex = void 0;
3
+ exports.getContrastColor = exports.expandChartPalette = exports.chartPaletteColorAt = exports.applyLumModOff = exports.CHART_PALETTE_VARIATIONS = exports.rgbToHex = exports.hexToRgb = exports.lightenColor = exports.colorStringToHex = exports.isSameColor = exports.rgbaToArgbHex = exports.getSelectionColorAtIndex = void 0;
4
4
  exports.normalizeColor = normalizeColor;
5
5
  var tslib_1 = require("tslib");
6
6
  var typeguards_1 = require("./typeguards");
@@ -139,6 +139,78 @@ var rgbToHex = function (r, g, b) {
139
139
  return "#" + ("000000" + hex).slice(-6);
140
140
  };
141
141
  exports.rgbToHex = rgbToHex;
142
+ /**
143
+ * Excel's colour variations for a chart palette that runs out of entries —
144
+ * the default chart colour style ("Colorful Palette 1", `colors1.xml`,
145
+ * `meth="cycle"`): the palette's entries are used as-is on the first pass,
146
+ * and every further pass reuses them with a luminance modification
147
+ * (`lumMod` scales each channel, `lumOff` adds toward white; 1 = 100%):
148
+ * darker, lighter, slightly darker, lighter still, … Nine passes, then the
149
+ * sequence repeats — 54 distinguishable shades over the six theme accents
150
+ * before any exact repeat. A pie with seven slices therefore gets accent 1
151
+ * darkened for slice 7, not accent 1 again.
152
+ */
153
+ exports.CHART_PALETTE_VARIATIONS = [
154
+ { lumMod: 1, lumOff: 0 },
155
+ { lumMod: 0.6, lumOff: 0 },
156
+ { lumMod: 0.8, lumOff: 0.2 },
157
+ { lumMod: 0.8, lumOff: 0 },
158
+ { lumMod: 0.6, lumOff: 0.4 },
159
+ { lumMod: 0.5, lumOff: 0 },
160
+ { lumMod: 0.7, lumOff: 0.3 },
161
+ { lumMod: 0.7, lumOff: 0 },
162
+ { lumMod: 0.5, lumOff: 0.5 },
163
+ ];
164
+ /**
165
+ * Apply DrawingML `lumMod` / `lumOff` (as fractions, 1 = 100%) to a colour:
166
+ * each channel becomes `c * lumMod + 255 * lumOff`, clamped — the arithmetic
167
+ * the xlsx importer uses for `<a:schemeClr>` modifiers, so a derived palette
168
+ * colour renders exactly as the same modifier read back from a file. A colour
169
+ * the normalizer cannot parse is returned unchanged; the result is `#RRGGBB`
170
+ * upper-case (the exporter's and importer's hex convention).
171
+ */
172
+ var applyLumModOff = function (color, lumMod, lumOff) {
173
+ if (lumMod === 1 && lumOff === 0)
174
+ return color;
175
+ var rgba = normalizeColor(color.trim());
176
+ if (!rgba || !Number.isFinite(rgba.r + rgba.g + rgba.b))
177
+ return color;
178
+ var channel = function (c) {
179
+ return Math.max(0, Math.min(255, Math.round(c * lumMod + 255 * lumOff)))
180
+ .toString(16)
181
+ .padStart(2, "0")
182
+ .toUpperCase();
183
+ };
184
+ return "#".concat(channel(rgba.r)).concat(channel(rgba.g)).concat(channel(rgba.b));
185
+ };
186
+ exports.applyLumModOff = applyLumModOff;
187
+ /**
188
+ * The colour for point / series `index` of a chart palette: the palette
189
+ * cycles, and each pass past its length applies the next
190
+ * {@link CHART_PALETTE_VARIATIONS} entry to the base colour (Excel's
191
+ * `varyColors` behaviour). Indexing an empty palette behaves like
192
+ * `palette[i]` (undefined at runtime); callers pass a non-empty palette.
193
+ */
194
+ var chartPaletteColorAt = function (palette, index) {
195
+ var base = palette[index % palette.length];
196
+ if (typeof base !== "string")
197
+ return base;
198
+ var pass = Math.floor(index / palette.length) % exports.CHART_PALETTE_VARIATIONS.length;
199
+ var _a = exports.CHART_PALETTE_VARIATIONS[pass], lumMod = _a.lumMod, lumOff = _a.lumOff;
200
+ return (0, exports.applyLumModOff)(base, lumMod, lumOff);
201
+ };
202
+ exports.chartPaletteColorAt = chartPaletteColorAt;
203
+ /**
204
+ * The palette unrolled through every variation pass — what to hand a
205
+ * renderer that cycles a colour list itself (echarts' option-level `color`,
206
+ * plotly's `marker.colors`): the first `palette.length` entries are the
207
+ * palette, the rest its variations, so the renderer's own wrap-around only
208
+ * starts where Excel's does.
209
+ */
210
+ var expandChartPalette = function (palette) {
211
+ return Array.from({ length: palette.length * exports.CHART_PALETTE_VARIATIONS.length }, function (_, index) { return (0, exports.chartPaletteColorAt)(palette, index); });
212
+ };
213
+ exports.expandChartPalette = expandChartPalette;
142
214
  var getContrastColor = function (backgroundColor, lightColor, darkColor) {
143
215
  var rgbColor = normalizeColor(backgroundColor);
144
216
  if (rgbColor) {
@@ -1,3 +1,11 @@
1
+ /**
2
+ * Excel's 1900 date system counts a day that never happened: serial 60 is
3
+ * 1900-02-29 (Lotus 1-2-3 compatibility). 1900-01-01 is 1, 1900-02-28 is 59,
4
+ * 1900-03-01 is 61. Google Sheets keeps the same numbering.
5
+ */
6
+ export declare const EXCEL_LEAP_BUG_SERIAL = 60;
7
+ /** The calendar day Excel's serial 60 stands for, which no `Date` can hold. */
8
+ export declare const isExcelLeapDay: (year: number, month: number, day: number) => boolean;
1
9
  export type DateSerialMode = "local" | "excel-utc";
2
10
  /**
3
11
  * Convert date to serial with explicit time zone behavior.
@@ -6,6 +14,14 @@ export type DateSerialMode = "local" | "excel-utc";
6
14
  */
7
15
  export declare const toSerialWithMode: (date: Date, use1904?: boolean, mode?: DateSerialMode) => number;
8
16
  export declare const toSerial: (date: Date, use1904?: boolean) => number;
17
+ /**
18
+ * Serial for calendar parts the way a user typed them. Unlike
19
+ * `toSerial(new Date(y, m, d))`, this never goes through a `Date`, so the
20
+ * phantom 1900-02-29 stays serial 60 instead of rolling over to March 1
21
+ * (rowsncolumns/spreadsheet#1026). Every other date takes the same path as
22
+ * `toSerial` in "local" mode. `month` is 0-based like `Date`.
23
+ */
24
+ export declare const toSerialFromParts: (year: number, month: number, day: number, hour?: number, minute?: number, second?: number, use1904?: boolean) => number;
9
25
  /**
10
26
  * Convert serial to date
11
27
  * @param serial
@@ -1 +1 @@
1
- {"version":3,"file":"date.d.ts","sourceRoot":"","sources":["../../date.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,WAAW,CAAC;AAEnD;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,GAC3B,MAAM,IAAI,EACV,iBAAe,EACf,OAAM,cAAwB,WAwB/B,CAAC;AAEF,eAAO,MAAM,QAAQ,GAAI,MAAM,IAAI,EAAE,iBAAe,WAEnD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,MAAM,GAAI,QAAQ,MAAM,EAAE,iBAAe,SA+BrD,CAAC"}
1
+ {"version":3,"file":"date.d.ts","sourceRoot":"","sources":["../../date.ts"],"names":[],"mappings":"AACA;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,KAAK,CAAC;AAExC,+EAA+E;AAC/E,eAAO,MAAM,cAAc,GAAI,MAAM,MAAM,EAAE,OAAO,MAAM,EAAE,KAAK,MAAM,YAC3B,CAAC;AAE7C,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,WAAW,CAAC;AAEnD;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,GAC3B,MAAM,IAAI,EACV,iBAAe,EACf,OAAM,cAAwB,WAwB/B,CAAC;AAEF,eAAO,MAAM,QAAQ,GAAI,MAAM,IAAI,EAAE,iBAAe,WAEnD,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,GAC5B,MAAM,MAAM,EACZ,OAAO,MAAM,EACb,KAAK,MAAM,EACX,aAAQ,EACR,eAAU,EACV,eAAU,EACV,iBAAe,WAWhB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,MAAM,GAAI,QAAQ,MAAM,EAAE,iBAAe,SA+BrD,CAAC"}
package/dist/cjs/date.js CHANGED
@@ -1,8 +1,18 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.toDate = exports.toSerial = exports.toSerialWithMode = void 0;
3
+ exports.toDate = exports.toSerialFromParts = exports.toSerial = exports.toSerialWithMode = exports.isExcelLeapDay = exports.EXCEL_LEAP_BUG_SERIAL = void 0;
4
4
  var DAY_TO_MS = 24 * 60 * 60 * 1000;
5
- var EXCEL_LEAP_BUG_SERIAL = 60;
5
+ /**
6
+ * Excel's 1900 date system counts a day that never happened: serial 60 is
7
+ * 1900-02-29 (Lotus 1-2-3 compatibility). 1900-01-01 is 1, 1900-02-28 is 59,
8
+ * 1900-03-01 is 61. Google Sheets keeps the same numbering.
9
+ */
10
+ exports.EXCEL_LEAP_BUG_SERIAL = 60;
11
+ /** The calendar day Excel's serial 60 stands for, which no `Date` can hold. */
12
+ var isExcelLeapDay = function (year, month, day) {
13
+ return year === 1900 && month === 1 && day === 29;
14
+ };
15
+ exports.isExcelLeapDay = isExcelLeapDay;
6
16
  /**
7
17
  * Convert date to serial with explicit time zone behavior.
8
18
  * - local: interpret date components in local time (UI entry behavior).
@@ -31,6 +41,25 @@ var toSerial = function (date, use1904) {
31
41
  return (0, exports.toSerialWithMode)(date, use1904, "local");
32
42
  };
33
43
  exports.toSerial = toSerial;
44
+ /**
45
+ * Serial for calendar parts the way a user typed them. Unlike
46
+ * `toSerial(new Date(y, m, d))`, this never goes through a `Date`, so the
47
+ * phantom 1900-02-29 stays serial 60 instead of rolling over to March 1
48
+ * (rowsncolumns/spreadsheet#1026). Every other date takes the same path as
49
+ * `toSerial` in "local" mode. `month` is 0-based like `Date`.
50
+ */
51
+ var toSerialFromParts = function (year, month, day, hour, minute, second, use1904) {
52
+ if (hour === void 0) { hour = 0; }
53
+ if (minute === void 0) { minute = 0; }
54
+ if (second === void 0) { second = 0; }
55
+ if (use1904 === void 0) { use1904 = false; }
56
+ var timeFraction = (hour * 3600 + minute * 60 + second) / (24 * 60 * 60);
57
+ if (!use1904 && (0, exports.isExcelLeapDay)(year, month, day)) {
58
+ return exports.EXCEL_LEAP_BUG_SERIAL + timeFraction;
59
+ }
60
+ return (0, exports.toSerialWithMode)(new Date(year, month, day, hour, minute, second, 0), use1904, "local");
61
+ };
62
+ exports.toSerialFromParts = toSerialFromParts;
34
63
  /**
35
64
  * Convert serial to date
36
65
  * @param serial
@@ -44,11 +73,11 @@ var toDate = function (serial, use1904) {
44
73
  var utcDate_1 = new Date(utcMillis_1);
45
74
  return new Date(utcDate_1.getUTCFullYear(), utcDate_1.getUTCMonth(), utcDate_1.getUTCDate(), utcDate_1.getUTCHours(), utcDate_1.getUTCMinutes(), utcDate_1.getUTCSeconds(), utcDate_1.getUTCMilliseconds());
46
75
  }
47
- if (serial === EXCEL_LEAP_BUG_SERIAL) {
76
+ if (serial === exports.EXCEL_LEAP_BUG_SERIAL) {
48
77
  return new Date(1900, 1, 28);
49
78
  }
50
79
  var baseUtc = Date.UTC(1899, 11, 31);
51
- var dayCount = serial < EXCEL_LEAP_BUG_SERIAL ? serial : serial - 1;
80
+ var dayCount = serial < exports.EXCEL_LEAP_BUG_SERIAL ? serial : serial - 1;
52
81
  var utcMillis = baseUtc + dayCount * DAY_TO_MS;
53
82
  var utcDate = new Date(utcMillis);
54
83
  return new Date(utcDate.getUTCFullYear(), utcDate.getUTCMonth(), utcDate.getUTCDate(), utcDate.getUTCHours(), utcDate.getUTCMinutes(), utcDate.getUTCSeconds(), utcDate.getUTCMilliseconds());
@@ -16,5 +16,45 @@ export declare const hexToRgb: (hex: string) => {
16
16
  b: number;
17
17
  };
18
18
  export declare const rgbToHex: (r: number, g: number, b: number) => string;
19
+ /**
20
+ * Excel's colour variations for a chart palette that runs out of entries —
21
+ * the default chart colour style ("Colorful Palette 1", `colors1.xml`,
22
+ * `meth="cycle"`): the palette's entries are used as-is on the first pass,
23
+ * and every further pass reuses them with a luminance modification
24
+ * (`lumMod` scales each channel, `lumOff` adds toward white; 1 = 100%):
25
+ * darker, lighter, slightly darker, lighter still, … Nine passes, then the
26
+ * sequence repeats — 54 distinguishable shades over the six theme accents
27
+ * before any exact repeat. A pie with seven slices therefore gets accent 1
28
+ * darkened for slice 7, not accent 1 again.
29
+ */
30
+ export declare const CHART_PALETTE_VARIATIONS: ReadonlyArray<{
31
+ lumMod: number;
32
+ lumOff: number;
33
+ }>;
34
+ /**
35
+ * Apply DrawingML `lumMod` / `lumOff` (as fractions, 1 = 100%) to a colour:
36
+ * each channel becomes `c * lumMod + 255 * lumOff`, clamped — the arithmetic
37
+ * the xlsx importer uses for `<a:schemeClr>` modifiers, so a derived palette
38
+ * colour renders exactly as the same modifier read back from a file. A colour
39
+ * the normalizer cannot parse is returned unchanged; the result is `#RRGGBB`
40
+ * upper-case (the exporter's and importer's hex convention).
41
+ */
42
+ export declare const applyLumModOff: (color: string, lumMod: number, lumOff: number) => string;
43
+ /**
44
+ * The colour for point / series `index` of a chart palette: the palette
45
+ * cycles, and each pass past its length applies the next
46
+ * {@link CHART_PALETTE_VARIATIONS} entry to the base colour (Excel's
47
+ * `varyColors` behaviour). Indexing an empty palette behaves like
48
+ * `palette[i]` (undefined at runtime); callers pass a non-empty palette.
49
+ */
50
+ export declare const chartPaletteColorAt: (palette: readonly string[], index: number) => string;
51
+ /**
52
+ * The palette unrolled through every variation pass — what to hand a
53
+ * renderer that cycles a colour list itself (echarts' option-level `color`,
54
+ * plotly's `marker.colors`): the first `palette.length` entries are the
55
+ * palette, the rest its variations, so the renderer's own wrap-around only
56
+ * starts where Excel's does.
57
+ */
58
+ export declare const expandChartPalette: (palette: readonly string[]) => string[];
19
59
  export declare const getContrastColor: (backgroundColor: string, lightColor: string, darkColor: string) => string | undefined;
20
60
  //# sourceMappingURL=color.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"color.d.ts","sourceRoot":"","sources":["../../color.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,wBAAwB,GAAI,KAAK,MAAM,WAoCnD,CAAC;AAEF,MAAM,MAAM,IAAI,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAYnE,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAkBzD;AAED,eAAO,MAAM,aAAa,GAAI,gBAAoB,IAAI,WAUrD,CAAC;AAEF,eAAO,MAAM,WAAW,GACtB,QAAQ,MAAM,GAAG,SAAS,EAC1B,QAAQ,MAAM,GAAG,SAAS,wBAiB3B,CAAC;AAQF,eAAO,MAAM,gBAAgB,GAAI,OAAO,MAAM,GAAG,SAAS,uBAczD,CAAC;AAGF,eAAO,MAAM,YAAY,GAAI,wBAAU,EAAE,OAAO,MAAM,uBAGrD,CAAC;AAEF,eAAO,MAAM,QAAQ,GAAI,KAAK,MAAM;;;;CAOnC,CAAC;AAEF,eAAO,MAAM,QAAQ,GAAI,GAAG,MAAM,EAAE,GAAG,MAAM,EAAE,GAAG,MAAM,WAGvD,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAC3B,iBAAiB,MAAM,EACvB,YAAY,MAAM,EAClB,WAAW,MAAM,uBAUlB,CAAC"}
1
+ {"version":3,"file":"color.d.ts","sourceRoot":"","sources":["../../color.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,wBAAwB,GAAI,KAAK,MAAM,WAoCnD,CAAC;AAEF,MAAM,MAAM,IAAI,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAYnE,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAkBzD;AAED,eAAO,MAAM,aAAa,GAAI,gBAAoB,IAAI,WAUrD,CAAC;AAEF,eAAO,MAAM,WAAW,GACtB,QAAQ,MAAM,GAAG,SAAS,EAC1B,QAAQ,MAAM,GAAG,SAAS,wBAiB3B,CAAC;AAQF,eAAO,MAAM,gBAAgB,GAAI,OAAO,MAAM,GAAG,SAAS,uBAczD,CAAC;AAGF,eAAO,MAAM,YAAY,GAAI,wBAAU,EAAE,OAAO,MAAM,uBAGrD,CAAC;AAEF,eAAO,MAAM,QAAQ,GAAI,KAAK,MAAM;;;;CAOnC,CAAC;AAEF,eAAO,MAAM,QAAQ,GAAI,GAAG,MAAM,EAAE,GAAG,MAAM,EAAE,GAAG,MAAM,WAGvD,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,wBAAwB,EAAE,aAAa,CAAC;IACnD,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB,CAUA,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,GACzB,OAAO,MAAM,EACb,QAAQ,MAAM,EACd,QAAQ,MAAM,KACb,MAUF,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,GAC9B,SAAS,SAAS,MAAM,EAAE,EAC1B,OAAO,MAAM,KACZ,MAMF,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,GAAI,SAAS,SAAS,MAAM,EAAE,KAAG,MAAM,EAInE,CAAC;AAEJ,eAAO,MAAM,gBAAgB,GAC3B,iBAAiB,MAAM,EACvB,YAAY,MAAM,EAClB,WAAW,MAAM,uBAUlB,CAAC"}
package/dist/esm/color.js CHANGED
@@ -125,6 +125,71 @@ export const rgbToHex = (r, g, b) => {
125
125
  const hex = ((r << 16) | (g << 8) | b).toString(16);
126
126
  return "#" + ("000000" + hex).slice(-6);
127
127
  };
128
+ /**
129
+ * Excel's colour variations for a chart palette that runs out of entries —
130
+ * the default chart colour style ("Colorful Palette 1", `colors1.xml`,
131
+ * `meth="cycle"`): the palette's entries are used as-is on the first pass,
132
+ * and every further pass reuses them with a luminance modification
133
+ * (`lumMod` scales each channel, `lumOff` adds toward white; 1 = 100%):
134
+ * darker, lighter, slightly darker, lighter still, … Nine passes, then the
135
+ * sequence repeats — 54 distinguishable shades over the six theme accents
136
+ * before any exact repeat. A pie with seven slices therefore gets accent 1
137
+ * darkened for slice 7, not accent 1 again.
138
+ */
139
+ export const CHART_PALETTE_VARIATIONS = [
140
+ { lumMod: 1, lumOff: 0 },
141
+ { lumMod: 0.6, lumOff: 0 },
142
+ { lumMod: 0.8, lumOff: 0.2 },
143
+ { lumMod: 0.8, lumOff: 0 },
144
+ { lumMod: 0.6, lumOff: 0.4 },
145
+ { lumMod: 0.5, lumOff: 0 },
146
+ { lumMod: 0.7, lumOff: 0.3 },
147
+ { lumMod: 0.7, lumOff: 0 },
148
+ { lumMod: 0.5, lumOff: 0.5 },
149
+ ];
150
+ /**
151
+ * Apply DrawingML `lumMod` / `lumOff` (as fractions, 1 = 100%) to a colour:
152
+ * each channel becomes `c * lumMod + 255 * lumOff`, clamped — the arithmetic
153
+ * the xlsx importer uses for `<a:schemeClr>` modifiers, so a derived palette
154
+ * colour renders exactly as the same modifier read back from a file. A colour
155
+ * the normalizer cannot parse is returned unchanged; the result is `#RRGGBB`
156
+ * upper-case (the exporter's and importer's hex convention).
157
+ */
158
+ export const applyLumModOff = (color, lumMod, lumOff) => {
159
+ if (lumMod === 1 && lumOff === 0)
160
+ return color;
161
+ const rgba = normalizeColor(color.trim());
162
+ if (!rgba || !Number.isFinite(rgba.r + rgba.g + rgba.b))
163
+ return color;
164
+ const channel = (c) => Math.max(0, Math.min(255, Math.round(c * lumMod + 255 * lumOff)))
165
+ .toString(16)
166
+ .padStart(2, "0")
167
+ .toUpperCase();
168
+ return `#${channel(rgba.r)}${channel(rgba.g)}${channel(rgba.b)}`;
169
+ };
170
+ /**
171
+ * The colour for point / series `index` of a chart palette: the palette
172
+ * cycles, and each pass past its length applies the next
173
+ * {@link CHART_PALETTE_VARIATIONS} entry to the base colour (Excel's
174
+ * `varyColors` behaviour). Indexing an empty palette behaves like
175
+ * `palette[i]` (undefined at runtime); callers pass a non-empty palette.
176
+ */
177
+ export const chartPaletteColorAt = (palette, index) => {
178
+ const base = palette[index % palette.length];
179
+ if (typeof base !== "string")
180
+ return base;
181
+ const pass = Math.floor(index / palette.length) % CHART_PALETTE_VARIATIONS.length;
182
+ const { lumMod, lumOff } = CHART_PALETTE_VARIATIONS[pass];
183
+ return applyLumModOff(base, lumMod, lumOff);
184
+ };
185
+ /**
186
+ * The palette unrolled through every variation pass — what to hand a
187
+ * renderer that cycles a colour list itself (echarts' option-level `color`,
188
+ * plotly's `marker.colors`): the first `palette.length` entries are the
189
+ * palette, the rest its variations, so the renderer's own wrap-around only
190
+ * starts where Excel's does.
191
+ */
192
+ export const expandChartPalette = (palette) => Array.from({ length: palette.length * CHART_PALETTE_VARIATIONS.length }, (_, index) => chartPaletteColorAt(palette, index));
128
193
  export const getContrastColor = (backgroundColor, lightColor, darkColor) => {
129
194
  const rgbColor = normalizeColor(backgroundColor);
130
195
  if (rgbColor) {
@@ -1,3 +1,11 @@
1
+ /**
2
+ * Excel's 1900 date system counts a day that never happened: serial 60 is
3
+ * 1900-02-29 (Lotus 1-2-3 compatibility). 1900-01-01 is 1, 1900-02-28 is 59,
4
+ * 1900-03-01 is 61. Google Sheets keeps the same numbering.
5
+ */
6
+ export declare const EXCEL_LEAP_BUG_SERIAL = 60;
7
+ /** The calendar day Excel's serial 60 stands for, which no `Date` can hold. */
8
+ export declare const isExcelLeapDay: (year: number, month: number, day: number) => boolean;
1
9
  export type DateSerialMode = "local" | "excel-utc";
2
10
  /**
3
11
  * Convert date to serial with explicit time zone behavior.
@@ -6,6 +14,14 @@ export type DateSerialMode = "local" | "excel-utc";
6
14
  */
7
15
  export declare const toSerialWithMode: (date: Date, use1904?: boolean, mode?: DateSerialMode) => number;
8
16
  export declare const toSerial: (date: Date, use1904?: boolean) => number;
17
+ /**
18
+ * Serial for calendar parts the way a user typed them. Unlike
19
+ * `toSerial(new Date(y, m, d))`, this never goes through a `Date`, so the
20
+ * phantom 1900-02-29 stays serial 60 instead of rolling over to March 1
21
+ * (rowsncolumns/spreadsheet#1026). Every other date takes the same path as
22
+ * `toSerial` in "local" mode. `month` is 0-based like `Date`.
23
+ */
24
+ export declare const toSerialFromParts: (year: number, month: number, day: number, hour?: number, minute?: number, second?: number, use1904?: boolean) => number;
9
25
  /**
10
26
  * Convert serial to date
11
27
  * @param serial
@@ -1 +1 @@
1
- {"version":3,"file":"date.d.ts","sourceRoot":"","sources":["../../date.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,WAAW,CAAC;AAEnD;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,GAC3B,MAAM,IAAI,EACV,iBAAe,EACf,OAAM,cAAwB,WAwB/B,CAAC;AAEF,eAAO,MAAM,QAAQ,GAAI,MAAM,IAAI,EAAE,iBAAe,WAEnD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,MAAM,GAAI,QAAQ,MAAM,EAAE,iBAAe,SA+BrD,CAAC"}
1
+ {"version":3,"file":"date.d.ts","sourceRoot":"","sources":["../../date.ts"],"names":[],"mappings":"AACA;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,KAAK,CAAC;AAExC,+EAA+E;AAC/E,eAAO,MAAM,cAAc,GAAI,MAAM,MAAM,EAAE,OAAO,MAAM,EAAE,KAAK,MAAM,YAC3B,CAAC;AAE7C,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,WAAW,CAAC;AAEnD;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,GAC3B,MAAM,IAAI,EACV,iBAAe,EACf,OAAM,cAAwB,WAwB/B,CAAC;AAEF,eAAO,MAAM,QAAQ,GAAI,MAAM,IAAI,EAAE,iBAAe,WAEnD,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,GAC5B,MAAM,MAAM,EACZ,OAAO,MAAM,EACb,KAAK,MAAM,EACX,aAAQ,EACR,eAAU,EACV,eAAU,EACV,iBAAe,WAWhB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,MAAM,GAAI,QAAQ,MAAM,EAAE,iBAAe,SA+BrD,CAAC"}
package/dist/esm/date.js CHANGED
@@ -1,5 +1,12 @@
1
1
  const DAY_TO_MS = 24 * 60 * 60 * 1000;
2
- const EXCEL_LEAP_BUG_SERIAL = 60;
2
+ /**
3
+ * Excel's 1900 date system counts a day that never happened: serial 60 is
4
+ * 1900-02-29 (Lotus 1-2-3 compatibility). 1900-01-01 is 1, 1900-02-28 is 59,
5
+ * 1900-03-01 is 61. Google Sheets keeps the same numbering.
6
+ */
7
+ export const EXCEL_LEAP_BUG_SERIAL = 60;
8
+ /** The calendar day Excel's serial 60 stands for, which no `Date` can hold. */
9
+ export const isExcelLeapDay = (year, month, day) => year === 1900 && month === 1 && day === 29;
3
10
  /**
4
11
  * Convert date to serial with explicit time zone behavior.
5
12
  * - local: interpret date components in local time (UI entry behavior).
@@ -23,6 +30,20 @@ export const toSerialWithMode = (date, use1904 = false, mode = "local") => {
23
30
  export const toSerial = (date, use1904 = false) => {
24
31
  return toSerialWithMode(date, use1904, "local");
25
32
  };
33
+ /**
34
+ * Serial for calendar parts the way a user typed them. Unlike
35
+ * `toSerial(new Date(y, m, d))`, this never goes through a `Date`, so the
36
+ * phantom 1900-02-29 stays serial 60 instead of rolling over to March 1
37
+ * (rowsncolumns/spreadsheet#1026). Every other date takes the same path as
38
+ * `toSerial` in "local" mode. `month` is 0-based like `Date`.
39
+ */
40
+ export const toSerialFromParts = (year, month, day, hour = 0, minute = 0, second = 0, use1904 = false) => {
41
+ const timeFraction = (hour * 3600 + minute * 60 + second) / (24 * 60 * 60);
42
+ if (!use1904 && isExcelLeapDay(year, month, day)) {
43
+ return EXCEL_LEAP_BUG_SERIAL + timeFraction;
44
+ }
45
+ return toSerialWithMode(new Date(year, month, day, hour, minute, second, 0), use1904, "local");
46
+ };
26
47
  /**
27
48
  * Convert serial to date
28
49
  * @param serial
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rowsncolumns/utils",
3
- "version": "9.5.3",
3
+ "version": "9.5.5",
4
4
  "author": "Vinay M",
5
5
  "license": "SEE LICENSE IN LICENSE.md",
6
6
  "main": "./dist/cjs/index.js",