@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,72 @@
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
+ /*
23
+ * render text types moved from tile renderer in grid
24
+ */
25
+
26
+ /**
27
+ * information about a rendered substring. FIXME: move this somewhere else
28
+ *
29
+ * FIXME: there's a lot of overlap between this and "TextPartFlag", which
30
+ * comes from base types and is used by formatter. can we consolidate these?
31
+ *
32
+ * testing some inline markdown...
33
+ * FIXME: gate on option? sheet option? (...)
34
+ *
35
+ */
36
+ export interface RenderTextPart {
37
+ text: string;
38
+ hidden: boolean;
39
+ width: number;
40
+
41
+ // italic?: boolean; // for imaginary // looks like crap
42
+
43
+ // adding optional layout info (for hyperlink, basically)
44
+
45
+ top?: number;
46
+ left?: number;
47
+ height?: number;
48
+
49
+ // testing, md
50
+ strong?: boolean;
51
+ emphasis?: boolean;
52
+ strike?: boolean;
53
+
54
+ }
55
+
56
+ export interface PreparedText {
57
+
58
+ /**
59
+ * strings now represents parts of individual lines; this both supports
60
+ * MD and unifies the old system where it meant _either_ parts _or_ lines,
61
+ * which was super confusing.
62
+ */
63
+ strings: RenderTextPart[][];
64
+
65
+ /** this is the max rendered width. individual components have their own width */
66
+ width: number;
67
+
68
+ /** possibly override format; this is used for number formats that have [color] */
69
+ format?: string;
70
+
71
+ }
72
+
@@ -0,0 +1,545 @@
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
+ // why is this a namespace? module is implicit... it's because of how
23
+ // base types exports; we can't export * as Style, so we're stuck with
24
+ // the namespace (or you could add an intermediate file and import ->
25
+ // export, but that just seems like unecessary complexity and still kludgy).
26
+
27
+ // eslint-disable-next-line @typescript-eslint/no-namespace
28
+ export namespace Style {
29
+
30
+ const empty_json = JSON.stringify({}); // we could probably hard-code this
31
+
32
+ /**
33
+ * horizontal align constants
34
+ */
35
+ export enum HorizontalAlign {
36
+ None = '',
37
+ Left = 'left',
38
+ Center = 'center',
39
+ Right = 'right',
40
+ }
41
+
42
+ /**
43
+ * vertical align constants
44
+ *
45
+ * @privateRemarks
46
+ *
47
+ * horizontal alignment was (none), left, center, right.
48
+ * vertical aligment was (none), top, bottom, middle.
49
+ *
50
+ * not sure why these were not symmetrical, but having strings makes it
51
+ * easier to manage.
52
+ */
53
+ export enum VerticalAlign {
54
+ None = '',
55
+ Top = 'top',
56
+ Bottom = 'bottom',
57
+ Middle = 'middle',
58
+ }
59
+
60
+ /** composite font size */
61
+ export interface FontSize {
62
+ unit: 'pt'|'px'|'em'|'%';
63
+ value: number;
64
+ }
65
+
66
+ /**
67
+ * color is either a theme color (theme index plus tint), or CSS text
68
+ *
69
+ * @privateRemarks
70
+ *
71
+ * FIXME: this should be a union type
72
+ */
73
+ export interface Color {
74
+
75
+ theme?: number;
76
+ tint?: number;
77
+ text?: string;
78
+
79
+ /** @internal */
80
+ offset?: Color;
81
+
82
+ /** @deprecated */
83
+ none?: boolean;
84
+ }
85
+
86
+ /** @internal */
87
+ export interface CompositeBorderEdge {
88
+ width: number;
89
+ color: Color;
90
+ }
91
+
92
+ /** @internal */
93
+ export interface CompositeBorder {
94
+ top: CompositeBorderEdge,
95
+ left: CompositeBorderEdge,
96
+ right: CompositeBorderEdge,
97
+ bottom: CompositeBorderEdge,
98
+ }
99
+
100
+ /**
101
+ * style properties applied to a cell.
102
+ */
103
+ export interface Properties {
104
+
105
+ /** horizontal align defaults to left */
106
+ horizontal_align?: HorizontalAlign;
107
+
108
+ /** vertical align defaults to bottom */
109
+ vertical_align?: VerticalAlign;
110
+
111
+ /** representation for NaN */
112
+ nan?: string;
113
+
114
+ /** number format, either a symbolic name like "General" or a format string */
115
+ number_format?: string;
116
+
117
+ /** wrap text */
118
+ wrap?: boolean;
119
+
120
+ /**
121
+ * font size. we recommend using relative font sizes (either % or em)
122
+ * which will be relative to the theme font size.
123
+ */
124
+ font_size?: FontSize;
125
+
126
+ /** font face. this can be a comma-delimited list, like CSS */
127
+ font_face?: string;
128
+
129
+ /** flag */
130
+ bold?: boolean; // FIXME: switch to weight
131
+
132
+ /** flag */
133
+ italic?: boolean;
134
+
135
+ /** flag */
136
+ underline?: boolean;
137
+
138
+ /** flag */
139
+ strike?: boolean;
140
+
141
+ // font_weight?: number;
142
+
143
+ /** border weight */
144
+ border_top?: number;
145
+
146
+ /** border weight */
147
+ border_right?: number;
148
+
149
+ /** border weight */
150
+ border_left?: number;
151
+
152
+ /** border weight */
153
+ border_bottom?: number;
154
+
155
+ // COLORS. there's a new thing with colors where we need to
156
+ // be able to clear them, in a merge operation. these should
157
+ // perhaps be an object, but for the time being for colors,
158
+ // "" in a merge means "remove this property".
159
+
160
+ // background?: string;
161
+ // text_color?: string;
162
+
163
+ //border_top_color?: string;
164
+ //border_left_color?: string;
165
+ //border_right_color?: string;
166
+ //border_bottom_color?: string;
167
+
168
+ // changing colors to support styles... starting with text
169
+
170
+ /** text color */
171
+ text?: Color;
172
+
173
+ /** background color */
174
+ fill?: Color;
175
+
176
+ /** border color */
177
+ border_top_fill?: Color;
178
+
179
+ /** border color */
180
+ border_left_fill?: Color;
181
+
182
+ /** border color */
183
+ border_right_fill?: Color;
184
+
185
+ /** border color */
186
+ border_bottom_fill?: Color;
187
+
188
+ // NEW
189
+ // FIXME: change name to editable, default true? (...)
190
+
191
+ // this is not properly in style -- should be in cell
192
+
193
+ // UPDATE: whether it's appropriate or not, style is a better place
194
+ // because it can cascade
195
+
196
+ /**
197
+ * cell is locked for editing
198
+ */
199
+ locked?: boolean;
200
+
201
+ }
202
+
203
+ /** @internal */
204
+ export type PropertyKeys = keyof Style.Properties;
205
+
206
+ /**
207
+ * note that there are no default colors; those should be set
208
+ * in grid when style is applied. that way the default colors for
209
+ * border, text and background colors will be theme-dependent and
210
+ * can change.
211
+ *
212
+ * @internal
213
+ */
214
+ export const DefaultProperties: Properties = {
215
+ horizontal_align: HorizontalAlign.None,
216
+ vertical_align: VerticalAlign.None,
217
+ number_format: 'General', // '0.######', // use symbolic, e.g. "general"
218
+ nan: 'NaN',
219
+ // font_size: 10, // should have units
220
+
221
+ font_size: { unit: 'pt', value: 10.5 },
222
+ font_face: 'sans-serif',
223
+
224
+ /*
225
+ // font_size_value: 10,
226
+ // font_size_unit: 'pt',
227
+ font_size: {
228
+ unit: 'em', value: 1,
229
+ },
230
+
231
+ font_face: 'times new roman', // switch to something generic "sans serif"
232
+ */
233
+
234
+ bold: false, // drop "font_"
235
+ italic: false, // ...
236
+ underline: false, // ...
237
+ strike: false, //
238
+ // background: 'none',
239
+
240
+ // text_color: 'none',
241
+ // text: 'theme',
242
+ // text_theme: 0,
243
+ text: { theme: 1 },
244
+
245
+ // border_top_color: 'none',
246
+ // border_left_color: 'none',
247
+ // border_right_color: 'none',
248
+ // border_bottom_color: 'none',
249
+
250
+ border_top: 0, // adding defaults so these prune propery
251
+ border_left: 0,
252
+ border_right: 0,
253
+ border_bottom: 0,
254
+ };
255
+
256
+ /**
257
+ * this is a utility function for callers that use borders, to
258
+ * reduce testing and facilitate reusable methods
259
+ *
260
+ * @internal
261
+ */
262
+ export const CompositeBorders = (style: Properties): CompositeBorder => {
263
+ return {
264
+ top: {
265
+ width: style.border_top || 0,
266
+ color: style.border_top_fill || {},
267
+ },
268
+ left: {
269
+ width: style.border_left || 0,
270
+ color: style.border_left_fill || {},
271
+ },
272
+ right: {
273
+ width: style.border_right || 0,
274
+ color: style.border_right_fill || {},
275
+ },
276
+ bottom: {
277
+ width: style.border_bottom || 0,
278
+ color: style.border_bottom_fill || {},
279
+ },
280
+ };
281
+ };
282
+
283
+ /* *
284
+ * this version of merge is used to support explicit deletes, via
285
+ * "undefined" properties. we use a trick via JSON to skip iterating
286
+ * properties (I believe this is faster, but have not tested).
287
+ * /
288
+ export const Merge2 = (dest: Properties, src: Properties): Properties => {
289
+ return JSON.parse(JSON.stringify({...dest, ...src}));
290
+ }
291
+ */
292
+
293
+ /**
294
+ * merge. returns a new object, does not update dest in place.
295
+ * NOTE: if it does not update dest in place, then what would be
296
+ * the use case for a non-delta merge? (...)
297
+ *
298
+ * @internal
299
+ */
300
+ export const Merge = (dest: Properties, src: Properties, delta = true): Properties => {
301
+ const properties: Properties = delta ? {...dest, ...src} : {...src};
302
+ return JSON.parse(JSON.stringify(properties));
303
+ };
304
+
305
+ /** @internal */
306
+ export const Composite = (list: Properties[]): Properties => {
307
+ return JSON.parse(JSON.stringify(list.reduce((composite, item) => ({...composite, ...item}), {})));
308
+ };
309
+
310
+ /** @internal */
311
+ export const Empty = (style: Properties): boolean => {
312
+ return JSON.stringify(style) === empty_json;
313
+ };
314
+
315
+ /** @internal */
316
+ export const ValidColor = (color?: Color): boolean => {
317
+ return !!(color && (!color.none) && (color.text || color.theme || color.theme === 0));
318
+ };
319
+
320
+ /*
321
+ export const Prune = (style: Properties): void => {
322
+
323
+ // text default is theme 0, so we can remove that if we see it.
324
+ // same for borders, we can group
325
+
326
+ if (style.text && !style.text.text && !style.text.theme) {
327
+ style.text = undefined;
328
+ }
329
+
330
+ if (style.border_top_fill && !style.border_top_fill.text && !style.border_top_fill.theme) {
331
+ style.border_top_fill = undefined;
332
+ }
333
+
334
+ if (style.border_left_fill && !style.border_left_fill.text && !style.border_left_fill.theme) {
335
+ style.border_left_fill = undefined;
336
+ }
337
+
338
+ if (style.border_right_fill && !style.border_right_fill.text && !style.border_right_fill.theme) {
339
+ style.border_right_fill = undefined;
340
+ }
341
+
342
+ if (style.border_bottom_fill && !style.border_bottom_fill.text && !style.border_bottom_fill.theme) {
343
+ style.border_bottom_fill = undefined;
344
+ }
345
+
346
+ // background has no default, so check for 0
347
+ if (style.fill && !style.fill.text && !style.fill.theme && style.fill.theme !== 0) {
348
+ style.fill = undefined;
349
+ }
350
+
351
+ };
352
+ */
353
+
354
+ /* *
355
+ * overlay. will always put defaults at the bottom.
356
+ * /
357
+ export const Composite = (list: Properties[]) => {
358
+ return list.reduce((composite, item) => ({...composite, ...item}),
359
+ {...DefaultProperties});
360
+ };
361
+
362
+ / * *
363
+ * modify default properties. useful for theming.
364
+ * /
365
+ export const UpdateDefaultProperties = (opts: Properties) => {
366
+ DefaultProperties = {
367
+ ...DefaultProperties, ...opts,
368
+ };
369
+ };
370
+ */
371
+
372
+ /** @internal */
373
+ export const ParseFontSize = (text = '', default_unit = 'em'): Properties => {
374
+ const match = text.match(/(-*[\d.]+)\s*(\S*)/);
375
+
376
+ if (match) {
377
+ const value = Number(match[1]);
378
+ if (!value || isNaN(value) || value < 0) {
379
+ return {}; // invalid
380
+ }
381
+ const unit = match[2].toLowerCase() || default_unit;
382
+ if (unit === 'pt' || unit === 'em' || unit === '%' || unit === 'px') {
383
+ // return { font_size_unit: unit, font_size_value: value };
384
+ return {
385
+ font_size: { unit, value },
386
+ };
387
+ }
388
+ }
389
+
390
+ return {};
391
+ };
392
+
393
+ /**
394
+ * returns the font size of the properties argument as a ratio of the
395
+ * base argument. this is intended to show the relative font size of
396
+ * a spreadsheet cell; so anything with no value should be "1", and
397
+ * everything else is relative to that.
398
+ *
399
+ * we prefer relative sizes (em, essentially) to fixed sizes because
400
+ * we may have different base font sizes on different platforms (we do,
401
+ * in fact, on windows because calibri is too small).
402
+ *
403
+ * using relative sizes helps ensure that it looks similar, if not
404
+ * identical, on different platforms.
405
+ *
406
+ * @internal
407
+ */
408
+ export const RelativeFontSize = (properties: Properties, base: Properties): number => {
409
+
410
+ // we can assume (I think) that base will be either points or px;
411
+ // there's no case where it should be relative. in fact, let's treat
412
+ // that as an error and return 1.
413
+
414
+ // note that if properties is relative (em or %) we don't have to
415
+ // calculate, it's implicit
416
+
417
+ let base_pt = 12;
418
+ let props_pt = 12;
419
+
420
+ switch (properties.font_size?.unit) {
421
+ case 'pt':
422
+ if (!properties.font_size.value) { return 1; } // also error
423
+ props_pt = properties.font_size.value;
424
+ break;
425
+
426
+ case 'px':
427
+ if (!properties.font_size.value) { return 1; } // also error
428
+ props_pt = Math.round(properties.font_size.value * 300 / 4) / 100;
429
+ break;
430
+
431
+ case 'em':
432
+ return (properties.font_size.value || 1); // short circuit
433
+
434
+ case '%':
435
+ return (properties.font_size.value || 100) / 100; // short circuit
436
+
437
+ default:
438
+ return 1; // error
439
+ }
440
+
441
+ switch (base.font_size?.unit) {
442
+ case 'pt':
443
+ if (!base.font_size.value) { return 1; } // also error
444
+ base_pt = base.font_size.value;
445
+ break;
446
+
447
+ case 'px':
448
+ if (!base.font_size.value) { return 1; } // also error
449
+ base_pt = Math.round(base.font_size.value * 300 / 4) / 100;
450
+ break;
451
+
452
+ default:
453
+ return 1; // error
454
+ }
455
+
456
+ return props_pt / base_pt;
457
+
458
+ };
459
+
460
+ /** @internal */
461
+ export const FontSize = (properties: Properties, prefer_points = true): string => {
462
+
463
+ const value = properties.font_size?.value;
464
+
465
+ switch (properties.font_size?.unit) {
466
+ case 'pt':
467
+ return (value||12) + 'pt';
468
+
469
+ case 'px':
470
+ if (prefer_points) {
471
+ const points = Math.round((value||16) * 300 / 4) / 100;
472
+ return (points) + 'pt';
473
+ }
474
+ return (value||16) + 'px';
475
+
476
+ case 'em':
477
+ return (value||1) + 'em';
478
+
479
+ case '%':
480
+ return (value||100) + '%';
481
+
482
+ }
483
+
484
+ return '';
485
+ };
486
+
487
+ /**
488
+ * returns a string representation suitable for canvas (or style)
489
+ *
490
+ * @internal
491
+ */
492
+ export const Font = (properties: Properties, scale = 1) => {
493
+
494
+ /*
495
+ let font_size = properties.font_size;
496
+ if (typeof font_size === 'number') {
497
+ font_size = (font_size * scale) + 'pt';
498
+ }
499
+ else if (font_size && scale !== 1) {
500
+ const font_parts = font_size.match(/^([\d\.]+)(\D*)$/);
501
+ if (font_parts) {
502
+ font_size = (Number(font_parts[1]) * scale) + font_parts[2];
503
+ }
504
+ }
505
+ */
506
+
507
+ const parts: string[] = [];
508
+
509
+ //if (properties.font_weight) {
510
+ // parts.push(properties.font_weight.toString());
511
+ //}
512
+ //else
513
+ if (properties.bold) {
514
+ parts.push('bold');
515
+ }
516
+
517
+ if (properties.italic) {
518
+ parts.push('italic');
519
+ }
520
+
521
+ parts.push(((properties.font_size?.value || 0) * scale).toFixed(2) +
522
+ (properties.font_size?.unit || 'pt'));
523
+
524
+ parts.push(properties.font_face || '');
525
+
526
+ return parts.join(' ');
527
+
528
+ /*
529
+ // console.info("FS", font_size);
530
+
531
+ if (properties.font_weight) {
532
+ return (properties.font_weight + ' ')
533
+ + (properties.font_italic ? 'italic ' : '')
534
+ + font_size + ' ' + properties.font_face;
535
+ }
536
+ else {
537
+ return (properties.font_bold ? 'bold ' : '')
538
+ + (properties.font_italic ? 'italic ' : '')
539
+ + font_size + ' ' + properties.font_face;
540
+ }
541
+ */
542
+
543
+ };
544
+
545
+ }