@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.
- package/README.md +1 -0
- package/dist/SvAlertRuleEditor.svelte +16 -5
- package/dist/SvGridAlerts.svelte +8 -0
- package/dist/SvGridAlerts.svelte.d.ts +4 -0
- package/dist/SvGridBoard.svelte +69 -10
- package/dist/SvGridBulkEditDrawer.svelte +13 -5
- package/dist/SvGridGallery.svelte +286 -0
- package/dist/SvGridGallery.svelte.d.ts +30 -0
- package/dist/SvGridScheduler.svelte +33 -11
- package/dist/SvGridSelectionBar.svelte +47 -0
- package/dist/advanced-filter/expr-columns-from-grid.d.ts +1 -0
- package/dist/advanced-filter/expr-columns-from-grid.js +11 -7
- package/dist/advanced-filter-enable.d.ts +6 -0
- package/dist/advanced-filter-enable.js +8 -0
- package/dist/alerts/alert-engine.d.ts +7 -0
- package/dist/alerts/alert-engine.js +5 -2
- package/dist/alerts/condition-editor.d.ts +26 -0
- package/dist/alerts/condition-editor.js +17 -0
- package/dist/base/index.d.ts +20 -0
- package/dist/base/index.js +20 -0
- package/dist/bulk-edit.d.ts +11 -0
- package/dist/bulk-edit.js +18 -1
- package/dist/cdn/svgrid-enterprise.svelte-external.js +11197 -10639
- package/dist/designer/assets/GridFooter-Cu8_yBlQ.js +2 -0
- package/dist/designer/assets/GridMenus-BUjkkAU2.js +6 -0
- package/dist/designer/assets/PinSplitter-BgTpgh1d.css +1 -0
- package/dist/designer/assets/PinSplitter-C5AwA1xV.js +1 -0
- package/dist/designer/assets/SvGrid.helpers-CIrmIo9U.js +1 -0
- package/dist/designer/assets/SvGridCellEditor-CJxThKL_.js +4 -0
- package/dist/designer/assets/SvListBox-CS7oUAiX.js +2 -0
- package/dist/designer/assets/conditional-formatting-MDWbF8_Y.js +1 -0
- package/dist/designer/assets/grid-extension.svelte-BZ7AqyJI.js +1 -0
- package/dist/designer/assets/{index-Obk8sI77.js → index-BPU2KNc5.js} +307 -307
- package/dist/designer/assets/index-BmvG99kR.css +1 -0
- package/dist/designer/assets/sparkline-C-NcnB2i.js +1 -0
- package/dist/designer/assets/src-C_U1NKOY.js +58 -0
- package/dist/designer/assets/sv-grid-scrollbar-B9N6Wuj0.js +109 -0
- package/dist/designer/assets/validate-H5u2HEQh.js +1 -0
- package/dist/designer/index.html +11 -7
- package/dist/expressions/compile.js +10 -0
- package/dist/expressions/evaluate.js +18 -0
- package/dist/expressions/expression-types.d.ts +10 -0
- package/dist/expressions/kinds.d.ts +28 -0
- package/dist/expressions/kinds.js +19 -0
- package/dist/expressions/parse.js +9 -1
- package/dist/fields/AttachmentCell.svelte +242 -0
- package/dist/fields/AttachmentCell.svelte.d.ts +5 -0
- package/dist/fields/AttachmentDialog.svelte +357 -0
- package/dist/fields/AttachmentDialog.svelte.d.ts +13 -0
- package/dist/fields/AttachmentEditor.svelte +41 -0
- package/dist/fields/AttachmentEditor.svelte.d.ts +11 -0
- package/dist/fields/AttachmentPreview.svelte +72 -0
- package/dist/fields/AttachmentPreview.svelte.d.ts +8 -0
- package/dist/fields/BarcodeCell.svelte +20 -0
- package/dist/fields/BarcodeCell.svelte.d.ts +5 -0
- package/dist/fields/BaseAutomations.svelte +558 -0
- package/dist/fields/BaseAutomations.svelte.d.ts +18 -0
- package/dist/fields/BaseChartView.svelte +47 -0
- package/dist/fields/BaseChartView.svelte.d.ts +8 -0
- package/dist/fields/BaseTableView.svelte +185 -0
- package/dist/fields/BaseTableView.svelte.d.ts +37 -0
- package/dist/fields/BaseTabs.svelte +308 -0
- package/dist/fields/BaseTabs.svelte.d.ts +21 -0
- package/dist/fields/ButtonCell.svelte +47 -0
- package/dist/fields/ButtonCell.svelte.d.ts +20 -0
- package/dist/fields/CheckboxCell.svelte +46 -0
- package/dist/fields/CheckboxCell.svelte.d.ts +14 -0
- package/dist/fields/DeleteFieldConfirm.svelte +80 -0
- package/dist/fields/DeleteFieldConfirm.svelte.d.ts +8 -0
- package/dist/fields/DeleteRecordConfirm.svelte +48 -0
- package/dist/fields/DeleteRecordConfirm.svelte.d.ts +9 -0
- package/dist/fields/FieldCell.svelte +80 -0
- package/dist/fields/FieldCell.svelte.d.ts +9 -0
- package/dist/fields/FieldEditor.svelte +321 -0
- package/dist/fields/FieldEditor.svelte.d.ts +10 -0
- package/dist/fields/FieldInput.svelte +188 -0
- package/dist/fields/FieldInput.svelte.d.ts +29 -0
- package/dist/fields/FieldsHeaderEnd.svelte +146 -0
- package/dist/fields/FieldsHeaderEnd.svelte.d.ts +6 -0
- package/dist/fields/FootRowAdder.svelte +8 -0
- package/dist/fields/FootRowAdder.svelte.d.ts +6 -0
- package/dist/fields/GroupHeader.svelte +127 -0
- package/dist/fields/GroupHeader.svelte.d.ts +24 -0
- package/dist/fields/LinkCell.svelte +46 -0
- package/dist/fields/LinkCell.svelte.d.ts +9 -0
- package/dist/fields/LinkPickerEditor.svelte +172 -0
- package/dist/fields/LinkPickerEditor.svelte.d.ts +9 -0
- package/dist/fields/LinkPreview.svelte +60 -0
- package/dist/fields/LinkPreview.svelte.d.ts +7 -0
- package/dist/fields/LinkedRecordView.svelte +94 -0
- package/dist/fields/LinkedRecordView.svelte.d.ts +9 -0
- package/dist/fields/LinkedRecordsCell.svelte +59 -0
- package/dist/fields/LinkedRecordsCell.svelte.d.ts +11 -0
- package/dist/fields/LongTextEditor.svelte +157 -0
- package/dist/fields/LongTextEditor.svelte.d.ts +11 -0
- package/dist/fields/NumberEditor.svelte +309 -0
- package/dist/fields/NumberEditor.svelte.d.ts +12 -0
- package/dist/fields/OptionsEditor.svelte +117 -0
- package/dist/fields/OptionsEditor.svelte.d.ts +11 -0
- package/dist/fields/PercentCell.svelte +21 -0
- package/dist/fields/PercentCell.svelte.d.ts +8 -0
- package/dist/fields/PropertyInput.svelte +204 -0
- package/dist/fields/PropertyInput.svelte.d.ts +11 -0
- package/dist/fields/RatingCell.svelte +75 -0
- package/dist/fields/RatingCell.svelte.d.ts +16 -0
- package/dist/fields/RatingEditor.svelte +82 -0
- package/dist/fields/RatingEditor.svelte.d.ts +9 -0
- package/dist/fields/RecordView.svelte +310 -0
- package/dist/fields/RecordView.svelte.d.ts +11 -0
- package/dist/fields/RichTextCell.svelte +30 -0
- package/dist/fields/RichTextCell.svelte.d.ts +5 -0
- package/dist/fields/RowAdder.svelte +93 -0
- package/dist/fields/RowAdder.svelte.d.ts +7 -0
- package/dist/fields/RowHeader.svelte +99 -0
- package/dist/fields/RowHeader.svelte.d.ts +11 -0
- package/dist/fields/SelectCell.svelte +35 -0
- package/dist/fields/SelectCell.svelte.d.ts +15 -0
- package/dist/fields/SelectEditor.svelte +350 -0
- package/dist/fields/SelectEditor.svelte.d.ts +17 -0
- package/dist/fields/SummaryCell.svelte +160 -0
- package/dist/fields/SummaryCell.svelte.d.ts +11 -0
- package/dist/fields/SvBase.svelte +545 -0
- package/dist/fields/SvBase.svelte.d.ts +30 -0
- package/dist/fields/SvBaseForm.svelte +295 -0
- package/dist/fields/SvBaseForm.svelte.d.ts +22 -0
- package/dist/fields/SvBaseViewBar.svelte +644 -0
- package/dist/fields/SvBaseViewBar.svelte.d.ts +26 -0
- package/dist/fields/UserCell.svelte +39 -0
- package/dist/fields/UserCell.svelte.d.ts +9 -0
- package/dist/fields/UserFace.svelte +30 -0
- package/dist/fields/UserFace.svelte.d.ts +12 -0
- package/dist/fields/activity.svelte.d.ts +50 -0
- package/dist/fields/activity.svelte.js +110 -0
- package/dist/fields/attachments.d.ts +95 -0
- package/dist/fields/attachments.js +145 -0
- package/dist/fields/automation-outbound.d.ts +46 -0
- package/dist/fields/automation-outbound.js +61 -0
- package/dist/fields/automation-server.d.ts +53 -0
- package/dist/fields/automation-server.js +333 -0
- package/dist/fields/automations.svelte.d.ts +208 -0
- package/dist/fields/automations.svelte.js +437 -0
- package/dist/fields/bar-request.svelte.d.ts +16 -0
- package/dist/fields/bar-request.svelte.js +15 -0
- package/dist/fields/base-alerts.d.ts +24 -0
- package/dist/fields/base-alerts.js +64 -0
- package/dist/fields/base-connect.d.ts +82 -0
- package/dist/fields/base-connect.js +271 -0
- package/dist/fields/base-schema.d.ts +104 -0
- package/dist/fields/base-schema.js +266 -0
- package/dist/fields/base-sql.d.ts +62 -0
- package/dist/fields/base-sql.js +251 -0
- package/dist/fields/base-sync.d.ts +142 -0
- package/dist/fields/base-sync.js +499 -0
- package/dist/fields/base-tables.d.ts +89 -0
- package/dist/fields/base-tables.js +349 -0
- package/dist/fields/builtin-types.d.ts +13 -0
- package/dist/fields/builtin-types.js +773 -0
- package/dist/fields/button.d.ts +2 -0
- package/dist/fields/button.js +17 -0
- package/dist/fields/chart-view.d.ts +35 -0
- package/dist/fields/chart-view.js +154 -0
- package/dist/fields/column-order.d.ts +6 -0
- package/dist/fields/column-order.js +12 -0
- package/dist/fields/convert.d.ts +16 -0
- package/dist/fields/convert.js +176 -0
- package/dist/fields/copy-text.d.ts +13 -0
- package/dist/fields/copy-text.js +45 -0
- package/dist/fields/editor-request.svelte.d.ts +71 -0
- package/dist/fields/editor-request.svelte.js +52 -0
- package/dist/fields/field-ops.d.ts +72 -0
- package/dist/fields/field-ops.js +334 -0
- package/dist/fields/filter-model.d.ts +84 -0
- package/dist/fields/filter-model.js +446 -0
- package/dist/fields/format.d.ts +109 -0
- package/dist/fields/format.js +288 -0
- package/dist/fields/formula.d.ts +50 -0
- package/dist/fields/formula.js +530 -0
- package/dist/fields/grid-access.d.ts +60 -0
- package/dist/fields/grid-access.js +120 -0
- package/dist/fields/index.d.ts +34 -0
- package/dist/fields/index.js +312 -0
- package/dist/fields/linked-fields.d.ts +8 -0
- package/dist/fields/linked-fields.js +40 -0
- package/dist/fields/links.d.ts +10 -0
- package/dist/fields/links.js +46 -0
- package/dist/fields/name-list.d.ts +16 -0
- package/dist/fields/name-list.js +49 -0
- package/dist/fields/palette.d.ts +47 -0
- package/dist/fields/palette.js +69 -0
- package/dist/fields/record-delete.svelte.d.ts +12 -0
- package/dist/fields/record-delete.svelte.js +5 -0
- package/dist/fields/record-menu.d.ts +9 -0
- package/dist/fields/record-menu.js +78 -0
- package/dist/fields/registry.svelte.d.ts +176 -0
- package/dist/fields/registry.svelte.js +51 -0
- package/dist/fields/rich-text.d.ts +23 -0
- package/dist/fields/rich-text.js +48 -0
- package/dist/fields/row-color-choice.svelte.d.ts +31 -0
- package/dist/fields/row-color-choice.svelte.js +25 -0
- package/dist/fields/row-colors.d.ts +36 -0
- package/dist/fields/row-colors.js +90 -0
- package/dist/fields/row-height.d.ts +28 -0
- package/dist/fields/row-height.js +50 -0
- package/dist/fields/sources.svelte.d.ts +80 -0
- package/dist/fields/sources.svelte.js +131 -0
- package/dist/fields/summaries.d.ts +18 -0
- package/dist/fields/summaries.js +138 -0
- package/dist/fields/view-model.d.ts +129 -0
- package/dist/fields/view-model.js +492 -0
- package/dist/fields/viewbar/ChartPanel.svelte +61 -0
- package/dist/fields/viewbar/ChartPanel.svelte.d.ts +9 -0
- package/dist/fields/viewbar/ColorPanel.svelte +112 -0
- package/dist/fields/viewbar/ColorPanel.svelte.d.ts +9 -0
- package/dist/fields/viewbar/ConditionValue.svelte +153 -0
- package/dist/fields/viewbar/ConditionValue.svelte.d.ts +15 -0
- package/dist/fields/viewbar/FieldIcon.svelte +18 -0
- package/dist/fields/viewbar/FieldIcon.svelte.d.ts +9 -0
- package/dist/fields/viewbar/FilterPanel.svelte +192 -0
- package/dist/fields/viewbar/FilterPanel.svelte.d.ts +13 -0
- package/dist/fields/viewbar/GanttPanel.svelte +60 -0
- package/dist/fields/viewbar/GanttPanel.svelte.d.ts +10 -0
- package/dist/fields/viewbar/HideFieldsPanel.svelte +104 -0
- package/dist/fields/viewbar/HideFieldsPanel.svelte.d.ts +7 -0
- package/dist/fields/viewbar/SortPanel.svelte +85 -0
- package/dist/fields/viewbar/SortPanel.svelte.d.ts +8 -0
- package/dist/fields/viewbar/ViewsMenu.svelte +250 -0
- package/dist/fields/viewbar/ViewsMenu.svelte.d.ts +15 -0
- package/dist/fields/viewbar/panel-focus.d.ts +3 -0
- package/dist/fields/viewbar/panel-focus.js +22 -0
- package/dist/fields/viewbar/sort-state.d.ts +20 -0
- package/dist/fields/viewbar/sort-state.js +24 -0
- package/dist/gallery.d.ts +7 -0
- package/dist/gallery.js +36 -0
- package/dist/gantt/SvGridGantt.svelte +88 -16
- package/dist/gantt/gantt-config.d.ts +28 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +6 -0
- package/dist/install.js +3 -0
- package/dist/license-core.d.ts +3 -3
- package/dist/license.js +1 -0
- package/dist/node/studio.js +105 -4
- package/dist/scheduler-config.d.ts +11 -0
- package/dist/sources/introspect-supabase.js +4 -1
- package/dist/sources/rest.js +6 -2
- package/dist/studio/ui-components.generated.js +93 -1
- package/dist/upgrade-prompt.d.ts +1 -1
- package/dist/version.d.ts +2 -2
- package/dist/version.js +2 -2
- package/dist/wc/GridFooter-f5K0aLe_.js +145 -0
- package/dist/wc/GridMenus-FtSN_8t9.js +1369 -0
- package/dist/wc/PinSplitter-D-qtDhSM.js +132 -0
- package/dist/wc/{SvGrid.helpers-zBkDTryR.js → SvGrid.helpers-B2GEKrxS.js} +84 -36
- package/dist/wc/{SvGridCellEditor-CzUKEbkI.js → SvGridCellEditor-B_cLJrsp.js} +20 -9
- package/dist/wc/conditional-formatting-BXis_oP1.js +189 -0
- package/dist/wc/grid-extension.svelte-Bufq4B4C.js +20 -0
- package/dist/wc/sv-sheet-element.js +7556 -7617
- package/dist/wc/svelte-virtualizer.svelte-ehwOupl-.js +360 -0
- package/dist/wc/{validate-43C03DLP.js → validate-BaMO8UPE.js} +1 -1
- package/package.json +14 -3
- package/dist/designer/assets/GridMenus-CvcASlKv.js +0 -8
- package/dist/designer/assets/SvGrid.helpers-DE5mmORW.js +0 -1
- package/dist/designer/assets/SvGridCellEditor-C7NWcnNC.js +0 -4
- package/dist/designer/assets/SvListBox-BlmmzYcU.js +0 -110
- package/dist/designer/assets/index-KmSEY7Lb.css +0 -1
- package/dist/designer/assets/src-DqHCqori.js +0 -58
- package/dist/designer/assets/validate-B71dE1Cs.js +0 -1
- package/dist/wc/GridMenus-fWbBUiRH.js +0 -1088
- package/dist/wc/svelte-virtualizer.svelte-Dntdh8Ms.js +0 -581
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The view bar's filter: conditions on fields, each with the operators that
|
|
3
|
+
* fit its type ("has any of" for a multiple select, "is within the past
|
|
4
|
+
* week" for a date), joined by "and" or "or", one level of groups deep.
|
|
5
|
+
*
|
|
6
|
+
* It is the grid's advanced filter (`api.setAdvancedFilter`) with its own
|
|
7
|
+
* expression kind, `fieldFilter`, so it is saved and restored with the rest
|
|
8
|
+
* of the grid's state.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* A person condition's value meaning whoever is signed in (`setCurrentUser`)
|
|
12
|
+
* when the filter runs, so one "My tasks" view works for everyone. With
|
|
13
|
+
* nobody signed in it matches no one.
|
|
14
|
+
*/
|
|
15
|
+
export const ME = '@me';
|
|
16
|
+
// Who `ME` is. `enableFields` points it at the signed-in user; this module
|
|
17
|
+
// stays free of Svelte state so it runs anywhere (the server runner too).
|
|
18
|
+
let currentUserId = () => undefined;
|
|
19
|
+
export function resolveMeWith(fn) {
|
|
20
|
+
currentUserId = fn;
|
|
21
|
+
}
|
|
22
|
+
export const isGroup = (c) => Array.isArray(c.conditions);
|
|
23
|
+
const TEXT_TYPES = new Set(['text', 'longText', 'url', 'email', 'phone', 'barcode']);
|
|
24
|
+
const NUMBER_TYPES = new Set(['number', 'currency', 'percent', 'rating', 'duration', 'autoNumber', 'count']);
|
|
25
|
+
const DATE_TYPES = new Set(['date', 'createdTime', 'lastModifiedTime']);
|
|
26
|
+
// Their values are whatever they compute, so the column's cellDataType says what they compare as.
|
|
27
|
+
// A numeric rollup (SUM, COUNT...) has cellDataType 'number'; one without it
|
|
28
|
+
// is a list joined as text (ARRAYJOIN, CONCATENATE), or AND / OR, a checkbox.
|
|
29
|
+
const COMPUTED_TYPES = { formula: 'text', lookup: 'text', rollup: 'text' };
|
|
30
|
+
const BOOLEAN_ROLLUPS = new Set(['AND', 'OR']);
|
|
31
|
+
/** What a column's cellDataType compares as, or null when it does not say. */
|
|
32
|
+
function kindOfData(def) {
|
|
33
|
+
const d = def.cellDataType;
|
|
34
|
+
if (d === 'number')
|
|
35
|
+
return 'number';
|
|
36
|
+
if (d === 'date' || d === 'dateString')
|
|
37
|
+
return 'date';
|
|
38
|
+
if (d === 'boolean')
|
|
39
|
+
return 'checkbox';
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* The kind of comparison a column gets; null for one that cannot be filtered
|
|
44
|
+
* (a button). A built-in type decides it; a computed type (formula, lookup,
|
|
45
|
+
* rollup), a type the app registered, and a plain column follow the
|
|
46
|
+
* column's cellDataType, as the footer summaries do.
|
|
47
|
+
*/
|
|
48
|
+
export function filterKindOf(def) {
|
|
49
|
+
const t = def.fieldType;
|
|
50
|
+
if (t === 'button')
|
|
51
|
+
return null;
|
|
52
|
+
if (t === 'singleSelect')
|
|
53
|
+
return 'select';
|
|
54
|
+
if (t === 'multiSelect')
|
|
55
|
+
return 'multi';
|
|
56
|
+
if (t === 'user' || t === 'createdBy' || t === 'lastModifiedBy')
|
|
57
|
+
return def.fieldProps?.multiple ? 'multi' : 'select';
|
|
58
|
+
if (t === 'checkbox')
|
|
59
|
+
return 'checkbox';
|
|
60
|
+
if (t === 'attachment')
|
|
61
|
+
return 'files';
|
|
62
|
+
if (t === 'link')
|
|
63
|
+
return 'link';
|
|
64
|
+
if (t && DATE_TYPES.has(t))
|
|
65
|
+
return 'date';
|
|
66
|
+
if (t && NUMBER_TYPES.has(t))
|
|
67
|
+
return 'number';
|
|
68
|
+
if (t && TEXT_TYPES.has(t))
|
|
69
|
+
return 'text';
|
|
70
|
+
if (t === 'rollup' && !def.cellDataType && BOOLEAN_ROLLUPS.has(String(def.fieldProps?.aggregation)))
|
|
71
|
+
return 'checkbox';
|
|
72
|
+
// A formula formatted as a number or a date compares as one, as its footer summaries do.
|
|
73
|
+
const result = t === 'formula' ? def.fieldProps?.result : undefined;
|
|
74
|
+
if (result === 'number' || result === 'currency' || result === 'percent')
|
|
75
|
+
return 'number';
|
|
76
|
+
if (result === 'date')
|
|
77
|
+
return 'date';
|
|
78
|
+
return kindOfData(def) ?? (t ? COMPUTED_TYPES[t] : undefined) ?? 'text';
|
|
79
|
+
}
|
|
80
|
+
const EMPTY_OPS = [
|
|
81
|
+
{ op: 'isEmpty', label: 'is empty' },
|
|
82
|
+
{ op: 'isNotEmpty', label: 'is not empty' },
|
|
83
|
+
];
|
|
84
|
+
/** The operators a kind offers, in the order the menu shows them. */
|
|
85
|
+
export function operatorsFor(kind) {
|
|
86
|
+
switch (kind) {
|
|
87
|
+
case 'number':
|
|
88
|
+
return [
|
|
89
|
+
{ op: 'eq', label: '=' },
|
|
90
|
+
{ op: 'neq', label: '≠' },
|
|
91
|
+
{ op: 'lt', label: '<' },
|
|
92
|
+
{ op: 'gt', label: '>' },
|
|
93
|
+
{ op: 'lte', label: '≤' },
|
|
94
|
+
{ op: 'gte', label: '≥' },
|
|
95
|
+
...EMPTY_OPS,
|
|
96
|
+
];
|
|
97
|
+
case 'select':
|
|
98
|
+
return [
|
|
99
|
+
{ op: 'is', label: 'is' },
|
|
100
|
+
{ op: 'isNot', label: 'is not' },
|
|
101
|
+
{ op: 'isAnyOf', label: 'is any of' },
|
|
102
|
+
{ op: 'isNoneOf', label: 'is none of' },
|
|
103
|
+
...EMPTY_OPS,
|
|
104
|
+
];
|
|
105
|
+
case 'multi':
|
|
106
|
+
return [
|
|
107
|
+
{ op: 'hasAnyOf', label: 'has any of' },
|
|
108
|
+
{ op: 'hasAllOf', label: 'has all of' },
|
|
109
|
+
{ op: 'isExactly', label: 'is exactly' },
|
|
110
|
+
{ op: 'hasNoneOf', label: 'has none of' },
|
|
111
|
+
...EMPTY_OPS,
|
|
112
|
+
];
|
|
113
|
+
case 'checkbox':
|
|
114
|
+
return [{ op: 'is', label: 'is' }];
|
|
115
|
+
case 'date':
|
|
116
|
+
return [
|
|
117
|
+
{ op: 'is', label: 'is' },
|
|
118
|
+
{ op: 'isBefore', label: 'is before' },
|
|
119
|
+
{ op: 'isAfter', label: 'is after' },
|
|
120
|
+
{ op: 'isOnOrBefore', label: 'is on or before' },
|
|
121
|
+
{ op: 'isOnOrAfter', label: 'is on or after' },
|
|
122
|
+
{ op: 'isWithin', label: 'is within' },
|
|
123
|
+
...EMPTY_OPS,
|
|
124
|
+
];
|
|
125
|
+
case 'files':
|
|
126
|
+
return [{ op: 'contains', label: 'file name contains' }, ...EMPTY_OPS];
|
|
127
|
+
case 'link':
|
|
128
|
+
case 'text':
|
|
129
|
+
return [
|
|
130
|
+
{ op: 'contains', label: 'contains' },
|
|
131
|
+
{ op: 'notContains', label: 'does not contain' },
|
|
132
|
+
{ op: 'is', label: 'is' },
|
|
133
|
+
{ op: 'isNot', label: 'is not' },
|
|
134
|
+
...EMPTY_OPS,
|
|
135
|
+
];
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/** The value a new condition starts with for an operator. */
|
|
139
|
+
export function defaultValue(kind, op) {
|
|
140
|
+
if (op === 'isEmpty' || op === 'isNotEmpty')
|
|
141
|
+
return undefined;
|
|
142
|
+
if (kind === 'checkbox')
|
|
143
|
+
return true;
|
|
144
|
+
if (kind === 'date')
|
|
145
|
+
return op === 'isWithin' ? { span: 'pastWeek' } : { mode: 'today' };
|
|
146
|
+
if (kind === 'select' && (op === 'is' || op === 'isNot'))
|
|
147
|
+
return '';
|
|
148
|
+
if (kind === 'select' || kind === 'multi')
|
|
149
|
+
return [];
|
|
150
|
+
return '';
|
|
151
|
+
}
|
|
152
|
+
/** A new condition on a column, with its first operator. */
|
|
153
|
+
export function newCondition(column, def) {
|
|
154
|
+
const kind = filterKindOf(def);
|
|
155
|
+
if (!kind)
|
|
156
|
+
return null;
|
|
157
|
+
const op = operatorsFor(kind)[0].op;
|
|
158
|
+
const table = kind === 'link' && typeof def.fieldProps?.table === 'string' ? def.fieldProps.table : undefined;
|
|
159
|
+
return { column, kind, op, value: defaultValue(kind, op), ...(table ? { table } : {}) };
|
|
160
|
+
}
|
|
161
|
+
/** Whether a condition says enough to filter: an empty value is a condition still being written. */
|
|
162
|
+
export function isComplete(c) {
|
|
163
|
+
if (c.op === 'isEmpty' || c.op === 'isNotEmpty' || c.kind === 'checkbox')
|
|
164
|
+
return true;
|
|
165
|
+
const v = c.value;
|
|
166
|
+
if (v == null)
|
|
167
|
+
return false;
|
|
168
|
+
if (Array.isArray(v))
|
|
169
|
+
return v.length > 0;
|
|
170
|
+
if (typeof v === 'string')
|
|
171
|
+
return v.trim() !== '';
|
|
172
|
+
if (c.kind === 'date' && typeof v === 'object') {
|
|
173
|
+
const t = v;
|
|
174
|
+
if (t.mode === 'exactDate')
|
|
175
|
+
return !!t.date;
|
|
176
|
+
if (t.span === 'pastDays' || t.span === 'nextDays')
|
|
177
|
+
return Number(t.days) > 0;
|
|
178
|
+
}
|
|
179
|
+
return true;
|
|
180
|
+
}
|
|
181
|
+
/** How many complete conditions a filter has (the view bar's count). */
|
|
182
|
+
export function conditionCount(filter) {
|
|
183
|
+
if (!filter)
|
|
184
|
+
return 0;
|
|
185
|
+
let n = 0;
|
|
186
|
+
for (const c of filter.conditions) {
|
|
187
|
+
if (isGroup(c))
|
|
188
|
+
n += c.conditions.filter(isComplete).length;
|
|
189
|
+
else if (isComplete(c))
|
|
190
|
+
n += 1;
|
|
191
|
+
}
|
|
192
|
+
return n;
|
|
193
|
+
}
|
|
194
|
+
const fold = (s) => String(s ?? '').trim().toLocaleLowerCase();
|
|
195
|
+
const list = (v) => v == null || v === '' ? [] : Array.isArray(v) ? v.map((x) => String(x && typeof x === 'object' ? (x.id ?? x.name ?? '') : x)) : [String(v)];
|
|
196
|
+
const isBlank = (v) => v == null || v === '' || (Array.isArray(v) && v.length === 0) || (typeof v === 'number' && Number.isNaN(v));
|
|
197
|
+
const DAY = 86400000;
|
|
198
|
+
/** A value's day as a count of local days, or null. */
|
|
199
|
+
export function dayOf(v) {
|
|
200
|
+
if (v == null || v === '')
|
|
201
|
+
return null;
|
|
202
|
+
let d;
|
|
203
|
+
if (v instanceof Date)
|
|
204
|
+
d = v;
|
|
205
|
+
else if (typeof v === 'number')
|
|
206
|
+
d = new Date(v);
|
|
207
|
+
else {
|
|
208
|
+
const s = String(v);
|
|
209
|
+
// A bare date is that day where the user is, not midnight UTC.
|
|
210
|
+
const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(s);
|
|
211
|
+
d = m ? new Date(Number(m[1]), Number(m[2]) - 1, Number(m[3])) : new Date(s);
|
|
212
|
+
}
|
|
213
|
+
if (Number.isNaN(d.getTime()))
|
|
214
|
+
return null;
|
|
215
|
+
return Math.floor((d.getTime() - d.getTimezoneOffset() * 60000) / DAY);
|
|
216
|
+
}
|
|
217
|
+
function targetDay(t, today) {
|
|
218
|
+
switch (t.mode) {
|
|
219
|
+
case 'today':
|
|
220
|
+
return today;
|
|
221
|
+
case 'tomorrow':
|
|
222
|
+
return today + 1;
|
|
223
|
+
case 'yesterday':
|
|
224
|
+
return today - 1;
|
|
225
|
+
case 'oneWeekAgo':
|
|
226
|
+
return today - 7;
|
|
227
|
+
case 'oneWeekFromNow':
|
|
228
|
+
return today + 7;
|
|
229
|
+
case 'oneMonthAgo':
|
|
230
|
+
return today - 30;
|
|
231
|
+
case 'oneMonthFromNow':
|
|
232
|
+
return today + 30;
|
|
233
|
+
case 'exactDate':
|
|
234
|
+
return dayOf(t.date);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
function spanDays(s, today) {
|
|
238
|
+
const n = Math.max(1, Math.floor(Number(s.days) || 1));
|
|
239
|
+
switch (s.span) {
|
|
240
|
+
case 'pastWeek':
|
|
241
|
+
return [today - 7, today];
|
|
242
|
+
case 'pastMonth':
|
|
243
|
+
return [today - 30, today];
|
|
244
|
+
case 'pastYear':
|
|
245
|
+
return [today - 365, today];
|
|
246
|
+
case 'nextWeek':
|
|
247
|
+
return [today, today + 7];
|
|
248
|
+
case 'nextMonth':
|
|
249
|
+
return [today, today + 30];
|
|
250
|
+
case 'nextYear':
|
|
251
|
+
return [today, today + 365];
|
|
252
|
+
case 'pastDays':
|
|
253
|
+
return [today - n, today];
|
|
254
|
+
case 'nextDays':
|
|
255
|
+
return [today, today + n];
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
/** One condition as a test of a cell value. */
|
|
259
|
+
export function compileCondition(c, linkNames, now = new Date()) {
|
|
260
|
+
if (c.op === 'isEmpty')
|
|
261
|
+
return isBlank;
|
|
262
|
+
if (c.op === 'isNotEmpty')
|
|
263
|
+
return (v) => !isBlank(v);
|
|
264
|
+
switch (c.kind) {
|
|
265
|
+
case 'number': {
|
|
266
|
+
const b = Number(c.value);
|
|
267
|
+
if (!Number.isFinite(b))
|
|
268
|
+
return () => true;
|
|
269
|
+
const num = (v) => (isBlank(v) ? NaN : Number(v));
|
|
270
|
+
const cmp = {
|
|
271
|
+
eq: (a) => a === b,
|
|
272
|
+
neq: (a) => a !== b,
|
|
273
|
+
lt: (a) => a < b,
|
|
274
|
+
gt: (a) => a > b,
|
|
275
|
+
lte: (a) => a <= b,
|
|
276
|
+
gte: (a) => a >= b,
|
|
277
|
+
};
|
|
278
|
+
const f = cmp[c.op] ?? (() => true);
|
|
279
|
+
// An empty cell is no number: it matches only "not equal".
|
|
280
|
+
return (v) => {
|
|
281
|
+
const a = num(v);
|
|
282
|
+
return Number.isNaN(a) ? c.op === 'neq' : f(a);
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
case 'checkbox': {
|
|
286
|
+
const want = c.value !== false;
|
|
287
|
+
return (v) => !!v === want;
|
|
288
|
+
}
|
|
289
|
+
case 'select':
|
|
290
|
+
case 'multi': {
|
|
291
|
+
const me = currentUserId();
|
|
292
|
+
const values = list(c.value).map((x) => (x === ME && me != null ? me : x));
|
|
293
|
+
const wanted = new Set(values);
|
|
294
|
+
if (c.op === 'is')
|
|
295
|
+
return (v) => list(v)[0] === values[0];
|
|
296
|
+
if (c.op === 'isNot')
|
|
297
|
+
return (v) => list(v)[0] !== values[0];
|
|
298
|
+
if (c.op === 'isAnyOf' || c.op === 'hasAnyOf')
|
|
299
|
+
return (v) => list(v).some((x) => wanted.has(x));
|
|
300
|
+
if (c.op === 'isNoneOf' || c.op === 'hasNoneOf')
|
|
301
|
+
return (v) => !list(v).some((x) => wanted.has(x));
|
|
302
|
+
if (c.op === 'hasAllOf')
|
|
303
|
+
return (v) => {
|
|
304
|
+
const have = new Set(list(v));
|
|
305
|
+
return [...wanted].every((x) => have.has(x));
|
|
306
|
+
};
|
|
307
|
+
if (c.op === 'isExactly')
|
|
308
|
+
return (v) => {
|
|
309
|
+
const have = new Set(list(v));
|
|
310
|
+
return have.size === wanted.size && [...wanted].every((x) => have.has(x));
|
|
311
|
+
};
|
|
312
|
+
return () => true;
|
|
313
|
+
}
|
|
314
|
+
case 'date': {
|
|
315
|
+
const today = dayOf(now);
|
|
316
|
+
if (c.op === 'isWithin') {
|
|
317
|
+
const [lo, hi] = spanDays((c.value ?? { span: 'pastWeek' }), today);
|
|
318
|
+
return (v) => {
|
|
319
|
+
const d = dayOf(v);
|
|
320
|
+
return d != null && d >= lo && d <= hi;
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
const t = targetDay((c.value ?? { mode: 'today' }), today);
|
|
324
|
+
if (t == null)
|
|
325
|
+
return () => true;
|
|
326
|
+
const cmp = {
|
|
327
|
+
is: (d) => d === t,
|
|
328
|
+
isBefore: (d) => d < t,
|
|
329
|
+
isAfter: (d) => d > t,
|
|
330
|
+
isOnOrBefore: (d) => d <= t,
|
|
331
|
+
isOnOrAfter: (d) => d >= t,
|
|
332
|
+
};
|
|
333
|
+
const f = cmp[c.op] ?? (() => true);
|
|
334
|
+
return (v) => {
|
|
335
|
+
const d = dayOf(v);
|
|
336
|
+
return d != null && f(d);
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
case 'files': {
|
|
340
|
+
const needle = fold(c.value);
|
|
341
|
+
return (v) => (Array.isArray(v) ? v : []).some((a) => fold(a?.name).includes(needle));
|
|
342
|
+
}
|
|
343
|
+
case 'link':
|
|
344
|
+
case 'text': {
|
|
345
|
+
const needle = fold(c.value);
|
|
346
|
+
const text = (v) => c.kind === 'link' && c.table && linkNames
|
|
347
|
+
? fold(linkNames(c.table, v).join(', '))
|
|
348
|
+
: fold(Array.isArray(v) ? v.map((x) => (x && typeof x === 'object' ? (x.name ?? '') : x)).join(', ') : v);
|
|
349
|
+
if (c.op === 'contains')
|
|
350
|
+
return (v) => text(v).includes(needle);
|
|
351
|
+
if (c.op === 'notContains')
|
|
352
|
+
return (v) => !text(v).includes(needle);
|
|
353
|
+
if (c.op === 'is')
|
|
354
|
+
return (v) => text(v) === needle;
|
|
355
|
+
if (c.op === 'isNot')
|
|
356
|
+
return (v) => text(v) !== needle;
|
|
357
|
+
return () => true;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
/** A whole filter as a row test; incomplete conditions are left out. Null when nothing filters. */
|
|
362
|
+
export function compileFieldFilter(filter, getValue, linkNames, now) {
|
|
363
|
+
const one = (c) => {
|
|
364
|
+
const test = compileCondition(c, linkNames, now);
|
|
365
|
+
return (row) => test(getValue(row, c.column));
|
|
366
|
+
};
|
|
367
|
+
const join = (conj, parts) => conj === 'or' ? (row) => parts.some((p) => p(row)) : (row) => parts.every((p) => p(row));
|
|
368
|
+
const parts = [];
|
|
369
|
+
for (const c of filter.conditions) {
|
|
370
|
+
if (isGroup(c)) {
|
|
371
|
+
const inner = c.conditions.filter(isComplete).map(one);
|
|
372
|
+
if (inner.length)
|
|
373
|
+
parts.push(join(c.conjunction, inner));
|
|
374
|
+
}
|
|
375
|
+
else if (isComplete(c))
|
|
376
|
+
parts.push(one(c));
|
|
377
|
+
}
|
|
378
|
+
return parts.length ? join(filter.conjunction, parts) : null;
|
|
379
|
+
}
|
|
380
|
+
// ---- As words ---------------------------------------------------------------
|
|
381
|
+
const DAY_WORDS = {
|
|
382
|
+
today: 'today',
|
|
383
|
+
tomorrow: 'tomorrow',
|
|
384
|
+
yesterday: 'yesterday',
|
|
385
|
+
oneWeekAgo: 'one week ago',
|
|
386
|
+
oneWeekFromNow: 'one week from now',
|
|
387
|
+
oneMonthAgo: 'one month ago',
|
|
388
|
+
oneMonthFromNow: 'one month from now',
|
|
389
|
+
};
|
|
390
|
+
const SPAN_WORDS = {
|
|
391
|
+
pastWeek: 'the past week',
|
|
392
|
+
pastMonth: 'the past month',
|
|
393
|
+
pastYear: 'the past year',
|
|
394
|
+
nextWeek: 'the next week',
|
|
395
|
+
nextMonth: 'the next month',
|
|
396
|
+
nextYear: 'the next year',
|
|
397
|
+
};
|
|
398
|
+
function valueWords(c) {
|
|
399
|
+
if (c.op === 'isEmpty' || c.op === 'isNotEmpty')
|
|
400
|
+
return '';
|
|
401
|
+
if (c.kind === 'checkbox')
|
|
402
|
+
return c.value === false ? 'unchecked' : 'checked';
|
|
403
|
+
if (c.kind === 'date') {
|
|
404
|
+
if (c.op === 'isWithin') {
|
|
405
|
+
const s = (c.value ?? { span: 'pastWeek' });
|
|
406
|
+
if (s.span === 'pastDays')
|
|
407
|
+
return `the past ${s.days ?? 0} days`;
|
|
408
|
+
if (s.span === 'nextDays')
|
|
409
|
+
return `the next ${s.days ?? 0} days`;
|
|
410
|
+
return SPAN_WORDS[s.span] ?? s.span;
|
|
411
|
+
}
|
|
412
|
+
const t = (c.value ?? { mode: 'today' });
|
|
413
|
+
return t.mode === 'exactDate' ? t.date : (DAY_WORDS[t.mode] ?? t.mode);
|
|
414
|
+
}
|
|
415
|
+
const word = (v) => (v === ME ? 'me' : String(v));
|
|
416
|
+
return Array.isArray(c.value) ? c.value.map(word).join(', ') : word(c.value ?? '');
|
|
417
|
+
}
|
|
418
|
+
/** One condition as words: "Status is Done", "Due date is before today". */
|
|
419
|
+
export function describeCondition(c, name = (id) => id) {
|
|
420
|
+
const op = operatorsFor(c.kind).find((o) => o.op === c.op)?.label ?? c.op;
|
|
421
|
+
return [name(c.column), op, valueWords(c)].filter(Boolean).join(' ');
|
|
422
|
+
}
|
|
423
|
+
/** A filter as words, groups in parentheses; incomplete conditions are left out. */
|
|
424
|
+
export function describeFieldFilter(filter, name) {
|
|
425
|
+
const parts = [];
|
|
426
|
+
for (const c of filter.conditions) {
|
|
427
|
+
if (isGroup(c)) {
|
|
428
|
+
const inner = c.conditions.filter(isComplete).map((x) => describeCondition(x, name));
|
|
429
|
+
if (inner.length)
|
|
430
|
+
parts.push(inner.length > 1 ? `(${inner.join(` ${c.conjunction} `)})` : inner[0]);
|
|
431
|
+
}
|
|
432
|
+
else if (isComplete(c))
|
|
433
|
+
parts.push(describeCondition(c, name));
|
|
434
|
+
}
|
|
435
|
+
return parts.length ? parts.join(` ${filter.conjunction} `) : 'every record';
|
|
436
|
+
}
|
|
437
|
+
/** The columns a filter's complete conditions read, each once. */
|
|
438
|
+
export function fieldFilterColumns(filter) {
|
|
439
|
+
const out = new Set();
|
|
440
|
+
for (const c of filter.conditions) {
|
|
441
|
+
for (const x of isGroup(c) ? c.conditions : [c])
|
|
442
|
+
if (isComplete(x))
|
|
443
|
+
out.add(x.column);
|
|
444
|
+
}
|
|
445
|
+
return [...out];
|
|
446
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
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
|
+
export type Separators = 'local' | 'comma-period' | 'period-comma' | 'space-comma' | 'space-period';
|
|
9
|
+
export type Abbreviation = 'none' | 'thousand' | 'million' | 'billion';
|
|
10
|
+
export type NumberFormatProps = {
|
|
11
|
+
/** Decimal places, 0..8. */
|
|
12
|
+
precision?: number;
|
|
13
|
+
separators?: Separators;
|
|
14
|
+
/** Group thousands. Default true. */
|
|
15
|
+
showThousands?: boolean;
|
|
16
|
+
abbreviation?: Abbreviation;
|
|
17
|
+
};
|
|
18
|
+
export declare function toNumber(value: unknown): number | null;
|
|
19
|
+
/** A number as the field shows it, without a currency symbol or percent sign. */
|
|
20
|
+
export declare function formatNumber(value: number, p: NumberFormatProps): string;
|
|
21
|
+
/** The thousands and decimal characters a field's `separators` setting means. */
|
|
22
|
+
export declare function separatorChars(sep?: Separators): {
|
|
23
|
+
group: string;
|
|
24
|
+
decimal: string;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* A number from what someone typed into a number, currency or percent cell,
|
|
28
|
+
* read with the field's own separators: "$1,200.50", "1.200,50 €" (with
|
|
29
|
+
* period-comma), "-15%", "2.5k", "3M". The currency symbol, a percent sign and
|
|
30
|
+
* spaces are ignored; a K, M or B suffix multiplies. Null when it is not a
|
|
31
|
+
* number.
|
|
32
|
+
*/
|
|
33
|
+
export declare function parseNumberText(text: string, p?: {
|
|
34
|
+
separators?: Separators;
|
|
35
|
+
symbol?: string;
|
|
36
|
+
}): number | null;
|
|
37
|
+
export type NumberFieldKind = 'number' | 'currency' | 'percent';
|
|
38
|
+
export type NumberFieldProps = {
|
|
39
|
+
format?: 'integer' | 'decimal' | 'currency' | 'percent';
|
|
40
|
+
precision?: number;
|
|
41
|
+
separators?: Separators;
|
|
42
|
+
symbol?: string;
|
|
43
|
+
symbolPosition?: 'before' | 'after';
|
|
44
|
+
allowNegative?: boolean;
|
|
45
|
+
points?: boolean;
|
|
46
|
+
};
|
|
47
|
+
/** Which of the three a number field is: its format, or an older currency / percent column's type. */
|
|
48
|
+
export declare function numberKind(fieldType: unknown, p: NumberFieldProps): NumberFieldKind;
|
|
49
|
+
/**
|
|
50
|
+
* How a number, currency or percent field stores what is typed: `places` to
|
|
51
|
+
* round the typed number to (an integer field: 0), and `scale` between the
|
|
52
|
+
* typed number and the stored one (100 for a percent field holding
|
|
53
|
+
* fractions: 75 typed is 0.75 stored).
|
|
54
|
+
*/
|
|
55
|
+
export declare function numberFieldShape(kind: NumberFieldKind, p: NumberFieldProps): {
|
|
56
|
+
places: number;
|
|
57
|
+
scale: number;
|
|
58
|
+
};
|
|
59
|
+
/** The stored value for typed or pasted text: parsed, rounded, scaled. Null when it is not a number. */
|
|
60
|
+
export declare function numberFromText(text: string, kind: NumberFieldKind, p: NumberFieldProps): number | null;
|
|
61
|
+
/**
|
|
62
|
+
* Round half away from zero, as people do: 2450.555 to 2 places is 2450.56.
|
|
63
|
+
* toFixed works on the binary value (2450.55499...) and rounds it down.
|
|
64
|
+
*/
|
|
65
|
+
export declare function roundTo(n: number, places: number): number;
|
|
66
|
+
/**
|
|
67
|
+
* A stored number as the edit box shows it: no grouping, the field's decimal
|
|
68
|
+
* character, and float noise trimmed (0.1 + 0.2 shows 0.3).
|
|
69
|
+
*/
|
|
70
|
+
export declare function numberEditText(value: number, p?: {
|
|
71
|
+
separators?: Separators;
|
|
72
|
+
}): string;
|
|
73
|
+
/**
|
|
74
|
+
* Currency: the symbol before the number with the minus before both
|
|
75
|
+
* ("-$5.00"), or after it with a space ("-5,00 €").
|
|
76
|
+
*/
|
|
77
|
+
export declare function formatCurrency(value: number, p: NumberFormatProps & {
|
|
78
|
+
symbol?: string;
|
|
79
|
+
symbolPosition?: 'before' | 'after';
|
|
80
|
+
}): string;
|
|
81
|
+
/** Percent: `value` is a fraction (0.75 shows 75%) unless `points` says 0..100. */
|
|
82
|
+
export declare function formatPercent(value: number, p: NumberFormatProps & {
|
|
83
|
+
points?: boolean;
|
|
84
|
+
}): string;
|
|
85
|
+
export type DurationFormat = 'h:mm' | 'h:mm:ss' | 'h:mm:ss.S' | 'h:mm:ss.SS' | 'h:mm:ss.SSS';
|
|
86
|
+
/** Seconds as h:mm, h:mm:ss or h:mm:ss with tenths, hundredths or thousandths. */
|
|
87
|
+
export declare function formatDuration(seconds: number, format?: DurationFormat): string;
|
|
88
|
+
/** "1:30" -> 5400, "1:30:15.5" -> 5415.5, "90" -> 5400 (minutes), "2h 15m" -> 8100. */
|
|
89
|
+
export declare function parseDuration(text: unknown): number | null;
|
|
90
|
+
export type DateFormatName = 'local' | 'friendly' | 'us' | 'european' | 'iso';
|
|
91
|
+
export type DateFieldProps = {
|
|
92
|
+
dateFormat?: DateFormatName;
|
|
93
|
+
/** Show the time too. */
|
|
94
|
+
time?: boolean;
|
|
95
|
+
timeFormat?: '12hour' | '24hour';
|
|
96
|
+
/** Show every date in GMT instead of the viewer's time zone. */
|
|
97
|
+
gmt?: boolean;
|
|
98
|
+
/** Append the time zone. */
|
|
99
|
+
showTimeZone?: boolean;
|
|
100
|
+
};
|
|
101
|
+
export declare function toDate(value: unknown): Date | null;
|
|
102
|
+
/**
|
|
103
|
+
* The date editor's text format (the grid's date-format tokens) for a date
|
|
104
|
+
* field, so an edit shows the date as the cell does: "MMMM d, yyyy" for
|
|
105
|
+
* friendly in English, "M/d/yyyy" for US. Local and friendly follow `Intl`,
|
|
106
|
+
* read from the parts it gives for a sample date.
|
|
107
|
+
*/
|
|
108
|
+
export declare function dateEditTokens(p: DateFieldProps): string;
|
|
109
|
+
export declare function formatDate(value: unknown, p: DateFieldProps): string;
|