@trebco/treb 23.6.5 → 25.0.0-rc1

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 (217) hide show
  1. package/.eslintignore +8 -0
  2. package/.eslintrc.js +164 -0
  3. package/README-shadow-DOM.md +88 -0
  4. package/README.md +37 -130
  5. package/api-config.json +29 -0
  6. package/api-generator/api-generator-types.ts +82 -0
  7. package/api-generator/api-generator.ts +1172 -0
  8. package/api-generator/package.json +3 -0
  9. package/build/treb-spreadsheet.mjs +14 -0
  10. package/{treb.d.ts → build/treb.d.ts} +285 -269
  11. package/esbuild-custom-element.mjs +336 -0
  12. package/esbuild.js +305 -0
  13. package/package.json +43 -14
  14. package/treb-base-types/package.json +5 -0
  15. package/treb-base-types/src/api_types.ts +36 -0
  16. package/treb-base-types/src/area.ts +583 -0
  17. package/treb-base-types/src/basic_types.ts +45 -0
  18. package/treb-base-types/src/cell.ts +612 -0
  19. package/treb-base-types/src/cells.ts +1066 -0
  20. package/treb-base-types/src/color.ts +124 -0
  21. package/treb-base-types/src/import.ts +71 -0
  22. package/treb-base-types/src/index-standalone.ts +29 -0
  23. package/treb-base-types/src/index.ts +42 -0
  24. package/treb-base-types/src/layout.ts +47 -0
  25. package/treb-base-types/src/localization.ts +187 -0
  26. package/treb-base-types/src/rectangle.ts +145 -0
  27. package/treb-base-types/src/render_text.ts +72 -0
  28. package/treb-base-types/src/style.ts +545 -0
  29. package/treb-base-types/src/table.ts +109 -0
  30. package/treb-base-types/src/text_part.ts +54 -0
  31. package/treb-base-types/src/theme.ts +608 -0
  32. package/treb-base-types/src/union.ts +152 -0
  33. package/treb-base-types/src/value-type.ts +164 -0
  34. package/treb-base-types/style/resizable.css +59 -0
  35. package/treb-calculator/modern.tsconfig.json +11 -0
  36. package/treb-calculator/package.json +5 -0
  37. package/treb-calculator/src/calculator.ts +2546 -0
  38. package/treb-calculator/src/complex-math.ts +558 -0
  39. package/treb-calculator/src/dag/array-vertex.ts +198 -0
  40. package/treb-calculator/src/dag/graph.ts +951 -0
  41. package/treb-calculator/src/dag/leaf_vertex.ts +118 -0
  42. package/treb-calculator/src/dag/spreadsheet_vertex.ts +327 -0
  43. package/treb-calculator/src/dag/spreadsheet_vertex_base.ts +44 -0
  44. package/treb-calculator/src/dag/vertex.ts +352 -0
  45. package/treb-calculator/src/descriptors.ts +162 -0
  46. package/treb-calculator/src/expression-calculator.ts +1069 -0
  47. package/treb-calculator/src/function-error.ts +103 -0
  48. package/treb-calculator/src/function-library.ts +103 -0
  49. package/treb-calculator/src/functions/base-functions.ts +1214 -0
  50. package/treb-calculator/src/functions/checkbox.ts +164 -0
  51. package/treb-calculator/src/functions/complex-functions.ts +253 -0
  52. package/treb-calculator/src/functions/finance-functions.ts +399 -0
  53. package/treb-calculator/src/functions/information-functions.ts +102 -0
  54. package/treb-calculator/src/functions/matrix-functions.ts +182 -0
  55. package/treb-calculator/src/functions/sparkline.ts +335 -0
  56. package/treb-calculator/src/functions/statistics-functions.ts +350 -0
  57. package/treb-calculator/src/functions/text-functions.ts +298 -0
  58. package/treb-calculator/src/index.ts +27 -0
  59. package/treb-calculator/src/notifier-types.ts +59 -0
  60. package/treb-calculator/src/primitives.ts +428 -0
  61. package/treb-calculator/src/utilities.ts +305 -0
  62. package/treb-charts/package.json +5 -0
  63. package/treb-charts/src/chart-functions.ts +156 -0
  64. package/treb-charts/src/chart-types.ts +230 -0
  65. package/treb-charts/src/chart.ts +1288 -0
  66. package/treb-charts/src/index.ts +24 -0
  67. package/treb-charts/src/main.ts +37 -0
  68. package/treb-charts/src/rectangle.ts +52 -0
  69. package/treb-charts/src/renderer.ts +1841 -0
  70. package/treb-charts/src/util.ts +122 -0
  71. package/treb-charts/style/charts.scss +221 -0
  72. package/treb-charts/style/old-charts.scss +250 -0
  73. package/treb-embed/markup/layout.html +137 -0
  74. package/treb-embed/markup/toolbar.html +175 -0
  75. package/treb-embed/modern.tsconfig.json +25 -0
  76. package/treb-embed/src/custom-element/content-types.d.ts +18 -0
  77. package/treb-embed/src/custom-element/global.d.ts +11 -0
  78. package/treb-embed/src/custom-element/spreadsheet-constructor.ts +1227 -0
  79. package/treb-embed/src/custom-element/treb-global.ts +44 -0
  80. package/treb-embed/src/custom-element/treb-spreadsheet-element.ts +52 -0
  81. package/treb-embed/src/embedded-spreadsheet.ts +5362 -0
  82. package/treb-embed/src/index.ts +16 -0
  83. package/treb-embed/src/language-model.ts +41 -0
  84. package/treb-embed/src/options.ts +320 -0
  85. package/treb-embed/src/progress-dialog.ts +228 -0
  86. package/treb-embed/src/selection-state.ts +16 -0
  87. package/treb-embed/src/spinner.ts +42 -0
  88. package/treb-embed/src/toolbar-message.ts +96 -0
  89. package/treb-embed/src/types.ts +167 -0
  90. package/treb-embed/style/autocomplete.scss +103 -0
  91. package/treb-embed/style/dark-theme.scss +114 -0
  92. package/treb-embed/style/defaults.scss +36 -0
  93. package/treb-embed/style/dialog.scss +181 -0
  94. package/treb-embed/style/dropdown-select.scss +101 -0
  95. package/treb-embed/style/formula-bar.scss +193 -0
  96. package/treb-embed/style/grid.scss +374 -0
  97. package/treb-embed/style/layout.scss +424 -0
  98. package/treb-embed/style/mouse-mask.scss +67 -0
  99. package/treb-embed/style/note.scss +92 -0
  100. package/treb-embed/style/overlay-editor.scss +102 -0
  101. package/treb-embed/style/spinner.scss +92 -0
  102. package/treb-embed/style/tab-bar.scss +228 -0
  103. package/treb-embed/style/table.scss +80 -0
  104. package/treb-embed/style/theme-defaults.scss +444 -0
  105. package/treb-embed/style/toolbar.scss +416 -0
  106. package/treb-embed/style/tooltip.scss +68 -0
  107. package/treb-embed/style/treb-icons.scss +130 -0
  108. package/treb-embed/style/treb-spreadsheet-element.scss +20 -0
  109. package/treb-embed/style/z-index.scss +43 -0
  110. package/treb-export/docs/charts.md +68 -0
  111. package/treb-export/modern.tsconfig.json +19 -0
  112. package/treb-export/package.json +4 -0
  113. package/treb-export/src/address-type.ts +77 -0
  114. package/treb-export/src/base-template.ts +22 -0
  115. package/treb-export/src/column-width.ts +85 -0
  116. package/treb-export/src/drawing2/chart-template-components2.ts +389 -0
  117. package/treb-export/src/drawing2/chart2.ts +282 -0
  118. package/treb-export/src/drawing2/column-chart-template2.ts +521 -0
  119. package/treb-export/src/drawing2/donut-chart-template2.ts +296 -0
  120. package/treb-export/src/drawing2/drawing2.ts +355 -0
  121. package/treb-export/src/drawing2/embedded-image.ts +71 -0
  122. package/treb-export/src/drawing2/scatter-chart-template2.ts +555 -0
  123. package/treb-export/src/export-worker/export-worker.ts +99 -0
  124. package/treb-export/src/export-worker/index-modern.ts +22 -0
  125. package/treb-export/src/export2.ts +2204 -0
  126. package/treb-export/src/import2.ts +882 -0
  127. package/treb-export/src/relationship.ts +36 -0
  128. package/treb-export/src/shared-strings2.ts +128 -0
  129. package/treb-export/src/template-2.ts +22 -0
  130. package/treb-export/src/unescape_xml.ts +47 -0
  131. package/treb-export/src/workbook-sheet2.ts +182 -0
  132. package/treb-export/src/workbook-style2.ts +1285 -0
  133. package/treb-export/src/workbook-theme2.ts +88 -0
  134. package/treb-export/src/workbook2.ts +491 -0
  135. package/treb-export/src/xml-utils.ts +201 -0
  136. package/treb-export/template/base/[Content_Types].xml +2 -0
  137. package/treb-export/template/base/_rels/.rels +2 -0
  138. package/treb-export/template/base/docProps/app.xml +2 -0
  139. package/treb-export/template/base/docProps/core.xml +12 -0
  140. package/treb-export/template/base/xl/_rels/workbook.xml.rels +2 -0
  141. package/treb-export/template/base/xl/sharedStrings.xml +2 -0
  142. package/treb-export/template/base/xl/styles.xml +2 -0
  143. package/treb-export/template/base/xl/theme/theme1.xml +2 -0
  144. package/treb-export/template/base/xl/workbook.xml +2 -0
  145. package/treb-export/template/base/xl/worksheets/sheet1.xml +2 -0
  146. package/treb-export/template/base.xlsx +0 -0
  147. package/treb-format/package.json +8 -0
  148. package/treb-format/src/format.test.ts +213 -0
  149. package/treb-format/src/format.ts +942 -0
  150. package/treb-format/src/format_cache.ts +199 -0
  151. package/treb-format/src/format_parser.ts +723 -0
  152. package/treb-format/src/index.ts +25 -0
  153. package/treb-format/src/number_format_section.ts +100 -0
  154. package/treb-format/src/value_parser.ts +337 -0
  155. package/treb-grid/package.json +5 -0
  156. package/treb-grid/src/editors/autocomplete.ts +394 -0
  157. package/treb-grid/src/editors/autocomplete_matcher.ts +260 -0
  158. package/treb-grid/src/editors/formula_bar.ts +473 -0
  159. package/treb-grid/src/editors/formula_editor_base.ts +910 -0
  160. package/treb-grid/src/editors/overlay_editor.ts +511 -0
  161. package/treb-grid/src/index.ts +37 -0
  162. package/treb-grid/src/layout/base_layout.ts +2618 -0
  163. package/treb-grid/src/layout/grid_layout.ts +299 -0
  164. package/treb-grid/src/layout/rectangle_cache.ts +86 -0
  165. package/treb-grid/src/render/selection-renderer.ts +414 -0
  166. package/treb-grid/src/render/svg_header_overlay.ts +93 -0
  167. package/treb-grid/src/render/svg_selection_block.ts +187 -0
  168. package/treb-grid/src/render/tile_renderer.ts +2122 -0
  169. package/treb-grid/src/types/annotation.ts +216 -0
  170. package/treb-grid/src/types/border_constants.ts +34 -0
  171. package/treb-grid/src/types/clipboard_data.ts +31 -0
  172. package/treb-grid/src/types/data_model.ts +334 -0
  173. package/treb-grid/src/types/drag_mask.ts +81 -0
  174. package/treb-grid/src/types/grid.ts +7743 -0
  175. package/treb-grid/src/types/grid_base.ts +3644 -0
  176. package/treb-grid/src/types/grid_command.ts +470 -0
  177. package/treb-grid/src/types/grid_events.ts +124 -0
  178. package/treb-grid/src/types/grid_options.ts +97 -0
  179. package/treb-grid/src/types/grid_selection.ts +60 -0
  180. package/treb-grid/src/types/named_range.ts +369 -0
  181. package/treb-grid/src/types/scale-control.ts +202 -0
  182. package/treb-grid/src/types/serialize_options.ts +72 -0
  183. package/treb-grid/src/types/set_range_options.ts +52 -0
  184. package/treb-grid/src/types/sheet.ts +3099 -0
  185. package/treb-grid/src/types/sheet_types.ts +95 -0
  186. package/treb-grid/src/types/tab_bar.ts +464 -0
  187. package/treb-grid/src/types/tile.ts +59 -0
  188. package/treb-grid/src/types/update_flags.ts +75 -0
  189. package/treb-grid/src/util/dom_utilities.ts +44 -0
  190. package/treb-grid/src/util/fontmetrics2.ts +179 -0
  191. package/treb-grid/src/util/ua.ts +104 -0
  192. package/treb-logo.svg +18 -0
  193. package/treb-parser/package.json +5 -0
  194. package/treb-parser/src/csv-parser.ts +122 -0
  195. package/treb-parser/src/index.ts +25 -0
  196. package/treb-parser/src/md-parser.ts +526 -0
  197. package/treb-parser/src/parser-types.ts +397 -0
  198. package/treb-parser/src/parser.test.ts +298 -0
  199. package/treb-parser/src/parser.ts +2673 -0
  200. package/treb-utils/package.json +5 -0
  201. package/treb-utils/src/dispatch.ts +57 -0
  202. package/treb-utils/src/event_source.ts +147 -0
  203. package/treb-utils/src/ievent_source.ts +33 -0
  204. package/treb-utils/src/index.ts +31 -0
  205. package/treb-utils/src/measurement.ts +174 -0
  206. package/treb-utils/src/resizable.ts +160 -0
  207. package/treb-utils/src/scale.ts +137 -0
  208. package/treb-utils/src/serialize_html.ts +124 -0
  209. package/treb-utils/src/template.ts +70 -0
  210. package/treb-utils/src/validate_uri.ts +61 -0
  211. package/tsconfig.json +10 -0
  212. package/tsproject.json +30 -0
  213. package/util/license-plugin-esbuild.js +86 -0
  214. package/util/list-css-vars.sh +46 -0
  215. package/README-esm.md +0 -37
  216. package/treb-bundle.css +0 -2
  217. package/treb-bundle.mjs +0 -15
@@ -0,0 +1,95 @@
1
+ /*
2
+ * This file is part of TREB.
3
+ *
4
+ * TREB is free software: you can redistribute it and/or modify it under the
5
+ * terms of the GNU General Public License as published by the Free Software
6
+ * Foundation, either version 3 of the License, or (at your option) any
7
+ * later version.
8
+ *
9
+ * TREB is distributed in the hope that it will be useful, but WITHOUT ANY
10
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12
+ * details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License along
15
+ * with TREB. If not, see <https://www.gnu.org/licenses/>.
16
+ *
17
+ * Copyright 2022-2023 trebco, llc.
18
+ * info@treb.app
19
+ *
20
+ */
21
+
22
+ import type { IArea, SerializedCellData, Style } from 'treb-base-types';
23
+ import type { Annotation } from './annotation';
24
+ import type { GridSelection } from './grid_selection';
25
+
26
+ export interface UpdateHints {
27
+ data?: boolean;
28
+ layout?: boolean;
29
+ style?: boolean;
30
+ annotations?: boolean;
31
+ freeze?: boolean;
32
+ names?: boolean;
33
+ }
34
+
35
+ export interface FreezePane {
36
+ rows: number;
37
+ columns: number;
38
+ }
39
+
40
+ export interface ScrollOffset {
41
+ x: number;
42
+ y: number;
43
+ }
44
+
45
+ export interface SerializedSheet {
46
+
47
+ // version: string;
48
+ // data: any; // FIXME
49
+ data: SerializedCellData;
50
+
51
+ sheet_style: Style.Properties;
52
+ rows: number;
53
+ columns: number;
54
+ cell_styles: Array<{row: number; column: number; ref: number, rows?: number}>;
55
+
56
+ /** @deprecated */
57
+ cell_style_refs?: Style.Properties[]; // old
58
+ styles?: Style.Properties[]; // new
59
+
60
+ // row_style: Style.Properties[];
61
+ // column_style: Style.Properties[];
62
+ // row_style: Array<Style.Properties|number>;
63
+ // column_style: Array<Style.Properties|number>;
64
+ row_style: Record<number, Style.Properties|number>;
65
+ column_style: Record<number, Style.Properties|number>;
66
+
67
+ row_pattern?: Style.Properties[];
68
+
69
+ default_row_height?: number;
70
+ default_column_width?: number;
71
+
72
+ row_height?: {[index: number]: number};
73
+ column_width?: {[index: number]: number};
74
+ named_ranges?: {[index: string]: IArea};
75
+ freeze?: FreezePane;
76
+
77
+ id?: number;
78
+ name?: string;
79
+
80
+ selection: GridSelection;
81
+ annotations?: Partial<Annotation>[];
82
+ scroll?: ScrollOffset;
83
+
84
+ visible?: boolean;
85
+
86
+ /** testing */
87
+ background_image?: string;
88
+
89
+ }
90
+
91
+ /**
92
+ * support for legacy sheet data
93
+ * (I think we can drop)
94
+ */
95
+ export type LegacySerializedSheet = SerializedSheet & { primary_selection?: GridSelection }
@@ -0,0 +1,464 @@
1
+ /*
2
+ * This file is part of TREB.
3
+ *
4
+ * TREB is free software: you can redistribute it and/or modify it under the
5
+ * terms of the GNU General Public License as published by the Free Software
6
+ * Foundation, either version 3 of the License, or (at your option) any
7
+ * later version.
8
+ *
9
+ * TREB is distributed in the hope that it will be useful, but WITHOUT ANY
10
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12
+ * details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License along
15
+ * with TREB. If not, see <https://www.gnu.org/licenses/>.
16
+ *
17
+ * Copyright 2022-2023 trebco, llc.
18
+ * info@treb.app
19
+ *
20
+ */
21
+
22
+ import type { DataModel, ViewModel } from './data_model';
23
+ import { EventSource } from 'treb-utils';
24
+ import type { Sheet } from './sheet';
25
+ import type { BaseLayout } from '../layout/base_layout';
26
+ import { MouseDrag } from './drag_mask';
27
+ import type { GridOptions } from './grid_options';
28
+ import { ScaleEvent, ScaleControl } from './scale-control';
29
+
30
+ export interface ActivateSheetEvent {
31
+ type: 'activate-sheet';
32
+ sheet: Sheet;
33
+ }
34
+
35
+ export interface RenameSheetEvent {
36
+ type: 'rename-sheet';
37
+ sheet: Sheet;
38
+ name: string;
39
+ }
40
+
41
+ export interface ReorderSheetEvent {
42
+ type: 'reorder-sheet';
43
+ index: number;
44
+ move_before: number;
45
+ }
46
+
47
+ export interface AddSheetEvent {
48
+ type: 'add-sheet';
49
+ }
50
+
51
+ export interface DeleteSheetEvent {
52
+ type: 'delete-sheet';
53
+ }
54
+
55
+ export interface CancelEvent {
56
+ type: 'cancel';
57
+ }
58
+
59
+ export type TabEvent
60
+ = CancelEvent
61
+ | ScaleEvent
62
+ | AddSheetEvent
63
+ | RenameSheetEvent
64
+ | DeleteSheetEvent
65
+ | ReorderSheetEvent
66
+ | ActivateSheetEvent
67
+ ;
68
+
69
+ export interface StatsEntry {
70
+ label: string;
71
+ value: string;
72
+ }
73
+
74
+ /**
75
+ * tabs for multiple sheets. at the bottom, atm (FIXME: options?)
76
+ *
77
+ * rename tabs (sheets) by double-clicking. this triggers a global
78
+ * rename over all cells and annotations.
79
+ *
80
+ * reorder tabs by dragging. reorders the array, but order is not
81
+ * material to any other module, so it's basically just housekeeping.
82
+ *
83
+ * add a new tab with a special (+) tab (last).
84
+ *
85
+ * FIXME: delete tabs... add an (x) to each tab? don't really want to
86
+ * do that. right-click is out. ??? [A: toolbar menu]
87
+ *
88
+ */
89
+ export class TabBar extends EventSource<TabEvent> {
90
+
91
+ // private container?: HTMLElement;
92
+ private tab_container?: HTMLElement;
93
+ private scale_control?: ScaleControl;
94
+ private stats_panel?: HTMLDivElement;
95
+
96
+ private dragging = false;
97
+
98
+ private double_click_data: {
99
+ index?: number;
100
+ timeout?: number;
101
+ } = {};
102
+
103
+ // tslint:disable-next-line: variable-name
104
+ private _visible = false;
105
+
106
+ public get visible(): boolean {
107
+ return this._visible;
108
+ }
109
+
110
+ public set stats_data(value: StatsEntry[]) {
111
+ if (this.stats_panel) {
112
+ this.stats_panel.innerText = ''; // clear
113
+ for (const entry of value) {
114
+
115
+ const label = document.createElement('span');
116
+ label.classList.add('treb-stats-label');
117
+ label.textContent = entry.label;
118
+ this.stats_panel.appendChild(label);
119
+
120
+ const figure = document.createElement('span');
121
+ figure.classList.add('treb-stats-value');
122
+ figure.textContent = entry.value;
123
+ this.stats_panel.appendChild(figure);
124
+ }
125
+ }
126
+ }
127
+
128
+ private container: HTMLElement;
129
+
130
+ constructor(
131
+ private layout: BaseLayout,
132
+ private model: DataModel,
133
+ private view: ViewModel,
134
+ private options: GridOptions,
135
+ // private container: HTMLElement,
136
+ view_node: HTMLElement,
137
+ ) {
138
+
139
+ super();
140
+
141
+ this.container = view_node.querySelector('.treb-spreadsheet-footer') as HTMLElement;
142
+ if (!this.container) {
143
+ throw new Error('missing container for tab bar');
144
+ }
145
+
146
+ // if we're here, we have a tab bar. show unless we're on auto
147
+ if (options.tab_bar !== 'auto') {
148
+ this.container.removeAttribute('hidden');
149
+ }
150
+
151
+ this.tab_container = this.container.querySelector('.treb-spreadsheet-tabs') as HTMLDivElement;
152
+
153
+ this.container.addEventListener('click', event => {
154
+ const command = (event.target as HTMLElement)?.dataset.command;
155
+ if (command) {
156
+ event.stopPropagation();
157
+ event.preventDefault();
158
+ switch (command) {
159
+ case 'add-tab':
160
+ this.Publish({ type: 'add-sheet' });
161
+ break;
162
+
163
+ case 'delete-tab':
164
+ this.Publish({ type: 'delete-sheet' });
165
+ break;
166
+
167
+ default:
168
+ console.info('unhandled command', command);
169
+ }
170
+ }
171
+ });
172
+
173
+ if (this.options.stats) {
174
+ this.stats_panel = this.container.querySelector('.treb-stats-panel') as HTMLDivElement;
175
+ }
176
+
177
+ if (this.options.scale_control) {
178
+ const div = this.container.querySelector('.treb-scale-control') as HTMLDivElement;
179
+ this.scale_control = new ScaleControl(div);
180
+ this.scale_control.Subscribe((event: ScaleEvent) => {
181
+ this.Publish(event);
182
+ });
183
+ this.UpdateScale(this.options.initial_scale || 1); // so we only have to write the scaling routine once
184
+ }
185
+
186
+ }
187
+
188
+ public IsDoubleClick(index: number, timeout = 300): boolean {
189
+
190
+ if (this.double_click_data.index === index ) {
191
+ clearTimeout(this.double_click_data.timeout);
192
+ this.double_click_data.index = undefined;
193
+ this.double_click_data.timeout = undefined;
194
+ return true;
195
+ }
196
+
197
+ if (this.double_click_data.timeout) {
198
+ clearTimeout(this.double_click_data.timeout);
199
+ }
200
+ this.double_click_data.index = index;
201
+ this.double_click_data.timeout = window.setTimeout(() => {
202
+ this.double_click_data.index = undefined;
203
+ this.double_click_data.timeout = undefined;
204
+ }, timeout);
205
+
206
+ return false;
207
+
208
+ }
209
+
210
+ public Hide(): void {
211
+ this.Show(false);
212
+ }
213
+
214
+ public Show(show = true): void {
215
+ if (!this.container) { return; }
216
+
217
+ this._visible = show;
218
+
219
+ if (show) {
220
+ this.container.removeAttribute('hidden');
221
+ }
222
+ else {
223
+ this.container.setAttribute('hidden', '');
224
+ }
225
+
226
+ }
227
+
228
+ public SetActive(tab: HTMLElement, active: boolean): void {
229
+ if (active) {
230
+ // tab.classList.add('treb-selected');
231
+ tab.setAttribute('selected', '');
232
+ }
233
+ else {
234
+ // tab.classList.remove('treb-selected');
235
+ tab.removeAttribute('selected');
236
+ }
237
+ }
238
+
239
+ /** change scale if we have a scale label */
240
+ public UpdateScale(scale: number): void {
241
+ this.scale_control?.UpdateScale(scale * 100);
242
+ }
243
+
244
+ public DoubleClickTab(event: MouseEvent, tab: HTMLElement, sheet: Sheet) {
245
+
246
+ tab.contentEditable = 'true';
247
+
248
+ // OK for shadow, seems to work as expected in all browsers
249
+ const selection = window.getSelection(); // OK for shadow
250
+
251
+ if (selection) {
252
+ selection.removeAllRanges();
253
+ const range = document.createRange();
254
+ range.selectNodeContents(tab);
255
+ selection.addRange(range);
256
+ }
257
+
258
+ tab.addEventListener('keydown', (inner_event: KeyboardEvent) => {
259
+ switch (inner_event.key) {
260
+ case 'Enter':
261
+ // const name = tab.innerText.trim();
262
+ this.Publish({
263
+ type: 'rename-sheet',
264
+ name: tab.innerText.trim(),
265
+ sheet,
266
+ });
267
+ break;
268
+
269
+ case 'Escape':
270
+ tab.innerText = sheet.name;
271
+ this.Publish({ type: 'cancel' });
272
+ this.Update();
273
+ break;
274
+
275
+ default:
276
+ return;
277
+ }
278
+ inner_event.stopPropagation();
279
+ inner_event.preventDefault();
280
+ });
281
+
282
+ tab.addEventListener('focusout', () => {
283
+ const name = tab.innerText.trim();
284
+ if (name !== sheet.name) {
285
+ this.Publish({ type: 'rename-sheet', name, sheet });
286
+ }
287
+ else {
288
+ this.Update();
289
+ }
290
+ });
291
+
292
+ tab.focus();
293
+
294
+ }
295
+
296
+ public MouseDownTab(event: MouseEvent, tab: HTMLElement, sheet: Sheet, index: number, tabs: HTMLElement[]) {
297
+
298
+ event.stopPropagation();
299
+ event.preventDefault();
300
+
301
+ if (this.IsDoubleClick(index)) {
302
+ return; // seems to allow us to process double clicks normally...
303
+ }
304
+
305
+ this.Publish({ type: 'activate-sheet', sheet });
306
+
307
+ let rectangles = tabs.map((element) => element.getBoundingClientRect());
308
+
309
+ let order = index * 2 - 1;
310
+
311
+ // orginal
312
+ const left = rectangles[0].left;
313
+ const right = rectangles[rectangles.length - 1].right;
314
+ const top = rectangles[0].top;
315
+ const bottom = rectangles[0].bottom;
316
+
317
+ const min = -1;
318
+ const max = (rectangles.length - 1) * 2 + 1;
319
+
320
+ // see above re: dragging and activation. if the tabs aren't rebuilt,
321
+ // then the classes won't change.
322
+
323
+ for (const candidate of tabs) {
324
+ this.SetActive(candidate, candidate === tab);
325
+ }
326
+
327
+ this.dragging = true;
328
+
329
+ MouseDrag(this.layout.mask, [], (move_event) => {
330
+
331
+ const [x, y] = [move_event.clientX, move_event.clientY];
332
+ if (y > top && y < bottom) {
333
+ let new_order = order;
334
+ if (x < left) { new_order = min; }
335
+ else if (x > right) { new_order = max; }
336
+ else {
337
+ for (let i = 0; i < rectangles.length; i++) {
338
+ const rectangle = rectangles[i];
339
+ if (x >= rectangle.left && x <= rectangle.right) {
340
+ if (i !== index) {
341
+ if (x >= rectangle.left + rectangle.width / 2) {
342
+ new_order = (i * 2) + 1;
343
+ }
344
+ else {
345
+ new_order = (i * 2) - 1;
346
+ }
347
+ }
348
+ break;
349
+ }
350
+ }
351
+ }
352
+ if (new_order !== order) {
353
+ order = new_order;
354
+ tab.style.order = order.toString();
355
+ rectangles = tabs.map((element) => element.getBoundingClientRect());
356
+ }
357
+ }
358
+
359
+ }, () => {
360
+ let current = index;
361
+ let move_before = (order + 1) / 2;
362
+
363
+ // console.info('set false')
364
+ this.dragging = false;
365
+
366
+ // the indexes we have are visible tabs only, so we may need
367
+ // to adjust if there are hidden tabs in between.
368
+
369
+ for (let i = 0; i < this.model.sheets.length; i++) {
370
+ if (!this.model.sheets.list[i].visible) {
371
+ if (current >= i) { current++; }
372
+ if (move_before >= i) { move_before++; }
373
+ }
374
+ }
375
+
376
+ if ((current === move_before) ||
377
+ (current === 0 && move_before <= 0) ||
378
+ (current === tabs.length - 1 && move_before >= tabs.length - 1)) {
379
+
380
+ // didn't change
381
+ }
382
+ else {
383
+ this.Publish({type: 'reorder-sheet', index: current, move_before});
384
+ }
385
+ });
386
+
387
+
388
+ }
389
+
390
+ /**
391
+ * update tabs from model.
392
+ */
393
+ public Update(): void {
394
+
395
+ // this is a hack to normalize behavior if you try to re-order
396
+ // a tab that's not the active tab. what ordinarily happens is
397
+ // we start the drag, but then Update is called again which rebuilds
398
+ // tabs and throws out the old set.
399
+
400
+ // at the same time we want to activate on mousedown, not mouseup.
401
+ // so for the time being we just block the rebuild if we are dragging.
402
+ // longer term it's a FIXME.
403
+
404
+ if (this.dragging) {
405
+ return;
406
+ }
407
+
408
+ if (this.options.tab_bar === 'auto') {
409
+ const visible_count = this.model.sheets.list.reduce((count, test) => test.visible ? count + 1 : count, 0);
410
+ if (visible_count <= 1) {
411
+ this.Show(false);
412
+ return;
413
+ }
414
+ this.Show(true);
415
+ }
416
+
417
+ if (!this.tab_container) {
418
+ return;
419
+ }
420
+
421
+ // clear
422
+ this.tab_container.innerText = '';
423
+
424
+ // we need to pass the full array to the drag function, so collect them
425
+ const tabs: HTMLElement[] = [];
426
+
427
+ for (const sheet of this.model.sheets.list) {
428
+
429
+ if (!sheet.visible) { continue; }
430
+
431
+ const index = tabs.length;
432
+ // const tab = document.createElement('div');
433
+ const tab = document.createElement('li');
434
+
435
+ // tab.classList.add('tab');
436
+ tab.style.order = (index * 2).toString();
437
+ tab.role = 'tab';
438
+
439
+ this.SetActive(tab, sheet === this.view.active_sheet);
440
+
441
+ const mousedown = (event: MouseEvent) => this.MouseDownTab(event, tab, sheet, index, tabs);
442
+
443
+ const doubleclick = (event: MouseEvent) => {
444
+ tab.removeEventListener('mousedown', mousedown);
445
+ tab.removeEventListener('dblclick', doubleclick);
446
+ this.DoubleClickTab(event, tab, sheet);
447
+ };
448
+
449
+ // you need the inner span for ellipsis, if we want that
450
+
451
+ tab.textContent = sheet.name;
452
+ // tab.innerHTML = `<span>${sheet.name}</span>`;
453
+
454
+ tab.addEventListener('dblclick', doubleclick);
455
+ tab.addEventListener('mousedown', mousedown);
456
+
457
+ this.tab_container.appendChild(tab);
458
+ tabs.push(tab);
459
+
460
+ }
461
+
462
+ }
463
+
464
+ }
@@ -0,0 +1,59 @@
1
+ /*
2
+ * This file is part of TREB.
3
+ *
4
+ * TREB is free software: you can redistribute it and/or modify it under the
5
+ * terms of the GNU General Public License as published by the Free Software
6
+ * Foundation, either version 3 of the License, or (at your option) any
7
+ * later version.
8
+ *
9
+ * TREB is distributed in the hope that it will be useful, but WITHOUT ANY
10
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12
+ * details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License along
15
+ * with TREB. If not, see <https://www.gnu.org/licenses/>.
16
+ *
17
+ * Copyright 2022-2023 trebco, llc.
18
+ * info@treb.app
19
+ *
20
+ */
21
+
22
+ import type { Point, Size, Position } from 'treb-base-types';
23
+
24
+ /**
25
+ * tile adds some metadata to canvas
26
+ *
27
+ * FIXME: there might be some performance cost with this, versus a wrapper
28
+ * or container class/interface that just holds the canvas.
29
+ */
30
+ export interface Tile extends HTMLCanvasElement {
31
+
32
+ /** contents have changed, needs repainting */
33
+ dirty: boolean;
34
+
35
+ /** never painted or layout has changed: repaint everything */
36
+ needs_full_repaint: boolean;
37
+
38
+ /** position in the grid, in grid rows/columns */
39
+ tile_position: Position;
40
+
41
+ /** first cell in the tile */
42
+ first_cell: Position;
43
+
44
+ /** last cell in the tile, more useful than extent */
45
+ last_cell: Position;
46
+
47
+ /** position in the grid, in pixels */
48
+ pixel_start: Point;
49
+
50
+ /** position in the grid, in pixels */
51
+ pixel_end: Point;
52
+
53
+ /**
54
+ * tile size in pixels, matching css height/width. this is
55
+ * different than the _canvas_ height/width, which is scaled
56
+ * to dpr for high-dpi displays.
57
+ */
58
+ logical_size: Size;
59
+ }
@@ -0,0 +1,75 @@
1
+ /*
2
+ * This file is part of TREB.
3
+ *
4
+ * TREB is free software: you can redistribute it and/or modify it under the
5
+ * terms of the GNU General Public License as published by the Free Software
6
+ * Foundation, either version 3 of the License, or (at your option) any
7
+ * later version.
8
+ *
9
+ * TREB is distributed in the hope that it will be useful, but WITHOUT ANY
10
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12
+ * details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License along
15
+ * with TREB. If not, see <https://www.gnu.org/licenses/>.
16
+ *
17
+ * Copyright 2022-2023 trebco, llc.
18
+ * info@treb.app
19
+ *
20
+ */
21
+
22
+ import type { Area } from 'treb-base-types';
23
+
24
+ /**
25
+ * trying to split data management from the grid, we are updating the
26
+ * command queue so that (some/most) methods return hints as to what
27
+ * needs to update: a nonvisible grid can just ignore this, but the
28
+ * visible grid can use it to trigger layout/repaint/etc.
29
+ */
30
+ export interface UpdateFlags {
31
+
32
+ /** sheet names or order have changed, update the tab bar */
33
+ sheets?: boolean;
34
+
35
+ /**
36
+ * structure refers to rows/columns/sheets -- something has been
37
+ * added, removed, or resized
38
+ */
39
+ structure?: boolean;
40
+
41
+ /**
42
+ * on sheet change, hide hover info -- hyperlink, note, &c
43
+ */
44
+ active_sheet?: boolean;
45
+
46
+ /**
47
+ * formula -- we might need to update the formula bar
48
+ */
49
+ formula?: boolean;
50
+
51
+ /**
52
+ * layout is changing. use this as a proxy for the old "queue layout update"
53
+ */
54
+ layout?: boolean;
55
+
56
+ /** non-active sheets updated. we set flags to update layout on activate */
57
+ pending?: number[];
58
+
59
+ /**
60
+ * this is only used by the setheaders command, which needs to come
61
+ * out. so this should also come out.
62
+ */
63
+ repaint?: boolean;
64
+
65
+ data_event?: boolean;
66
+ style_event?: boolean;
67
+ structure_event?: boolean;
68
+ structure_rebuild_required?: boolean;
69
+
70
+ render_area?: Area;
71
+ data_area?: Area;
72
+ style_area?: Area;
73
+
74
+
75
+ }