@svgrid/enterprise 3.1.8 → 3.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (268) hide show
  1. package/README.md +1 -0
  2. package/dist/SvAlertRuleEditor.svelte +16 -5
  3. package/dist/SvGridAlerts.svelte +8 -0
  4. package/dist/SvGridAlerts.svelte.d.ts +4 -0
  5. package/dist/SvGridBoard.svelte +69 -10
  6. package/dist/SvGridBulkEditDrawer.svelte +13 -5
  7. package/dist/SvGridGallery.svelte +286 -0
  8. package/dist/SvGridGallery.svelte.d.ts +30 -0
  9. package/dist/SvGridScheduler.svelte +33 -11
  10. package/dist/SvGridSelectionBar.svelte +47 -0
  11. package/dist/advanced-filter/expr-columns-from-grid.d.ts +1 -0
  12. package/dist/advanced-filter/expr-columns-from-grid.js +11 -7
  13. package/dist/advanced-filter-enable.d.ts +6 -0
  14. package/dist/advanced-filter-enable.js +8 -0
  15. package/dist/alerts/alert-engine.d.ts +7 -0
  16. package/dist/alerts/alert-engine.js +5 -2
  17. package/dist/alerts/condition-editor.d.ts +26 -0
  18. package/dist/alerts/condition-editor.js +17 -0
  19. package/dist/base/index.d.ts +20 -0
  20. package/dist/base/index.js +20 -0
  21. package/dist/bulk-edit.d.ts +11 -0
  22. package/dist/bulk-edit.js +18 -1
  23. package/dist/cdn/svgrid-enterprise.svelte-external.js +11197 -10639
  24. package/dist/designer/assets/GridFooter-Cu8_yBlQ.js +2 -0
  25. package/dist/designer/assets/GridMenus-BUjkkAU2.js +6 -0
  26. package/dist/designer/assets/PinSplitter-BgTpgh1d.css +1 -0
  27. package/dist/designer/assets/PinSplitter-C5AwA1xV.js +1 -0
  28. package/dist/designer/assets/SvGrid.helpers-CIrmIo9U.js +1 -0
  29. package/dist/designer/assets/SvGridCellEditor-CJxThKL_.js +4 -0
  30. package/dist/designer/assets/SvListBox-CS7oUAiX.js +2 -0
  31. package/dist/designer/assets/conditional-formatting-MDWbF8_Y.js +1 -0
  32. package/dist/designer/assets/grid-extension.svelte-BZ7AqyJI.js +1 -0
  33. package/dist/designer/assets/{index-Obk8sI77.js → index-BPU2KNc5.js} +307 -307
  34. package/dist/designer/assets/index-BmvG99kR.css +1 -0
  35. package/dist/designer/assets/sparkline-C-NcnB2i.js +1 -0
  36. package/dist/designer/assets/src-C_U1NKOY.js +58 -0
  37. package/dist/designer/assets/sv-grid-scrollbar-B9N6Wuj0.js +109 -0
  38. package/dist/designer/assets/validate-H5u2HEQh.js +1 -0
  39. package/dist/designer/index.html +11 -7
  40. package/dist/expressions/compile.js +10 -0
  41. package/dist/expressions/evaluate.js +18 -0
  42. package/dist/expressions/expression-types.d.ts +10 -0
  43. package/dist/expressions/kinds.d.ts +28 -0
  44. package/dist/expressions/kinds.js +19 -0
  45. package/dist/expressions/parse.js +9 -1
  46. package/dist/fields/AttachmentCell.svelte +242 -0
  47. package/dist/fields/AttachmentCell.svelte.d.ts +5 -0
  48. package/dist/fields/AttachmentDialog.svelte +357 -0
  49. package/dist/fields/AttachmentDialog.svelte.d.ts +13 -0
  50. package/dist/fields/AttachmentEditor.svelte +41 -0
  51. package/dist/fields/AttachmentEditor.svelte.d.ts +11 -0
  52. package/dist/fields/AttachmentPreview.svelte +72 -0
  53. package/dist/fields/AttachmentPreview.svelte.d.ts +8 -0
  54. package/dist/fields/BarcodeCell.svelte +20 -0
  55. package/dist/fields/BarcodeCell.svelte.d.ts +5 -0
  56. package/dist/fields/BaseAutomations.svelte +558 -0
  57. package/dist/fields/BaseAutomations.svelte.d.ts +18 -0
  58. package/dist/fields/BaseChartView.svelte +47 -0
  59. package/dist/fields/BaseChartView.svelte.d.ts +8 -0
  60. package/dist/fields/BaseTableView.svelte +185 -0
  61. package/dist/fields/BaseTableView.svelte.d.ts +37 -0
  62. package/dist/fields/BaseTabs.svelte +308 -0
  63. package/dist/fields/BaseTabs.svelte.d.ts +21 -0
  64. package/dist/fields/ButtonCell.svelte +47 -0
  65. package/dist/fields/ButtonCell.svelte.d.ts +20 -0
  66. package/dist/fields/CheckboxCell.svelte +46 -0
  67. package/dist/fields/CheckboxCell.svelte.d.ts +14 -0
  68. package/dist/fields/DeleteFieldConfirm.svelte +80 -0
  69. package/dist/fields/DeleteFieldConfirm.svelte.d.ts +8 -0
  70. package/dist/fields/DeleteRecordConfirm.svelte +48 -0
  71. package/dist/fields/DeleteRecordConfirm.svelte.d.ts +9 -0
  72. package/dist/fields/FieldCell.svelte +80 -0
  73. package/dist/fields/FieldCell.svelte.d.ts +9 -0
  74. package/dist/fields/FieldEditor.svelte +321 -0
  75. package/dist/fields/FieldEditor.svelte.d.ts +10 -0
  76. package/dist/fields/FieldInput.svelte +188 -0
  77. package/dist/fields/FieldInput.svelte.d.ts +29 -0
  78. package/dist/fields/FieldsHeaderEnd.svelte +146 -0
  79. package/dist/fields/FieldsHeaderEnd.svelte.d.ts +6 -0
  80. package/dist/fields/FootRowAdder.svelte +8 -0
  81. package/dist/fields/FootRowAdder.svelte.d.ts +6 -0
  82. package/dist/fields/GroupHeader.svelte +127 -0
  83. package/dist/fields/GroupHeader.svelte.d.ts +24 -0
  84. package/dist/fields/LinkCell.svelte +46 -0
  85. package/dist/fields/LinkCell.svelte.d.ts +9 -0
  86. package/dist/fields/LinkPickerEditor.svelte +172 -0
  87. package/dist/fields/LinkPickerEditor.svelte.d.ts +9 -0
  88. package/dist/fields/LinkPreview.svelte +60 -0
  89. package/dist/fields/LinkPreview.svelte.d.ts +7 -0
  90. package/dist/fields/LinkedRecordView.svelte +94 -0
  91. package/dist/fields/LinkedRecordView.svelte.d.ts +9 -0
  92. package/dist/fields/LinkedRecordsCell.svelte +59 -0
  93. package/dist/fields/LinkedRecordsCell.svelte.d.ts +11 -0
  94. package/dist/fields/LongTextEditor.svelte +157 -0
  95. package/dist/fields/LongTextEditor.svelte.d.ts +11 -0
  96. package/dist/fields/NumberEditor.svelte +309 -0
  97. package/dist/fields/NumberEditor.svelte.d.ts +12 -0
  98. package/dist/fields/OptionsEditor.svelte +117 -0
  99. package/dist/fields/OptionsEditor.svelte.d.ts +11 -0
  100. package/dist/fields/PercentCell.svelte +21 -0
  101. package/dist/fields/PercentCell.svelte.d.ts +8 -0
  102. package/dist/fields/PropertyInput.svelte +204 -0
  103. package/dist/fields/PropertyInput.svelte.d.ts +11 -0
  104. package/dist/fields/RatingCell.svelte +75 -0
  105. package/dist/fields/RatingCell.svelte.d.ts +16 -0
  106. package/dist/fields/RatingEditor.svelte +82 -0
  107. package/dist/fields/RatingEditor.svelte.d.ts +9 -0
  108. package/dist/fields/RecordView.svelte +310 -0
  109. package/dist/fields/RecordView.svelte.d.ts +11 -0
  110. package/dist/fields/RichTextCell.svelte +30 -0
  111. package/dist/fields/RichTextCell.svelte.d.ts +5 -0
  112. package/dist/fields/RowAdder.svelte +93 -0
  113. package/dist/fields/RowAdder.svelte.d.ts +7 -0
  114. package/dist/fields/RowHeader.svelte +99 -0
  115. package/dist/fields/RowHeader.svelte.d.ts +11 -0
  116. package/dist/fields/SelectCell.svelte +35 -0
  117. package/dist/fields/SelectCell.svelte.d.ts +15 -0
  118. package/dist/fields/SelectEditor.svelte +350 -0
  119. package/dist/fields/SelectEditor.svelte.d.ts +17 -0
  120. package/dist/fields/SummaryCell.svelte +160 -0
  121. package/dist/fields/SummaryCell.svelte.d.ts +11 -0
  122. package/dist/fields/SvBase.svelte +545 -0
  123. package/dist/fields/SvBase.svelte.d.ts +30 -0
  124. package/dist/fields/SvBaseForm.svelte +295 -0
  125. package/dist/fields/SvBaseForm.svelte.d.ts +22 -0
  126. package/dist/fields/SvBaseViewBar.svelte +644 -0
  127. package/dist/fields/SvBaseViewBar.svelte.d.ts +26 -0
  128. package/dist/fields/UserCell.svelte +39 -0
  129. package/dist/fields/UserCell.svelte.d.ts +9 -0
  130. package/dist/fields/UserFace.svelte +30 -0
  131. package/dist/fields/UserFace.svelte.d.ts +12 -0
  132. package/dist/fields/activity.svelte.d.ts +50 -0
  133. package/dist/fields/activity.svelte.js +110 -0
  134. package/dist/fields/attachments.d.ts +95 -0
  135. package/dist/fields/attachments.js +145 -0
  136. package/dist/fields/automation-outbound.d.ts +46 -0
  137. package/dist/fields/automation-outbound.js +61 -0
  138. package/dist/fields/automation-server.d.ts +53 -0
  139. package/dist/fields/automation-server.js +333 -0
  140. package/dist/fields/automations.svelte.d.ts +208 -0
  141. package/dist/fields/automations.svelte.js +437 -0
  142. package/dist/fields/bar-request.svelte.d.ts +16 -0
  143. package/dist/fields/bar-request.svelte.js +15 -0
  144. package/dist/fields/base-alerts.d.ts +24 -0
  145. package/dist/fields/base-alerts.js +64 -0
  146. package/dist/fields/base-connect.d.ts +82 -0
  147. package/dist/fields/base-connect.js +271 -0
  148. package/dist/fields/base-schema.d.ts +104 -0
  149. package/dist/fields/base-schema.js +266 -0
  150. package/dist/fields/base-sql.d.ts +62 -0
  151. package/dist/fields/base-sql.js +251 -0
  152. package/dist/fields/base-sync.d.ts +142 -0
  153. package/dist/fields/base-sync.js +499 -0
  154. package/dist/fields/base-tables.d.ts +89 -0
  155. package/dist/fields/base-tables.js +349 -0
  156. package/dist/fields/builtin-types.d.ts +13 -0
  157. package/dist/fields/builtin-types.js +773 -0
  158. package/dist/fields/button.d.ts +2 -0
  159. package/dist/fields/button.js +17 -0
  160. package/dist/fields/chart-view.d.ts +35 -0
  161. package/dist/fields/chart-view.js +154 -0
  162. package/dist/fields/column-order.d.ts +6 -0
  163. package/dist/fields/column-order.js +12 -0
  164. package/dist/fields/convert.d.ts +16 -0
  165. package/dist/fields/convert.js +176 -0
  166. package/dist/fields/copy-text.d.ts +13 -0
  167. package/dist/fields/copy-text.js +45 -0
  168. package/dist/fields/editor-request.svelte.d.ts +71 -0
  169. package/dist/fields/editor-request.svelte.js +52 -0
  170. package/dist/fields/field-ops.d.ts +72 -0
  171. package/dist/fields/field-ops.js +334 -0
  172. package/dist/fields/filter-model.d.ts +84 -0
  173. package/dist/fields/filter-model.js +446 -0
  174. package/dist/fields/format.d.ts +109 -0
  175. package/dist/fields/format.js +288 -0
  176. package/dist/fields/formula.d.ts +50 -0
  177. package/dist/fields/formula.js +530 -0
  178. package/dist/fields/grid-access.d.ts +60 -0
  179. package/dist/fields/grid-access.js +120 -0
  180. package/dist/fields/index.d.ts +34 -0
  181. package/dist/fields/index.js +312 -0
  182. package/dist/fields/linked-fields.d.ts +8 -0
  183. package/dist/fields/linked-fields.js +40 -0
  184. package/dist/fields/links.d.ts +10 -0
  185. package/dist/fields/links.js +46 -0
  186. package/dist/fields/name-list.d.ts +16 -0
  187. package/dist/fields/name-list.js +49 -0
  188. package/dist/fields/palette.d.ts +47 -0
  189. package/dist/fields/palette.js +69 -0
  190. package/dist/fields/record-delete.svelte.d.ts +12 -0
  191. package/dist/fields/record-delete.svelte.js +5 -0
  192. package/dist/fields/record-menu.d.ts +9 -0
  193. package/dist/fields/record-menu.js +78 -0
  194. package/dist/fields/registry.svelte.d.ts +176 -0
  195. package/dist/fields/registry.svelte.js +51 -0
  196. package/dist/fields/rich-text.d.ts +23 -0
  197. package/dist/fields/rich-text.js +48 -0
  198. package/dist/fields/row-color-choice.svelte.d.ts +31 -0
  199. package/dist/fields/row-color-choice.svelte.js +25 -0
  200. package/dist/fields/row-colors.d.ts +36 -0
  201. package/dist/fields/row-colors.js +90 -0
  202. package/dist/fields/row-height.d.ts +28 -0
  203. package/dist/fields/row-height.js +50 -0
  204. package/dist/fields/sources.svelte.d.ts +80 -0
  205. package/dist/fields/sources.svelte.js +131 -0
  206. package/dist/fields/summaries.d.ts +18 -0
  207. package/dist/fields/summaries.js +138 -0
  208. package/dist/fields/view-model.d.ts +129 -0
  209. package/dist/fields/view-model.js +492 -0
  210. package/dist/fields/viewbar/ChartPanel.svelte +61 -0
  211. package/dist/fields/viewbar/ChartPanel.svelte.d.ts +9 -0
  212. package/dist/fields/viewbar/ColorPanel.svelte +112 -0
  213. package/dist/fields/viewbar/ColorPanel.svelte.d.ts +9 -0
  214. package/dist/fields/viewbar/ConditionValue.svelte +153 -0
  215. package/dist/fields/viewbar/ConditionValue.svelte.d.ts +15 -0
  216. package/dist/fields/viewbar/FieldIcon.svelte +18 -0
  217. package/dist/fields/viewbar/FieldIcon.svelte.d.ts +9 -0
  218. package/dist/fields/viewbar/FilterPanel.svelte +192 -0
  219. package/dist/fields/viewbar/FilterPanel.svelte.d.ts +13 -0
  220. package/dist/fields/viewbar/GanttPanel.svelte +60 -0
  221. package/dist/fields/viewbar/GanttPanel.svelte.d.ts +10 -0
  222. package/dist/fields/viewbar/HideFieldsPanel.svelte +104 -0
  223. package/dist/fields/viewbar/HideFieldsPanel.svelte.d.ts +7 -0
  224. package/dist/fields/viewbar/SortPanel.svelte +85 -0
  225. package/dist/fields/viewbar/SortPanel.svelte.d.ts +8 -0
  226. package/dist/fields/viewbar/ViewsMenu.svelte +250 -0
  227. package/dist/fields/viewbar/ViewsMenu.svelte.d.ts +15 -0
  228. package/dist/fields/viewbar/panel-focus.d.ts +3 -0
  229. package/dist/fields/viewbar/panel-focus.js +22 -0
  230. package/dist/fields/viewbar/sort-state.d.ts +20 -0
  231. package/dist/fields/viewbar/sort-state.js +24 -0
  232. package/dist/gallery.d.ts +7 -0
  233. package/dist/gallery.js +36 -0
  234. package/dist/gantt/SvGridGantt.svelte +88 -16
  235. package/dist/gantt/gantt-config.d.ts +28 -0
  236. package/dist/index.d.ts +3 -0
  237. package/dist/index.js +6 -0
  238. package/dist/install.js +3 -0
  239. package/dist/license-core.d.ts +3 -3
  240. package/dist/license.js +1 -0
  241. package/dist/node/studio.js +105 -4
  242. package/dist/scheduler-config.d.ts +11 -0
  243. package/dist/sources/introspect-supabase.js +4 -1
  244. package/dist/sources/rest.js +6 -2
  245. package/dist/studio/ui-components.generated.js +93 -1
  246. package/dist/upgrade-prompt.d.ts +1 -1
  247. package/dist/version.d.ts +2 -2
  248. package/dist/version.js +2 -2
  249. package/dist/wc/GridFooter-f5K0aLe_.js +145 -0
  250. package/dist/wc/GridMenus-FtSN_8t9.js +1369 -0
  251. package/dist/wc/PinSplitter-D-qtDhSM.js +132 -0
  252. package/dist/wc/{SvGrid.helpers-zBkDTryR.js → SvGrid.helpers-B2GEKrxS.js} +84 -36
  253. package/dist/wc/{SvGridCellEditor-CzUKEbkI.js → SvGridCellEditor-B_cLJrsp.js} +20 -9
  254. package/dist/wc/conditional-formatting-BXis_oP1.js +189 -0
  255. package/dist/wc/grid-extension.svelte-Bufq4B4C.js +20 -0
  256. package/dist/wc/sv-sheet-element.js +7556 -7617
  257. package/dist/wc/svelte-virtualizer.svelte-ehwOupl-.js +360 -0
  258. package/dist/wc/{validate-43C03DLP.js → validate-BaMO8UPE.js} +1 -1
  259. package/package.json +14 -3
  260. package/dist/designer/assets/GridMenus-CvcASlKv.js +0 -8
  261. package/dist/designer/assets/SvGrid.helpers-DE5mmORW.js +0 -1
  262. package/dist/designer/assets/SvGridCellEditor-C7NWcnNC.js +0 -4
  263. package/dist/designer/assets/SvListBox-BlmmzYcU.js +0 -110
  264. package/dist/designer/assets/index-KmSEY7Lb.css +0 -1
  265. package/dist/designer/assets/src-DqHCqori.js +0 -58
  266. package/dist/designer/assets/validate-B71dE1Cs.js +0 -1
  267. package/dist/wc/GridMenus-fWbBUiRH.js +0 -1088
  268. package/dist/wc/svelte-virtualizer.svelte-Dntdh8Ms.js +0 -581
@@ -0,0 +1,288 @@
1
+ /**
2
+ * Display formats for number-like and date fields, as the field editor offers
3
+ * them: decimal places, which characters separate thousands and decimals, a
4
+ * large-number abbreviation (1.2K, 3.4M), a currency symbol, duration as
5
+ * h:mm(:ss(.S)), dates as local / friendly / US / European / ISO with a 12- or
6
+ * 24-hour time, in local time or one shared time zone.
7
+ */
8
+ const SEPARATOR_PAIRS = {
9
+ 'comma-period': [',', '.'],
10
+ 'period-comma': ['.', ','],
11
+ 'space-comma': [' ', ','],
12
+ 'space-period': [' ', '.'],
13
+ };
14
+ const ABBR = {
15
+ thousand: [1e3, 'K'],
16
+ million: [1e6, 'M'],
17
+ billion: [1e9, 'B'],
18
+ };
19
+ export function toNumber(value) {
20
+ if (value == null || value === '')
21
+ return null;
22
+ const n = typeof value === 'number' ? value : Number(value);
23
+ return Number.isFinite(n) ? n : null;
24
+ }
25
+ /** A number as the field shows it, without a currency symbol or percent sign. */
26
+ export function formatNumber(value, p) {
27
+ let n = value;
28
+ let suffix = '';
29
+ if (p.abbreviation && p.abbreviation !== 'none') {
30
+ const [div, s] = ABBR[p.abbreviation];
31
+ n = value / div;
32
+ suffix = s;
33
+ }
34
+ const digits = Math.max(0, Math.min(8, Math.round(p.precision ?? 0)));
35
+ const group = p.showThousands !== false;
36
+ const sep = p.separators ?? 'local';
37
+ if (sep === 'local') {
38
+ return new Intl.NumberFormat(undefined, { minimumFractionDigits: digits, maximumFractionDigits: digits, useGrouping: group }).format(n) + suffix;
39
+ }
40
+ const [th, dec] = SEPARATOR_PAIRS[sep];
41
+ const fixed = Math.abs(n).toFixed(digits);
42
+ const [int, frac] = fixed.split('.');
43
+ const grouped = group ? int.replace(/\B(?=(\d{3})+(?!\d))/g, th) : int;
44
+ return `${n < 0 ? '-' : ''}${grouped}${frac ? dec + frac : ''}${suffix}`;
45
+ }
46
+ /** The thousands and decimal characters a field's `separators` setting means. */
47
+ export function separatorChars(sep = 'local') {
48
+ if (sep !== 'local') {
49
+ const [group, decimal] = SEPARATOR_PAIRS[sep];
50
+ return { group, decimal };
51
+ }
52
+ const parts = new Intl.NumberFormat(undefined, { useGrouping: true }).formatToParts(12345.6);
53
+ return {
54
+ group: parts.find((p) => p.type === 'group')?.value ?? ',',
55
+ decimal: parts.find((p) => p.type === 'decimal')?.value ?? '.',
56
+ };
57
+ }
58
+ const MULTIPLIER = { k: 1e3, m: 1e6, b: 1e9 };
59
+ /**
60
+ * A number from what someone typed into a number, currency or percent cell,
61
+ * read with the field's own separators: "$1,200.50", "1.200,50 €" (with
62
+ * period-comma), "-15%", "2.5k", "3M". The currency symbol, a percent sign and
63
+ * spaces are ignored; a K, M or B suffix multiplies. Null when it is not a
64
+ * number.
65
+ */
66
+ export function parseNumberText(text, p = {}) {
67
+ const { group, decimal } = separatorChars(p.separators);
68
+ let s = text.trim();
69
+ if (p.symbol)
70
+ s = s.split(p.symbol).join('');
71
+ s = s.replace(/[%\s  ]/g, '').replace(/−/g, '-');
72
+ // Accounting style: (5) is -5.
73
+ if (/^\(.*\)$/.test(s))
74
+ s = `-${s.slice(1, -1)}`;
75
+ let mult = 1;
76
+ const suffix = /[kmb]$/i.exec(s);
77
+ if (suffix) {
78
+ mult = MULTIPLIER[suffix[0].toLowerCase()];
79
+ s = s.slice(0, -1);
80
+ }
81
+ if (group.trim())
82
+ s = s.split(group).join('');
83
+ if (decimal !== '.')
84
+ s = s.split(decimal).join('.');
85
+ if (!/^[-+]?(\d+\.?\d*|\.\d+)$/.test(s))
86
+ return null;
87
+ const n = Number(s) * mult;
88
+ return Number.isFinite(n) ? n : null;
89
+ }
90
+ /** Which of the three a number field is: its format, or an older currency / percent column's type. */
91
+ export function numberKind(fieldType, p) {
92
+ if (fieldType === 'currency' || p.format === 'currency')
93
+ return 'currency';
94
+ if (fieldType === 'percent' || p.format === 'percent')
95
+ return 'percent';
96
+ return 'number';
97
+ }
98
+ /**
99
+ * How a number, currency or percent field stores what is typed: `places` to
100
+ * round the typed number to (an integer field: 0), and `scale` between the
101
+ * typed number and the stored one (100 for a percent field holding
102
+ * fractions: 75 typed is 0.75 stored).
103
+ */
104
+ export function numberFieldShape(kind, p) {
105
+ const n = Number(p.precision);
106
+ const ok = Number.isInteger(n) && n >= 0 && n <= 8;
107
+ const places = kind === 'number' ? (p.format === 'integer' ? 0 : ok ? n : 1) : kind === 'currency' ? (ok ? n : 2) : ok ? n : 0;
108
+ return { places, scale: kind === 'percent' && !p.points ? 100 : 1 };
109
+ }
110
+ /** The stored value for typed or pasted text: parsed, rounded, scaled. Null when it is not a number. */
111
+ export function numberFromText(text, kind, p) {
112
+ const n = parseNumberText(text, p);
113
+ if (n == null)
114
+ return null;
115
+ const { places, scale } = numberFieldShape(kind, p);
116
+ const shown = roundTo(n, places);
117
+ return scale === 1 ? shown : Number((shown / scale).toPrecision(12));
118
+ }
119
+ /**
120
+ * Round half away from zero, as people do: 2450.555 to 2 places is 2450.56.
121
+ * toFixed works on the binary value (2450.55499...) and rounds it down.
122
+ */
123
+ export function roundTo(n, places) {
124
+ const f = 10 ** places;
125
+ return (Math.sign(n) * Math.round(Number((Math.abs(n) * f).toPrecision(15)))) / f;
126
+ }
127
+ /**
128
+ * A stored number as the edit box shows it: no grouping, the field's decimal
129
+ * character, and float noise trimmed (0.1 + 0.2 shows 0.3).
130
+ */
131
+ export function numberEditText(value, p = {}) {
132
+ const text = String(Number(value.toPrecision(12)));
133
+ if (/e/i.test(text))
134
+ return text;
135
+ const { decimal } = separatorChars(p.separators);
136
+ return decimal === '.' ? text : text.replace('.', decimal);
137
+ }
138
+ /**
139
+ * Currency: the symbol before the number with the minus before both
140
+ * ("-$5.00"), or after it with a space ("-5,00 €").
141
+ */
142
+ export function formatCurrency(value, p) {
143
+ const symbol = p.symbol ?? '$';
144
+ const body = formatNumber(Math.abs(value), p);
145
+ const sign = value < 0 ? '-' : '';
146
+ if (!symbol)
147
+ return sign + body;
148
+ return p.symbolPosition === 'after' ? `${sign}${body}\u00a0${symbol}` : `${sign}${symbol}${body}`;
149
+ }
150
+ /** Percent: `value` is a fraction (0.75 shows 75%) unless `points` says 0..100. */
151
+ export function formatPercent(value, p) {
152
+ return `${formatNumber(p.points ? value : value * 100, p)}%`;
153
+ }
154
+ /** Seconds as h:mm, h:mm:ss or h:mm:ss with tenths, hundredths or thousandths. */
155
+ export function formatDuration(seconds, format = 'h:mm') {
156
+ const neg = seconds < 0;
157
+ const s = Math.abs(seconds);
158
+ const frac = format.endsWith('.SSS') ? 3 : format.endsWith('.SS') ? 2 : format.endsWith('.S') ? 1 : 0;
159
+ const withSeconds = format !== 'h:mm';
160
+ const scale = 10 ** frac;
161
+ // Round once, at the shown precision, so 59.96 s does not print as 0:59.10.
162
+ const units = withSeconds ? Math.round(s * scale) : Math.round(s / 60) * 60 * scale;
163
+ const totalSeconds = Math.floor(units / scale);
164
+ const h = Math.floor(totalSeconds / 3600);
165
+ const m = Math.floor((totalSeconds % 3600) / 60);
166
+ const sec = totalSeconds % 60;
167
+ let out = `${h}:${String(m).padStart(2, '0')}`;
168
+ if (withSeconds)
169
+ out += `:${String(sec).padStart(2, '0')}`;
170
+ if (frac)
171
+ out += `.${String(units % scale).padStart(frac, '0')}`;
172
+ return (neg ? '-' : '') + out;
173
+ }
174
+ /** "1:30" -> 5400, "1:30:15.5" -> 5415.5, "90" -> 5400 (minutes), "2h 15m" -> 8100. */
175
+ export function parseDuration(text) {
176
+ if (typeof text === 'number')
177
+ return Number.isFinite(text) ? text : null;
178
+ const t = String(text ?? '').trim();
179
+ if (!t)
180
+ return null;
181
+ const units = t.match(/^(?:(\d+(?:\.\d+)?)\s*h)?\s*(?:(\d+(?:\.\d+)?)\s*m(?:in)?)?\s*(?:(\d+(?:\.\d+)?)\s*s)?$/i);
182
+ if (units && (units[1] || units[2] || units[3])) {
183
+ return Number(units[1] ?? 0) * 3600 + Number(units[2] ?? 0) * 60 + Number(units[3] ?? 0);
184
+ }
185
+ const neg = t.startsWith('-');
186
+ const parts = t.replace(/^-/, '').split(':');
187
+ if (parts.length > 3 || parts.some((x) => !/^\d+(\.\d+)?$/.test(x)))
188
+ return null;
189
+ const nums = parts.map(Number);
190
+ const secs = nums.length === 1 ? nums[0] * 60 : nums.length === 2 ? nums[0] * 3600 + nums[1] * 60 : nums[0] * 3600 + nums[1] * 60 + nums[2];
191
+ return neg ? -secs : secs;
192
+ }
193
+ const pad = (n) => String(n).padStart(2, '0');
194
+ export function toDate(value) {
195
+ if (value == null || value === '')
196
+ return null;
197
+ if (value instanceof Date)
198
+ return Number.isNaN(value.getTime()) ? null : value;
199
+ // A bare YYYY-MM-DD is a calendar date: read it in local time, not as UTC
200
+ // midnight, so it does not show as the day before west of Greenwich.
201
+ if (typeof value === 'string' && /^\d{4}-\d{2}-\d{2}$/.test(value)) {
202
+ const [y, m, d] = value.split('-').map(Number);
203
+ return new Date(y, m - 1, d);
204
+ }
205
+ const d = new Date(value);
206
+ return Number.isNaN(d.getTime()) ? null : d;
207
+ }
208
+ /**
209
+ * The date editor's text format (the grid's date-format tokens) for a date
210
+ * field, so an edit shows the date as the cell does: "MMMM d, yyyy" for
211
+ * friendly in English, "M/d/yyyy" for US. Local and friendly follow `Intl`,
212
+ * read from the parts it gives for a sample date.
213
+ */
214
+ export function dateEditTokens(p) {
215
+ let date;
216
+ switch (p.dateFormat ?? 'local') {
217
+ case 'us':
218
+ date = 'M/d/yyyy';
219
+ break;
220
+ case 'european':
221
+ date = 'd/M/yyyy';
222
+ break;
223
+ case 'iso':
224
+ date = 'yyyy-MM-dd';
225
+ break;
226
+ default: {
227
+ const long = p.dateFormat === 'friendly';
228
+ // 5 January: a padded part shows as "05", a long month as a name.
229
+ const parts = new Intl.DateTimeFormat(undefined, { year: 'numeric', month: long ? 'long' : 'numeric', day: 'numeric' }).formatToParts(new Date(2026, 0, 5));
230
+ date = parts
231
+ .map((x) => {
232
+ if (x.type === 'year')
233
+ return 'yyyy';
234
+ if (x.type === 'month')
235
+ return long ? 'MMMM' : x.value.length === 2 ? 'MM' : 'M';
236
+ if (x.type === 'day')
237
+ return x.value.length === 2 ? 'dd' : 'd';
238
+ // Literal text: quoted when it has letters, so they are not tokens.
239
+ return /[a-z]/i.test(x.value) ? `'${x.value}'` : x.value;
240
+ })
241
+ .join('');
242
+ }
243
+ }
244
+ if (!p.time)
245
+ return date;
246
+ return `${date} ${p.timeFormat === '24hour' ? 'HH:mm' : 'h:mm tt'}`;
247
+ }
248
+ export function formatDate(value, p) {
249
+ const d = toDate(value);
250
+ if (!d)
251
+ return '';
252
+ const utc = !!p.gmt;
253
+ const y = utc ? d.getUTCFullYear() : d.getFullYear();
254
+ const mo = utc ? d.getUTCMonth() : d.getMonth();
255
+ const day = utc ? d.getUTCDate() : d.getDate();
256
+ let date;
257
+ switch (p.dateFormat ?? 'local') {
258
+ case 'friendly':
259
+ date = new Intl.DateTimeFormat(undefined, { year: 'numeric', month: 'long', day: 'numeric', timeZone: utc ? 'UTC' : undefined }).format(d);
260
+ break;
261
+ case 'us':
262
+ date = `${mo + 1}/${day}/${y}`;
263
+ break;
264
+ case 'european':
265
+ date = `${day}/${mo + 1}/${y}`;
266
+ break;
267
+ case 'iso':
268
+ date = `${y}-${pad(mo + 1)}-${pad(day)}`;
269
+ break;
270
+ default:
271
+ date = new Intl.DateTimeFormat(undefined, { year: 'numeric', month: 'numeric', day: 'numeric', timeZone: utc ? 'UTC' : undefined }).format(d);
272
+ }
273
+ if (!p.time)
274
+ return date;
275
+ const h = utc ? d.getUTCHours() : d.getHours();
276
+ const mi = utc ? d.getUTCMinutes() : d.getMinutes();
277
+ const time = p.timeFormat === '24hour' ? `${pad(h)}:${pad(mi)}` : `${((h + 11) % 12) + 1}:${pad(mi)}${h < 12 ? 'am' : 'pm'}`;
278
+ const zone = p.showTimeZone ? ` ${utc ? 'GMT' : localZoneName(d)}` : '';
279
+ return `${date} ${time}${zone}`;
280
+ }
281
+ function localZoneName(d) {
282
+ try {
283
+ return new Intl.DateTimeFormat(undefined, { timeZoneName: 'short' }).formatToParts(d).find((x) => x.type === 'timeZoneName')?.value ?? '';
284
+ }
285
+ catch {
286
+ return '';
287
+ }
288
+ }
@@ -0,0 +1,50 @@
1
+ export type FormulaValue = number | string | boolean | Date | null | FormulaValue[];
2
+ export type FormulaFn = (row: Record<string, unknown>) => FormulaValue;
3
+ export declare class FormulaError extends Error {
4
+ }
5
+ /**
6
+ * Text written the way a date field or a timestamp stores it (2026-12-04,
7
+ * 2026-12-04T10:30:00Z) as that date; any other text is not a date. A bare
8
+ * YYYY-MM-DD is that day at local midnight, as format.ts reads it.
9
+ */
10
+ export declare function isoDate(text: string): Date | null;
11
+ /** The functions a formula may call, for the editor's help line. */
12
+ export declare const FORMULA_FUNCTIONS: string[];
13
+ /** Resolve a `{Field name}` to the row key it reads. */
14
+ export type FieldResolver = (name: string) => string | null;
15
+ /** The message for a formula that names the field it belongs to. */
16
+ export declare const selfReferenceError: (name: string) => FormulaError;
17
+ /**
18
+ * A resolver over columns: a name matches a header or a field key, ignoring
19
+ * case and outer spaces. `self` lists the names of the formula's own field
20
+ * (its key, its header, a header being typed): naming one is an error.
21
+ */
22
+ export declare function columnResolver(columns: ReadonlyArray<Record<string, unknown>>, self?: ReadonlyArray<unknown>): FieldResolver;
23
+ /** Compile a formula. Throws FormulaError with a message for the user. */
24
+ export declare function compileFormula(src: string, resolve: FieldResolver): {
25
+ fn: FormulaFn;
26
+ refs: string[];
27
+ };
28
+ /**
29
+ * The formula with each `{name}` that `rename` gives a new name for written
30
+ * as `{new name}`. Braces inside text ("{x}") are left alone; a formula that
31
+ * does not tokenize comes back as it was.
32
+ */
33
+ export declare function renameFormulaRefs(src: string, rename: (name: string) => string | null): string;
34
+ /**
35
+ * The keys of the fields a formula names, as `resolve` reads them. Unlike
36
+ * `compileFormula` it does not stop at a name no field has or at a mistake
37
+ * elsewhere in the formula; a formula that does not tokenize names nothing.
38
+ */
39
+ export declare function formulaRefs(src: string, resolve: FieldResolver): string[];
40
+ /**
41
+ * The formula fields among `columns` that read the field `field` (its key or
42
+ * id): deleting it turns their cells to #ERROR. Names resolve against
43
+ * `columns`, as the field editor resolves them.
44
+ */
45
+ export declare function formulaReaders<T extends Record<string, any>>(columns: ReadonlyArray<T>, field: {
46
+ field?: unknown;
47
+ id?: unknown;
48
+ }): T[];
49
+ /** The formula's message if it does not compile, else null. */
50
+ export declare function formulaError(src: string, resolve: FieldResolver): string | null;