@trebco/treb 27.7.6 → 27.11.1

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.
Files changed (55) hide show
  1. package/dist/treb-spreadsheet.mjs +14 -14
  2. package/dist/treb.d.ts +28 -26
  3. package/notes/conditional-fomratring.md +29 -0
  4. package/package.json +1 -1
  5. package/treb-base-types/src/area.ts +181 -0
  6. package/{treb-grid/src/util/dom_utilities.ts → treb-base-types/src/dom-utilities.ts} +29 -20
  7. package/treb-base-types/src/evaluate-options.ts +21 -0
  8. package/treb-base-types/src/gradient.ts +97 -0
  9. package/treb-base-types/src/import.ts +2 -1
  10. package/treb-base-types/src/index.ts +3 -0
  11. package/treb-base-types/src/theme.ts +3 -5
  12. package/treb-calculator/src/calculator.ts +190 -28
  13. package/treb-calculator/src/dag/calculation_leaf_vertex.ts +97 -0
  14. package/treb-calculator/src/dag/graph.ts +10 -22
  15. package/treb-calculator/src/dag/{leaf_vertex.ts → state_leaf_vertex.ts} +3 -3
  16. package/treb-calculator/src/descriptors.ts +10 -3
  17. package/treb-calculator/src/expression-calculator.ts +1 -1
  18. package/treb-calculator/src/function-library.ts +25 -22
  19. package/treb-calculator/src/functions/base-functions.ts +166 -5
  20. package/treb-calculator/src/index.ts +6 -6
  21. package/treb-calculator/src/notifier-types.ts +1 -1
  22. package/treb-calculator/src/utilities.ts +2 -2
  23. package/treb-charts/src/util.ts +2 -2
  24. package/treb-embed/src/custom-element/global.d.ts +3 -1
  25. package/treb-embed/src/custom-element/spreadsheet-constructor.ts +13 -19
  26. package/treb-embed/src/embedded-spreadsheet.ts +378 -132
  27. package/treb-embed/src/spinner.ts +3 -3
  28. package/treb-embed/style/layout.scss +1 -1
  29. package/treb-export/src/drawing2/chart2.ts +11 -2
  30. package/treb-export/src/export-worker/export-worker.ts +0 -13
  31. package/treb-export/src/export2.ts +197 -2
  32. package/treb-export/src/import2.ts +169 -4
  33. package/treb-export/src/workbook-style2.ts +59 -10
  34. package/treb-export/src/workbook2.ts +10 -1
  35. package/treb-grid/src/editors/autocomplete.ts +28 -24
  36. package/treb-grid/src/editors/editor.ts +3 -4
  37. package/treb-grid/src/editors/formula_bar.ts +1 -1
  38. package/treb-grid/src/index.ts +2 -1
  39. package/treb-grid/src/layout/base_layout.ts +34 -31
  40. package/treb-grid/src/layout/grid_layout.ts +17 -28
  41. package/treb-grid/src/render/selection-renderer.ts +2 -3
  42. package/treb-grid/src/render/svg_header_overlay.ts +4 -11
  43. package/treb-grid/src/render/svg_selection_block.ts +27 -34
  44. package/treb-grid/src/render/tile_renderer.ts +8 -6
  45. package/treb-grid/src/types/conditional_format.ts +168 -0
  46. package/treb-grid/src/types/grid.ts +37 -47
  47. package/treb-grid/src/types/grid_base.ts +188 -33
  48. package/treb-grid/src/types/scale-control.ts +2 -2
  49. package/treb-grid/src/types/sheet.ts +332 -28
  50. package/treb-grid/src/types/sheet_types.ts +4 -0
  51. package/treb-grid/src/types/tab_bar.ts +4 -8
  52. package/treb-utils/src/index.ts +0 -1
  53. package/treb-utils/src/resizable.ts +26 -27
  54. package/treb-utils/src/template.ts +0 -70
  55. /package/{README-shadow-DOM.md → notes/shadow-DOM.md} +0 -0
@@ -21,10 +21,10 @@
21
21
 
22
22
  import type { FunctionMap } from '../descriptors';
23
23
  import * as Utils from '../utilities';
24
- import { ReferenceError, NotImplError, NAError, ArgumentError, DivideByZeroError, ValueError } from '../function-error';
24
+ import { ReferenceError, NotImplError, NAError, ArgumentError, DivideByZeroError, ValueError, NameError } from '../function-error';
25
25
  import type { UnionValue,
26
26
  RenderFunctionResult, RenderFunctionOptions, Complex } from 'treb-base-types';
27
- import { Box, ValueType, GetValueType, ComplexOrReal } from 'treb-base-types';
27
+ import { Box, ValueType, GetValueType, ComplexOrReal, IsComplex } from 'treb-base-types';
28
28
  import { Sparkline } from './sparkline';
29
29
  import { LotusDate, UnlotusDate } from 'treb-format';
30
30
 
@@ -427,7 +427,7 @@ export const BaseFunctionLibrary: FunctionMap = {
427
427
  description: 'Counts cells that contain numbers',
428
428
  fn: (...args: unknown[]): UnionValue => {
429
429
  return Box(Utils.FlattenUnboxed(args).reduce((a: number, b: unknown) => {
430
- if (typeof b === 'number') return a + 1;
430
+ if (typeof b === 'number' || IsComplex(b)) return a + 1;
431
431
  return a;
432
432
  }, 0));
433
433
  },
@@ -456,7 +456,7 @@ export const BaseFunctionLibrary: FunctionMap = {
456
456
  },
457
457
 
458
458
  Not: {
459
- fn: (...args: unknown[]): UnionValue => {
459
+ fn: Utils.ApplyAsArray((...args: unknown[]): UnionValue => {
460
460
  if (args.length === 0) {
461
461
  return ArgumentError();
462
462
  }
@@ -464,7 +464,7 @@ export const BaseFunctionLibrary: FunctionMap = {
464
464
  return Box(!args[0]);
465
465
  }
466
466
  return Box(true);
467
- }
467
+ })
468
468
  },
469
469
 
470
470
  If: {
@@ -1126,6 +1126,167 @@ export const BaseFunctionLibrary: FunctionMap = {
1126
1126
  fn: (...args: unknown[]): UnionValue => {
1127
1127
  return { type: ValueType.object, value: args, key: 'sparkline-data' };
1128
1128
  },
1129
+ },
1130
+
1131
+ UniqueValues: {
1132
+ arguments: [
1133
+ { name: 'range', boxed: true },
1134
+ ],
1135
+ visibility: 'internal',
1136
+ fn: (area: UnionValue): UnionValue => {
1137
+
1138
+ if (area.type === ValueType.array) {
1139
+
1140
+ const cols = area.value.length;
1141
+ const rows = area.value[0]?.length;
1142
+
1143
+ // how is uniqueness defined in this context? (...)
1144
+
1145
+ const Normalize = (cell?: UnionValue): string|number|boolean => {
1146
+
1147
+ if (!cell) {
1148
+ return '';
1149
+ }
1150
+ else switch (cell.type) {
1151
+ case ValueType.string:
1152
+ case ValueType.number:
1153
+ case ValueType.boolean:
1154
+ return cell.value;
1155
+
1156
+ case ValueType.undefined:
1157
+ return '';
1158
+
1159
+ default:
1160
+ console.info("check", cell, cell.value)
1161
+ return cell.value?.toString() || '';
1162
+ }
1163
+
1164
+ };
1165
+
1166
+ const set: Set<number|string|boolean> = new Set();
1167
+ const duplicates: Set<number|string|boolean> = new Set();
1168
+
1169
+ for (const column of area.value) {
1170
+ for (const cell of column) {
1171
+ const normalized = Normalize(cell);
1172
+ if (set.has(normalized)) {
1173
+ duplicates.add(normalized);
1174
+ }
1175
+ else {
1176
+ set.add(normalized);
1177
+ }
1178
+ }
1179
+ }
1180
+
1181
+ const result: UnionValue[][] = [];
1182
+ for (const column of area.value) {
1183
+ const column_result: UnionValue[] = [];
1184
+ for (const cell of column) {
1185
+ const value = Normalize(cell);
1186
+ column_result.push({
1187
+ type: ValueType.boolean,
1188
+ value: !duplicates.has(value),
1189
+ });
1190
+ }
1191
+ result.push(column_result);
1192
+ }
1193
+
1194
+ return {
1195
+ type: ValueType.array,
1196
+ value: result,
1197
+ };
1198
+
1199
+ }
1200
+
1201
+ // if it's not an array, by definition it's unique
1202
+
1203
+ return {
1204
+ type: ValueType.boolean,
1205
+ value: true,
1206
+ }
1207
+
1208
+ },
1209
+ },
1210
+
1211
+ Gradient: {
1212
+ arguments: [
1213
+ { name: 'range', boxed: true },
1214
+ { name: 'min', },
1215
+ { name: 'max', },
1216
+ ],
1217
+ visibility: 'internal',
1218
+ fn: (area: UnionValue, static_min?: number, static_max?: number): UnionValue => {
1219
+
1220
+ const tmp = Utils.FlattenBoxed([area]);
1221
+
1222
+ let sum = 0;
1223
+ let count = 0;
1224
+ let min = 0;
1225
+ let max = 0;
1226
+
1227
+ for (const ref of tmp as UnionValue[]) {
1228
+ if (ref.type === ValueType.error) {
1229
+ return ref;
1230
+ }
1231
+ if (ref.type === ValueType.number) {
1232
+ if (count === 0) {
1233
+ min = ref.value;
1234
+ max = ref.value;
1235
+ }
1236
+ else {
1237
+ min = Math.min(min, ref.value);
1238
+ max = Math.max(max, ref.value);
1239
+ }
1240
+ count++;
1241
+ }
1242
+ }
1243
+
1244
+ if (typeof static_max === 'number') {
1245
+ max = static_max;
1246
+ }
1247
+ if (typeof static_min === 'number') {
1248
+ min = static_min;
1249
+ }
1250
+
1251
+ let range = max - min;
1252
+
1253
+ let rows = 1;
1254
+ let columns = 1;
1255
+
1256
+ if (area.type === ValueType.array) {
1257
+
1258
+ rows = area.value.length;
1259
+ columns = area.value[0]?.length || 0;
1260
+
1261
+ const result: UnionValue[][] = [];
1262
+ for (let r = 0; r < rows; r++) {
1263
+ const row: UnionValue[] = [];
1264
+ for (let c = 0; c < columns; c++) {
1265
+ const src = area.value[r][c];
1266
+ if (src.type === ValueType.number) {
1267
+ let calc = 0;
1268
+ if (range > 0) {
1269
+ calc = (src.value - min) / range;
1270
+ }
1271
+ row.push({ type: ValueType.number, value: calc });
1272
+ }
1273
+ else {
1274
+ row.push({ type: ValueType.undefined });
1275
+ }
1276
+
1277
+ }
1278
+ result.push(row);
1279
+ }
1280
+
1281
+ return { type: ValueType.array, value: result };
1282
+
1283
+
1284
+ }
1285
+ else {
1286
+ return ArgumentError();
1287
+ }
1288
+
1289
+ },
1129
1290
  }
1130
1291
 
1131
1292
  };
@@ -19,9 +19,9 @@
19
19
  *
20
20
  */
21
21
 
22
- export * from './calculator';
23
- // export * from './pack-results';
24
-
25
- // for annotations that have dependencies
26
-
27
- export {LeafVertex} from './dag/leaf_vertex';
22
+ export * from './calculator';
23
+ // export * from './pack-results';
24
+
25
+ // for annotations that have dependencies
26
+
27
+ export type { LeafVertex } from './dag/graph';
@@ -19,7 +19,7 @@
19
19
  *
20
20
  */
21
21
 
22
- import type { LeafVertex } from './dag/leaf_vertex';
22
+ import type { LeafVertex } from './dag/graph';
23
23
  import type { Area } from 'treb-base-types';
24
24
 
25
25
  export interface NotifierType {
@@ -180,10 +180,10 @@ export const UndefinedToEmptyString = (args: any[]): any[] => {
180
180
  export const ApplyArrayFunc = (base: (...args: any[]) => any) => {
181
181
  return (a: any) => {
182
182
  if (Array.isArray(a)) {
183
- const tmp = [];
183
+ const tmp: any[] = [];
184
184
  const rows = a[0].length;
185
185
  for (let c = 0; c < a.length; c++) {
186
- const col = [];
186
+ const col: any[] = [];
187
187
  for (let r = 0; r < rows; r++) col[r] = base(a[c][r]);
188
188
  tmp.push(col);
189
189
  }
@@ -38,7 +38,7 @@ export class Util {
38
38
  * given a passed range, find the best scale range. count is just a
39
39
  * suggestion -- we try to get as close as possible.
40
40
  */
41
- public static Scale(min: number, max: number, count = 6.5): RangeScale {
41
+ public static Scale(min: number, max: number, count = 6.5, limit_count?: boolean, discrete?: boolean): RangeScale {
42
42
 
43
43
  /*
44
44
  const range = max - min;
@@ -71,7 +71,7 @@ export class Util {
71
71
 
72
72
  return { scale, step, count, min, max };
73
73
  */
74
- return Scale(min, max, count);
74
+ return Scale(min, max, count, limit_count, discrete);
75
75
 
76
76
  }
77
77
 
@@ -5,7 +5,9 @@
5
5
  declare global {
6
6
  interface HTMLElementTagNameMap {
7
7
  'treb-spreadsheet': HTMLElement & {
8
- sheet: EmbeddedSpreadsheet|undefined;
8
+ instance: {
9
+ sheet: EmbeddedSpreadsheet | undefined;
10
+ } | undefined;
9
11
  };
10
12
  }
11
13
  }
@@ -19,8 +19,11 @@ interface ElementOptions {
19
19
  classes: string|string[];
20
20
  }
21
21
 
22
- const Element = <T extends HTMLElement>(tag: string, parent?: HTMLElement|DocumentFragment, options: Partial<ElementOptions> = {}, attrs: Record<string, string> = {}): T => {
23
- const element = document.createElement(tag) as T;
22
+ /**
23
+ * FIXME: unify this with DOMUtils
24
+ */
25
+ const Element = <K extends keyof HTMLElementTagNameMap>(tag: K, parent?: HTMLElement|DocumentFragment, options: Partial<ElementOptions> = {}, attrs: Record<string, string> = {}): HTMLElementTagNameMap[K] => {
26
+ const element = document.createElement(tag);
24
27
  if (options.classes) {
25
28
 
26
29
  // you can't use an array destructure in a ternary expression? TIL
@@ -105,21 +108,12 @@ export class SpreadsheetConstructor {
105
108
 
106
109
  const style_node = document.head.querySelector('style[treb-stylesheet]');
107
110
  if (!style_node) {
108
- const style = document.createElement('style');
111
+ const style = Element('style');
109
112
  style.setAttribute('treb-stylesheet', '');
110
113
  style.textContent = css;
111
114
  document.head.prepend(style);
112
115
  }
113
116
 
114
- /*
115
- if (!SpreadsheetConstructor.stylesheets_attached) {
116
- const style = document.createElement('style');
117
- style.textContent = css;
118
- document.head.prepend(style);
119
- SpreadsheetConstructor.stylesheets_attached = true;
120
- }
121
- */
122
-
123
117
  }
124
118
 
125
119
  }
@@ -509,9 +503,9 @@ export class SpreadsheetConstructor {
509
503
 
510
504
  const resize_parent = root.querySelector('.treb-main') as HTMLElement; // was document.body
511
505
 
512
- resizer = Element<HTMLDivElement>('div', resize_parent, { classes: 'treb-resize-rect' });
506
+ resizer = Element('div', resize_parent, { classes: 'treb-resize-rect' });
513
507
 
514
- mask = Element<HTMLDivElement>('div', resize_parent, {
508
+ mask = Element('div', resize_parent, {
515
509
  classes: 'treb-resize-mask',
516
510
  style: 'cursor: nw-resize;',
517
511
  });
@@ -724,7 +718,7 @@ export class SpreadsheetConstructor {
724
718
  }
725
719
 
726
720
  }
727
- Element<HTMLButtonElement>('button', fragment, { style, title, data: { command: 'set-color', color: JSON.stringify(entry.color) } });
721
+ Element('button', fragment, { style, title, data: { command: 'set-color', color: JSON.stringify(entry.color) } });
728
722
  }
729
723
  }
730
724
 
@@ -733,7 +727,7 @@ export class SpreadsheetConstructor {
733
727
  this.swatch_lists.theme?.replaceChildren(fragment);
734
728
 
735
729
  fragment = document.createDocumentFragment();
736
- Element<HTMLButtonElement>('button', fragment, {
730
+ Element('button', fragment, {
737
731
  classes: 'treb-default-color',
738
732
  title: 'Default color',
739
733
  data: { command: 'set-color', color: JSON.stringify({}) },
@@ -748,7 +742,7 @@ export class SpreadsheetConstructor {
748
742
 
749
743
  for (const text of [...colors, ...additional_colors]) {
750
744
  const style = `background: ${text.toLowerCase()};`;
751
- Element<HTMLButtonElement>('button', fragment, { style, title: text, data: { command: 'set-color', color: JSON.stringify({text: text.toLowerCase()})}});
745
+ Element('button', fragment, { style, title: text, data: { command: 'set-color', color: JSON.stringify({text: text.toLowerCase()})}});
752
746
  }
753
747
 
754
748
  this.swatch_lists.other?.replaceChildren(fragment);
@@ -777,7 +771,7 @@ export class SpreadsheetConstructor {
777
771
  }
778
772
 
779
773
  const Button = (format: string) => {
780
- return Element<HTMLButtonElement>('button', undefined, {
774
+ return Element('button', undefined, {
781
775
  text: format, data: { format, command: 'number-format' },
782
776
  });
783
777
  };
@@ -785,7 +779,7 @@ export class SpreadsheetConstructor {
785
779
  const fragment = document.createDocumentFragment();
786
780
  fragment.append(...number_formats.map(format => Button(format)));
787
781
 
788
- fragment.append(Element<HTMLDivElement>('div', undefined, {}, {separator: ''}));
782
+ fragment.append(Element('div', undefined, {}, {separator: ''}));
789
783
  fragment.append(...date_formats.map(format => Button(format)));
790
784
 
791
785
  format_menu.textContent = '';