@svgrid/enterprise 3.1.7 → 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 +11375 -10805
- 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-DtBIaQno.js → index-BPU2KNc5.js} +396 -395
- 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 +141 -20
- 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/emit-project.js +25 -6
- package/dist/studio/sveltekit3.js +13 -7
- package/dist/studio/ui-components.generated.js +94 -2
- 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 +7561 -7618
- 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,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Colors and icons the field editor offers: a bright set for checkbox,
|
|
3
|
+
* rating and button fields, the 40-color set for select options (ten hues in
|
|
4
|
+
* four strengths), and the icon set a checkbox or rating can use.
|
|
5
|
+
*/
|
|
6
|
+
/** Bright colors, one per hue. */
|
|
7
|
+
export declare const BRIGHT: ReadonlyArray<{
|
|
8
|
+
value: string;
|
|
9
|
+
label: string;
|
|
10
|
+
}>;
|
|
11
|
+
/** The 40 select-option colors, row by strength, column by hue. */
|
|
12
|
+
export declare const OPTION_COLORS: ReadonlyArray<{
|
|
13
|
+
value: string;
|
|
14
|
+
label: string;
|
|
15
|
+
}>;
|
|
16
|
+
/** The colors new options cycle through. */
|
|
17
|
+
export declare const OPTION_CYCLE: string[];
|
|
18
|
+
export declare const ICONS: {
|
|
19
|
+
readonly check: "M5 12.5l4.5 4.5L19 7.5";
|
|
20
|
+
readonly x: "M6 6l12 12M18 6 6 18";
|
|
21
|
+
readonly star: "M12 3.2l2.7 5.6 6.1.9-4.4 4.3 1 6.1L12 17.2l-5.4 2.9 1-6.1-4.4-4.3 6.1-.9z";
|
|
22
|
+
readonly heart: "M12 20.3s-7.8-4.7-7.8-10.2A4.5 4.5 0 0 1 12 7.4a4.5 4.5 0 0 1 7.8 2.7c0 5.5-7.8 10.2-7.8 10.2z";
|
|
23
|
+
readonly thumbsUp: "M7 10v10H4V10zM7 10l4-7c1.4 0 2.3 1 2 2.4L12.4 9H19a2 2 0 0 1 2 2.3l-1.2 7A2 2 0 0 1 17.8 20H7";
|
|
24
|
+
readonly flag: "M5 21V4M5 4h11l-2 4 2 4H5";
|
|
25
|
+
readonly dot: "M12 7a5 5 0 1 0 0 10 5 5 0 0 0 0-10z";
|
|
26
|
+
};
|
|
27
|
+
export type IconName = keyof typeof ICONS;
|
|
28
|
+
/** Icons a checkbox can use. */
|
|
29
|
+
export declare const CHECKBOX_ICONS: {
|
|
30
|
+
value: "x" | "dot" | "check" | "flag" | "star" | "heart" | "thumbsUp";
|
|
31
|
+
label: string;
|
|
32
|
+
path: "M6 6l12 12M18 6 6 18" | "M5 12.5l4.5 4.5L19 7.5" | "M12 3.2l2.7 5.6 6.1.9-4.4 4.3 1 6.1L12 17.2l-5.4 2.9 1-6.1-4.4-4.3 6.1-.9z" | "M12 20.3s-7.8-4.7-7.8-10.2A4.5 4.5 0 0 1 12 7.4a4.5 4.5 0 0 1 7.8 2.7c0 5.5-7.8 10.2-7.8 10.2z" | "M7 10v10H4V10zM7 10l4-7c1.4 0 2.3 1 2 2.4L12.4 9H19a2 2 0 0 1 2 2.3l-1.2 7A2 2 0 0 1 17.8 20H7" | "M5 21V4M5 4h11l-2 4 2 4H5" | "M12 7a5 5 0 1 0 0 10 5 5 0 0 0 0-10z";
|
|
33
|
+
}[];
|
|
34
|
+
/** Icons a rating can use. */
|
|
35
|
+
export declare const RATING_ICONS: {
|
|
36
|
+
value: "x" | "dot" | "check" | "flag" | "star" | "heart" | "thumbsUp";
|
|
37
|
+
label: string;
|
|
38
|
+
path: "M6 6l12 12M18 6 6 18" | "M5 12.5l4.5 4.5L19 7.5" | "M12 3.2l2.7 5.6 6.1.9-4.4 4.3 1 6.1L12 17.2l-5.4 2.9 1-6.1-4.4-4.3 6.1-.9z" | "M12 20.3s-7.8-4.7-7.8-10.2A4.5 4.5 0 0 1 12 7.4a4.5 4.5 0 0 1 7.8 2.7c0 5.5-7.8 10.2-7.8 10.2z" | "M7 10v10H4V10zM7 10l4-7c1.4 0 2.3 1 2 2.4L12.4 9H19a2 2 0 0 1 2 2.3l-1.2 7A2 2 0 0 1 17.8 20H7" | "M5 21V4M5 4h11l-2 4 2 4H5" | "M12 7a5 5 0 1 0 0 10 5 5 0 0 0 0-10z";
|
|
39
|
+
}[];
|
|
40
|
+
/** Icons that read as a stroke (check, x, flag) rather than a filled shape. */
|
|
41
|
+
export declare const STROKE_ICONS: Set<"x" | "dot" | "check" | "flag" | "star" | "heart" | "thumbsUp">;
|
|
42
|
+
/**
|
|
43
|
+
* Text color for a pill filled with `color`: near-black or white, whichever
|
|
44
|
+
* has more contrast on it. Colors that are not #rgb / #rrggbb get the theme's
|
|
45
|
+
* text color.
|
|
46
|
+
*/
|
|
47
|
+
export declare function textOn(color: string | undefined): string;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Colors and icons the field editor offers: a bright set for checkbox,
|
|
3
|
+
* rating and button fields, the 40-color set for select options (ten hues in
|
|
4
|
+
* four strengths), and the icon set a checkbox or rating can use.
|
|
5
|
+
*/
|
|
6
|
+
const HUES = ['blue', 'cyan', 'teal', 'green', 'yellow', 'orange', 'red', 'pink', 'purple', 'gray'];
|
|
7
|
+
/** Bright colors, one per hue. */
|
|
8
|
+
export const BRIGHT = [
|
|
9
|
+
{ value: '#2d7ff9', label: 'Blue' },
|
|
10
|
+
{ value: '#18bfff', label: 'Cyan' },
|
|
11
|
+
{ value: '#20d9d2', label: 'Teal' },
|
|
12
|
+
{ value: '#20c933', label: 'Green' },
|
|
13
|
+
{ value: '#fcb400', label: 'Yellow' },
|
|
14
|
+
{ value: '#ff6f2c', label: 'Orange' },
|
|
15
|
+
{ value: '#f82b60', label: 'Red' },
|
|
16
|
+
{ value: '#ff08c2', label: 'Pink' },
|
|
17
|
+
{ value: '#8b46ff', label: 'Purple' },
|
|
18
|
+
{ value: '#666666', label: 'Gray' },
|
|
19
|
+
];
|
|
20
|
+
// Per hue: lightest, light, bright, dark.
|
|
21
|
+
const SHADES = {
|
|
22
|
+
blue: ['#cfdfff', '#9cc7ff', '#2d7ff9', '#2750ae'],
|
|
23
|
+
cyan: ['#d0f0fd', '#77d1f3', '#18bfff', '#0b76b7'],
|
|
24
|
+
teal: ['#c2f5e9', '#72ddc3', '#20d9d2', '#06a09b'],
|
|
25
|
+
green: ['#d1f7c4', '#93e088', '#20c933', '#338a17'],
|
|
26
|
+
yellow: ['#ffeab6', '#ffd66e', '#fcb400', '#b87503'],
|
|
27
|
+
orange: ['#fee2d5', '#ffa981', '#ff6f2c', '#d74d26'],
|
|
28
|
+
red: ['#ffdce5', '#ff9eb7', '#f82b60', '#ba1e45'],
|
|
29
|
+
pink: ['#ffdaf6', '#f99de2', '#ff08c2', '#b2158b'],
|
|
30
|
+
purple: ['#ede2fe', '#cdb0ff', '#8b46ff', '#6b1cb0'],
|
|
31
|
+
gray: ['#eeeeee', '#cccccc', '#666666', '#444444'],
|
|
32
|
+
};
|
|
33
|
+
const STRENGTH = ['lightest', 'light', 'bright', 'dark'];
|
|
34
|
+
/** The 40 select-option colors, row by strength, column by hue. */
|
|
35
|
+
export const OPTION_COLORS = STRENGTH.flatMap((s, i) => HUES.map((h) => ({ value: SHADES[h][i], label: `${h[0].toUpperCase()}${h.slice(1)}, ${s}` })));
|
|
36
|
+
/** The colors new options cycle through. */
|
|
37
|
+
export const OPTION_CYCLE = HUES.map((h) => SHADES[h][1]);
|
|
38
|
+
// 24x24 path data. Filled icons (rating, checked checkbox) use them as fills.
|
|
39
|
+
export const ICONS = {
|
|
40
|
+
check: 'M5 12.5l4.5 4.5L19 7.5',
|
|
41
|
+
x: 'M6 6l12 12M18 6 6 18',
|
|
42
|
+
star: 'M12 3.2l2.7 5.6 6.1.9-4.4 4.3 1 6.1L12 17.2l-5.4 2.9 1-6.1-4.4-4.3 6.1-.9z',
|
|
43
|
+
heart: 'M12 20.3s-7.8-4.7-7.8-10.2A4.5 4.5 0 0 1 12 7.4a4.5 4.5 0 0 1 7.8 2.7c0 5.5-7.8 10.2-7.8 10.2z',
|
|
44
|
+
thumbsUp: 'M7 10v10H4V10zM7 10l4-7c1.4 0 2.3 1 2 2.4L12.4 9H19a2 2 0 0 1 2 2.3l-1.2 7A2 2 0 0 1 17.8 20H7',
|
|
45
|
+
flag: 'M5 21V4M5 4h11l-2 4 2 4H5',
|
|
46
|
+
dot: 'M12 7a5 5 0 1 0 0 10 5 5 0 0 0 0-10z',
|
|
47
|
+
};
|
|
48
|
+
const ICON_LABEL = { check: 'Check', x: 'Cross', star: 'Star', heart: 'Heart', thumbsUp: 'Thumbs up', flag: 'Flag', dot: 'Dot' };
|
|
49
|
+
/** Icons a checkbox can use. */
|
|
50
|
+
export const CHECKBOX_ICONS = ['check', 'x', 'star', 'heart', 'thumbsUp', 'flag', 'dot'].map((v) => ({ value: v, label: ICON_LABEL[v], path: ICONS[v] }));
|
|
51
|
+
/** Icons a rating can use. */
|
|
52
|
+
export const RATING_ICONS = ['star', 'heart', 'thumbsUp', 'flag', 'dot'].map((v) => ({ value: v, label: ICON_LABEL[v], path: ICONS[v] }));
|
|
53
|
+
/** Icons that read as a stroke (check, x, flag) rather than a filled shape. */
|
|
54
|
+
export const STROKE_ICONS = new Set(['check', 'x', 'flag', 'thumbsUp']);
|
|
55
|
+
/**
|
|
56
|
+
* Text color for a pill filled with `color`: near-black or white, whichever
|
|
57
|
+
* has more contrast on it. Colors that are not #rgb / #rrggbb get the theme's
|
|
58
|
+
* text color.
|
|
59
|
+
*/
|
|
60
|
+
export function textOn(color) {
|
|
61
|
+
const m = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(color ?? '');
|
|
62
|
+
if (!m)
|
|
63
|
+
return 'var(--sg-fg, #0f172a)';
|
|
64
|
+
const hex = m[1].length === 3 ? [...m[1]].map((c) => c + c).join('') : m[1];
|
|
65
|
+
const [r, g, b] = [0, 2, 4].map((i) => parseInt(hex.slice(i, i + 2), 16) / 255).map((c) => (c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4));
|
|
66
|
+
const l = 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
67
|
+
// #1d1f25 has a luminance of 0.014; white has 1.
|
|
68
|
+
return (l + 0.05) / 0.064 > 1.05 / (l + 0.05) ? '#1d1f25' : '#ffffff';
|
|
69
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* "Delete record?" asked by the record menus (a row's, a card's) before the
|
|
3
|
+
* record goes. The grid's header host (FieldsHeaderEnd) shows it for the grid
|
|
4
|
+
* the request names.
|
|
5
|
+
*/
|
|
6
|
+
export type DeleteRecordRequest = {
|
|
7
|
+
ctrl: unknown;
|
|
8
|
+
api: unknown;
|
|
9
|
+
row: unknown;
|
|
10
|
+
};
|
|
11
|
+
export declare const getDeleteRecordRequest: () => DeleteRecordRequest | null;
|
|
12
|
+
export declare function askDeleteRecord(r: DeleteRecordRequest | null): void;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The right-click menu on a record in a base's grid: expand it, add a record
|
|
3
|
+
* above or below it (in its group), duplicate it, copy and paste cells, and
|
|
4
|
+
* delete it. A record made here is a record as "+ Add row" makes one: its
|
|
5
|
+
* own id, the next autonumber, the created time, and `onRowAdd` fired, so a
|
|
6
|
+
* base with a database writes it.
|
|
7
|
+
*/
|
|
8
|
+
import type { ContextMenuItem } from '@svgrid/grid';
|
|
9
|
+
export declare function recordMenu(getApi: () => any, getCtrl: () => any): ContextMenuItem[];
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { openRecord } from './editor-request.svelte.js';
|
|
2
|
+
import { newRowValues, recordCopyValues } from './field-ops.js';
|
|
3
|
+
import { askDeleteRecord } from './record-delete.svelte.js';
|
|
4
|
+
// Glyphs on the menu's 16 x 16 grid.
|
|
5
|
+
const ICONS = {
|
|
6
|
+
expand: { paths: [{ d: 'M9.5 2.5h4v4M13.5 2.5 9 7M6.5 13.5h-4v-4M2.5 13.5 7 9' }] },
|
|
7
|
+
above: { paths: [{ d: 'M2.5 9.5h11v4h-11zM8 2.5v5M5.5 5 8 2.5 10.5 5' }] },
|
|
8
|
+
below: { paths: [{ d: 'M2.5 2.5h11v4h-11zM8 8.5v5M5.5 11 8 13.5 10.5 11' }] },
|
|
9
|
+
duplicate: { paths: [{ d: 'M5.5 5.5h8v8h-8zM10.5 5.5v-3h-8v8h3M9.5 8v3M8 9.5h3' }] },
|
|
10
|
+
copy: { paths: [{ d: 'M5.5 5.5h8v8h-8zM10.5 5.5v-3h-8v8h3' }] },
|
|
11
|
+
paste: { paths: [{ d: 'M5.5 3h-2v10.5h9V3h-2M6 2h4v2.5H6zM6 8h4M6 10.5h4' }] },
|
|
12
|
+
comment: { paths: [{ d: 'M2.5 3.5h11v7.5H8l-3 2.5V11H2.5z' }] },
|
|
13
|
+
delete: { paths: [{ d: 'M2.5 4.5h11M6 4.5v-2h4v2M4 4.5l.7 9h6.6l.7-9M6.8 7v4.5M9.2 7v4.5' }] },
|
|
14
|
+
};
|
|
15
|
+
/** A list value (tags, links) is copied, not shared with the record it came from. */
|
|
16
|
+
const copy = (v) => (Array.isArray(v) ? [...v] : v);
|
|
17
|
+
export function recordMenu(getApi, getCtrl) {
|
|
18
|
+
const ctrl = () => getCtrl();
|
|
19
|
+
const editable = () => !!ctrl()?.editingEnabled;
|
|
20
|
+
const noRecord = (t) => !t.row;
|
|
21
|
+
const readOnly = (t) => !t.row || !editable();
|
|
22
|
+
/** Add `values` as a new record next to `t`'s record; `edit` starts on its first field (an empty record, not a copy). */
|
|
23
|
+
function add(t, values, offset, edit) {
|
|
24
|
+
const c = ctrl();
|
|
25
|
+
const api = getApi();
|
|
26
|
+
if (!c || !api || !t.row)
|
|
27
|
+
return;
|
|
28
|
+
const cfg = c.props.rowAdder;
|
|
29
|
+
const defaults = cfg && typeof cfg === 'object' && typeof cfg.defaults === 'function' ? cfg.defaults() : {};
|
|
30
|
+
const row = newRowValues(c, { ...defaults, ...values });
|
|
31
|
+
// The menu's row may be another object than the one the data holds: match by id too.
|
|
32
|
+
const id = t.row.id;
|
|
33
|
+
const at = c.internalData.findIndex((r) => r === t.row || (id != null && r?.id === id));
|
|
34
|
+
api.addRow(row, at < 0 ? 'bottom' : at + offset);
|
|
35
|
+
c.props.onRowAdd?.({ row });
|
|
36
|
+
// Sorting can put it anywhere: find it, show it, and start on its first field.
|
|
37
|
+
queueMicrotask(() => {
|
|
38
|
+
const index = c.allRows.findIndex((r) => r.original === row);
|
|
39
|
+
if (index < 0)
|
|
40
|
+
return;
|
|
41
|
+
api.scrollToRow(index);
|
|
42
|
+
if (edit)
|
|
43
|
+
for (const col of c.allColumns)
|
|
44
|
+
if (api.startEditing(index, col.id))
|
|
45
|
+
break;
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
/** The values that keep a new record in `t`'s groups. */
|
|
49
|
+
function groupValues(t) {
|
|
50
|
+
const c = ctrl();
|
|
51
|
+
const out = {};
|
|
52
|
+
const grouped = c?.grid?.getState?.().grouping ?? [];
|
|
53
|
+
for (const id of grouped) {
|
|
54
|
+
const def = c.internalColumns.find((d) => String(d.id ?? d.field) === id);
|
|
55
|
+
if (def?.field && !def.fieldFn)
|
|
56
|
+
out[def.field] = copy(t.row[def.field]);
|
|
57
|
+
}
|
|
58
|
+
return out;
|
|
59
|
+
}
|
|
60
|
+
function duplicate(t) {
|
|
61
|
+
const c = ctrl();
|
|
62
|
+
if (c && t.row)
|
|
63
|
+
add(t, recordCopyValues(c, t.row), 1, false);
|
|
64
|
+
}
|
|
65
|
+
return [
|
|
66
|
+
{ key: 'expand', label: 'Expand record', icon: ICONS.expand, hidden: noRecord, action: (t) => openRecord({ ctrl: ctrl(), rowId: t.rowId }) },
|
|
67
|
+
{ key: 'comment', label: 'Comment', icon: ICONS.comment, hidden: noRecord, action: (t) => openRecord({ ctrl: ctrl(), rowId: t.rowId, focus: 'comment' }) },
|
|
68
|
+
'separator',
|
|
69
|
+
{ key: 'record_above', label: 'Insert record above', icon: ICONS.above, hidden: readOnly, action: (t) => add(t, groupValues(t), 0, true) },
|
|
70
|
+
{ key: 'record_below', label: 'Insert record below', icon: ICONS.below, hidden: readOnly, action: (t) => add(t, groupValues(t), 1, true) },
|
|
71
|
+
{ key: 'duplicate', label: 'Duplicate record', icon: ICONS.duplicate, hidden: readOnly, action: duplicate },
|
|
72
|
+
'separator',
|
|
73
|
+
{ key: 'copy', icon: ICONS.copy },
|
|
74
|
+
{ key: 'paste', icon: ICONS.paste, hidden: () => !editable() },
|
|
75
|
+
'separator',
|
|
76
|
+
{ key: 'delete_record', label: 'Delete record', icon: ICONS.delete, hidden: readOnly, action: (t) => askDeleteRecord({ ctrl: ctrl(), api: getApi(), row: t.row }) },
|
|
77
|
+
];
|
|
78
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Field types: what a column IS (rating, URL, single select, attachment...),
|
|
3
|
+
* as opposed to how it is edited. A type fills in the column (editor, format,
|
|
4
|
+
* alignment) and can draw its own cell. Columns name one with `fieldType` and
|
|
5
|
+
* set its properties with `fieldProps`.
|
|
6
|
+
*/
|
|
7
|
+
import type { Component } from 'svelte';
|
|
8
|
+
/** Props every field cell receives. `props` is the type's defaults merged with the column's `fieldProps`. */
|
|
9
|
+
export type FieldCellProps<P = Record<string, unknown>> = {
|
|
10
|
+
ctrl: unknown;
|
|
11
|
+
row: {
|
|
12
|
+
id: string;
|
|
13
|
+
original: unknown;
|
|
14
|
+
};
|
|
15
|
+
column: {
|
|
16
|
+
id: string;
|
|
17
|
+
columnDef: Record<string, unknown>;
|
|
18
|
+
};
|
|
19
|
+
value: unknown;
|
|
20
|
+
props: P;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* What a property's dynamic parts see: the grid, the draft's properties, every
|
|
24
|
+
* other column, and the field's own names (key, id, saved header, draft name),
|
|
25
|
+
* which its formula may not read.
|
|
26
|
+
*/
|
|
27
|
+
export type FieldEditorContext = {
|
|
28
|
+
ctrl: any;
|
|
29
|
+
props: Record<string, any>;
|
|
30
|
+
columns: ReadonlyArray<Record<string, any>>;
|
|
31
|
+
self?: ReadonlyArray<unknown>;
|
|
32
|
+
};
|
|
33
|
+
type Choices = ReadonlyArray<{
|
|
34
|
+
value: string;
|
|
35
|
+
label: string;
|
|
36
|
+
}>;
|
|
37
|
+
type Base = {
|
|
38
|
+
key: string;
|
|
39
|
+
label: string;
|
|
40
|
+
/** Show the property only when this says so (e.g. decimal places for decimals). */
|
|
41
|
+
visible?: (props: Record<string, any>) => boolean;
|
|
42
|
+
/** One line of help under the control. */
|
|
43
|
+
hint?: string;
|
|
44
|
+
/** Other properties to change along with this one (a number format sets its usual precision). */
|
|
45
|
+
alsoSets?: (value: unknown, props: Record<string, any>) => Record<string, unknown>;
|
|
46
|
+
};
|
|
47
|
+
/** One property the field editor shows for a type. */
|
|
48
|
+
export type FieldPropertyDef = Base & ({
|
|
49
|
+
kind: 'number';
|
|
50
|
+
min?: number;
|
|
51
|
+
max?: number;
|
|
52
|
+
} | {
|
|
53
|
+
kind: 'text';
|
|
54
|
+
placeholder?: string;
|
|
55
|
+
} | {
|
|
56
|
+
kind: 'checkbox';
|
|
57
|
+
} | {
|
|
58
|
+
kind: 'choice';
|
|
59
|
+
choices: Choices | ((ctx: FieldEditorContext) => Choices);
|
|
60
|
+
}
|
|
61
|
+
/** The same, drawn as a row of buttons. */
|
|
62
|
+
| {
|
|
63
|
+
kind: 'segmented';
|
|
64
|
+
choices: Choices;
|
|
65
|
+
}
|
|
66
|
+
/** A color from a palette (hex values). */
|
|
67
|
+
| {
|
|
68
|
+
kind: 'color';
|
|
69
|
+
palette: ReadonlyArray<{
|
|
70
|
+
value: string;
|
|
71
|
+
label: string;
|
|
72
|
+
}>;
|
|
73
|
+
}
|
|
74
|
+
/** An icon from a set (SVG path data per icon). */
|
|
75
|
+
| {
|
|
76
|
+
kind: 'icon';
|
|
77
|
+
icons: ReadonlyArray<{
|
|
78
|
+
value: string;
|
|
79
|
+
label: string;
|
|
80
|
+
path: string;
|
|
81
|
+
}>;
|
|
82
|
+
}
|
|
83
|
+
/** A list of select options with colors. */
|
|
84
|
+
| {
|
|
85
|
+
kind: 'options';
|
|
86
|
+
}
|
|
87
|
+
/** The value new rows get; the editor follows the field type. */
|
|
88
|
+
| {
|
|
89
|
+
kind: 'default';
|
|
90
|
+
}
|
|
91
|
+
/** A formula over the row's fields. */
|
|
92
|
+
| {
|
|
93
|
+
kind: 'formula';
|
|
94
|
+
}
|
|
95
|
+
/** Some of the grid's other columns. */
|
|
96
|
+
| {
|
|
97
|
+
kind: 'columns';
|
|
98
|
+
});
|
|
99
|
+
/** What a type is told when it fills in a column. */
|
|
100
|
+
export type FieldFillContext = {
|
|
101
|
+
columns: ReadonlyArray<Record<string, any>>;
|
|
102
|
+
};
|
|
103
|
+
/** What a type is told when a row is added (row adder) or the field is created. */
|
|
104
|
+
export type FieldRowContext = {
|
|
105
|
+
props: Record<string, any>;
|
|
106
|
+
field: string;
|
|
107
|
+
rows: ReadonlyArray<Record<string, unknown>>;
|
|
108
|
+
};
|
|
109
|
+
export type FieldTypeDef<P extends Record<string, unknown> = Record<string, unknown>> = {
|
|
110
|
+
/** The name columns use in `fieldType`. */
|
|
111
|
+
id: string;
|
|
112
|
+
/** Shown in the type picker. */
|
|
113
|
+
label: string;
|
|
114
|
+
/** One line under the picker when the type is chosen. */
|
|
115
|
+
description?: string;
|
|
116
|
+
/** An SVG path (24x24 viewBox) for the picker and the header. */
|
|
117
|
+
icon?: string;
|
|
118
|
+
/** Group in the type picker. */
|
|
119
|
+
group?: 'basic' | 'number' | 'date' | 'people' | 'computed' | 'relation';
|
|
120
|
+
/** Property values a column gets when its `fieldProps` leave them out. */
|
|
121
|
+
defaults?: P;
|
|
122
|
+
/**
|
|
123
|
+
* Fill in the column: editor, format, alignment. Keep what the column set
|
|
124
|
+
* itself (`def.editorType ?? ...`), so a column can still override a type.
|
|
125
|
+
* `ctx.columns` is every column, for types that refer to other fields.
|
|
126
|
+
*/
|
|
127
|
+
fill?: (def: Record<string, unknown>, props: P, ctx: FieldFillContext) => Record<string, unknown>;
|
|
128
|
+
/** Draws the cell. Without one, the grid draws the filled-in column as usual. */
|
|
129
|
+
cell?: Component<FieldCellProps<P>>;
|
|
130
|
+
/** When `cell` draws (default: always). A percent field draws its own cell only as a bar. */
|
|
131
|
+
hasCell?: (props: P) => boolean;
|
|
132
|
+
/** What the field editor lets a user set for this type. */
|
|
133
|
+
properties?: ReadonlyArray<FieldPropertyDef>;
|
|
134
|
+
/** Column width a new field of this type starts with. */
|
|
135
|
+
width?: number;
|
|
136
|
+
/** The value a new row gets (a default, the next number, the current time). */
|
|
137
|
+
newRowValue?: (ctx: FieldRowContext) => unknown;
|
|
138
|
+
/** Values for every existing row when the field is created (autonumber, created time). */
|
|
139
|
+
onCreate?: (ctx: FieldRowContext) => unknown[] | null;
|
|
140
|
+
/**
|
|
141
|
+
* `false`: a duplicated record gets a new value from `newRowValue` instead
|
|
142
|
+
* of a copy (the field's `default` when the type has no `newRowValue`).
|
|
143
|
+
* For an id, a number or a stamp no two records should share.
|
|
144
|
+
*/
|
|
145
|
+
copy?: false;
|
|
146
|
+
/**
|
|
147
|
+
* A type kept for columns that already name it, and edited as another: the
|
|
148
|
+
* field editor opens it as `type` with `props` on top of its own, and
|
|
149
|
+
* leaves it out of the type picker.
|
|
150
|
+
*/
|
|
151
|
+
editAs?: {
|
|
152
|
+
type: string;
|
|
153
|
+
props: Record<string, unknown>;
|
|
154
|
+
};
|
|
155
|
+
};
|
|
156
|
+
/** Add or replace a field type. */
|
|
157
|
+
export declare function registerFieldType<P extends Record<string, unknown>>(def: FieldTypeDef<P>): void;
|
|
158
|
+
/** The type named `id`, or undefined. */
|
|
159
|
+
export declare function getFieldType(id: unknown): FieldTypeDef<any> | undefined;
|
|
160
|
+
/** Every registered type, in registration order. */
|
|
161
|
+
export declare function listFieldTypes(): FieldTypeDef<any>[];
|
|
162
|
+
/** A column's effective properties: the type's defaults, then its own `fieldProps`. */
|
|
163
|
+
export declare function fieldPropsOf(def: {
|
|
164
|
+
fieldType?: unknown;
|
|
165
|
+
fieldProps?: Record<string, unknown>;
|
|
166
|
+
}): Record<string, unknown>;
|
|
167
|
+
/** The column as the grid should see it, filled in by its type. Unknown types pass through. */
|
|
168
|
+
export declare function fillFieldColumn<T extends Record<string, unknown>>(def: T, columns?: ReadonlyArray<Record<string, any>>): T & Record<string, unknown>;
|
|
169
|
+
/** The column as it was declared, before its type filled it in. */
|
|
170
|
+
export declare function originalColumn<T extends object>(def: T): T;
|
|
171
|
+
/** Whether this column's type draws the cell itself (else the grid draws the filled-in column). */
|
|
172
|
+
export declare function typeDrawsCell(def: {
|
|
173
|
+
fieldType?: unknown;
|
|
174
|
+
fieldProps?: Record<string, unknown>;
|
|
175
|
+
}): boolean;
|
|
176
|
+
export {};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { withSummary } from './summaries.js';
|
|
2
|
+
let types = $state.raw({});
|
|
3
|
+
/** Add or replace a field type. */
|
|
4
|
+
export function registerFieldType(def) {
|
|
5
|
+
types = { ...types, [def.id]: def };
|
|
6
|
+
}
|
|
7
|
+
/** The type named `id`, or undefined. */
|
|
8
|
+
export function getFieldType(id) {
|
|
9
|
+
return typeof id === 'string' ? types[id] : undefined;
|
|
10
|
+
}
|
|
11
|
+
/** Every registered type, in registration order. */
|
|
12
|
+
export function listFieldTypes() {
|
|
13
|
+
return Object.values(types);
|
|
14
|
+
}
|
|
15
|
+
/** A column's effective properties: the type's defaults, then its own `fieldProps`. */
|
|
16
|
+
export function fieldPropsOf(def) {
|
|
17
|
+
return { ...(getFieldType(def.fieldType)?.defaults ?? {}), ...(def.fieldProps ?? {}) };
|
|
18
|
+
}
|
|
19
|
+
// Each filled-in column -> the column it was filled from, so the field editor
|
|
20
|
+
// can hand the app back exactly what it declared. Kept twice: in a WeakMap,
|
|
21
|
+
// and on the filled column under a symbol, because the grid copies columns
|
|
22
|
+
// (`{ ...col }` when it resolves a data type) and a copy is not in the map;
|
|
23
|
+
// a spread carries symbol keys along, and JSON and Object.keys leave them out.
|
|
24
|
+
const ORIGINAL = new WeakMap();
|
|
25
|
+
const SOURCE = Symbol('svgrid.fieldSource');
|
|
26
|
+
/** The column as the grid should see it, filled in by its type. Unknown types pass through. */
|
|
27
|
+
export function fillFieldColumn(def, columns = []) {
|
|
28
|
+
const type = getFieldType(def.fieldType);
|
|
29
|
+
if (!type)
|
|
30
|
+
return def;
|
|
31
|
+
const source = originalColumn(def);
|
|
32
|
+
const props = fieldPropsOf(source);
|
|
33
|
+
// A type without `fill` takes the column as declared, and still gets the rest.
|
|
34
|
+
const filled = type.fill ? type.fill(source, props, { columns: columns.map((c) => originalColumn(c)) }) : { ...source };
|
|
35
|
+
// The footer summary the field keeps in `fieldProps.summary` (none until picked).
|
|
36
|
+
const out = withSummary(filled, props);
|
|
37
|
+
ORIGINAL.set(out, source);
|
|
38
|
+
out[SOURCE] = source;
|
|
39
|
+
return out;
|
|
40
|
+
}
|
|
41
|
+
/** The column as it was declared, before its type filled it in. */
|
|
42
|
+
export function originalColumn(def) {
|
|
43
|
+
return def[SOURCE] ?? ORIGINAL.get(def) ?? def;
|
|
44
|
+
}
|
|
45
|
+
/** Whether this column's type draws the cell itself (else the grid draws the filled-in column). */
|
|
46
|
+
export function typeDrawsCell(def) {
|
|
47
|
+
const type = getFieldType(def.fieldType);
|
|
48
|
+
if (!type?.cell)
|
|
49
|
+
return false;
|
|
50
|
+
return type.hasCell ? type.hasCell(fieldPropsOf(def)) : true;
|
|
51
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rich text for long-text fields: **bold**, *italic*, `code`, [links](https://...)
|
|
3
|
+
* and "- " list lines. Parsed into plain parts that the cell renders as
|
|
4
|
+
* elements; nothing reaches the page as HTML, so the text cannot inject markup.
|
|
5
|
+
* Links keep http(s) and mailto only.
|
|
6
|
+
*/
|
|
7
|
+
export type RichPart = {
|
|
8
|
+
kind: 'text';
|
|
9
|
+
text: string;
|
|
10
|
+
} | {
|
|
11
|
+
kind: 'b' | 'i' | 'code';
|
|
12
|
+
text: string;
|
|
13
|
+
} | {
|
|
14
|
+
kind: 'a';
|
|
15
|
+
text: string;
|
|
16
|
+
href: string;
|
|
17
|
+
};
|
|
18
|
+
export type RichLine = {
|
|
19
|
+
bullet: boolean;
|
|
20
|
+
parts: RichPart[];
|
|
21
|
+
};
|
|
22
|
+
export declare function parseInline(text: string): RichPart[];
|
|
23
|
+
export declare function parseRichText(value: unknown): RichLine[];
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rich text for long-text fields: **bold**, *italic*, `code`, [links](https://...)
|
|
3
|
+
* and "- " list lines. Parsed into plain parts that the cell renders as
|
|
4
|
+
* elements; nothing reaches the page as HTML, so the text cannot inject markup.
|
|
5
|
+
* Links keep http(s) and mailto only.
|
|
6
|
+
*/
|
|
7
|
+
const INLINE = /\*\*([^*]+)\*\*|\*([^*]+)\*|`([^`]+)`|\[([^\]]+)\]\(([^)\s]+)\)/g;
|
|
8
|
+
function safeHref(href) {
|
|
9
|
+
try {
|
|
10
|
+
const u = new URL(href);
|
|
11
|
+
return u.protocol === 'http:' || u.protocol === 'https:' || u.protocol === 'mailto:' ? u.href : null;
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export function parseInline(text) {
|
|
18
|
+
const out = [];
|
|
19
|
+
let last = 0;
|
|
20
|
+
for (const m of text.matchAll(INLINE)) {
|
|
21
|
+
if (m.index > last)
|
|
22
|
+
out.push({ kind: 'text', text: text.slice(last, m.index) });
|
|
23
|
+
if (m[1] != null)
|
|
24
|
+
out.push({ kind: 'b', text: m[1] });
|
|
25
|
+
else if (m[2] != null)
|
|
26
|
+
out.push({ kind: 'i', text: m[2] });
|
|
27
|
+
else if (m[3] != null)
|
|
28
|
+
out.push({ kind: 'code', text: m[3] });
|
|
29
|
+
else {
|
|
30
|
+
const href = safeHref(m[5]);
|
|
31
|
+
out.push(href ? { kind: 'a', text: m[4], href } : { kind: 'text', text: m[4] });
|
|
32
|
+
}
|
|
33
|
+
last = m.index + m[0].length;
|
|
34
|
+
}
|
|
35
|
+
if (last < text.length)
|
|
36
|
+
out.push({ kind: 'text', text: text.slice(last) });
|
|
37
|
+
return out;
|
|
38
|
+
}
|
|
39
|
+
export function parseRichText(value) {
|
|
40
|
+
const text = value == null ? '' : String(value);
|
|
41
|
+
return text
|
|
42
|
+
.split(/\r?\n/)
|
|
43
|
+
.filter((line) => line.trim() !== '')
|
|
44
|
+
.map((line) => {
|
|
45
|
+
const bullet = /^\s*[-*]\s+/.test(line);
|
|
46
|
+
return { bullet, parts: parseInline(bullet ? line.replace(/^\s*[-*]\s+/, '') : line) };
|
|
47
|
+
});
|
|
48
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The status field a grid's rows are colored by when someone picks it from
|
|
3
|
+
* the column menu ("Color rows by this field"): it wins over the `rowColor`
|
|
4
|
+
* prop for that grid, and `onRowColorChange` reports it so the app can keep
|
|
5
|
+
* it. Held per grid, weakly, so a grid that unmounts takes its choice along.
|
|
6
|
+
* A view's colors are a choice too; a view with no color setting clears it.
|
|
7
|
+
*/
|
|
8
|
+
type Config = {
|
|
9
|
+
field?: string;
|
|
10
|
+
target?: 'header' | 'bar' | 'row';
|
|
11
|
+
rules?: ReadonlyArray<unknown>;
|
|
12
|
+
};
|
|
13
|
+
/** The choice made for this grid, `undefined` when none was made (the prop rules). */
|
|
14
|
+
export declare function chosenRowColor(ctrl: object): Config | null | undefined;
|
|
15
|
+
/** Color this grid's rows by `config` (null: no colors), and tell the app. */
|
|
16
|
+
export declare function chooseRowColor(ctrl: {
|
|
17
|
+
props: {
|
|
18
|
+
onRowColorChange?: (c: Config | null) => void;
|
|
19
|
+
};
|
|
20
|
+
}, config: Config | null): void;
|
|
21
|
+
/**
|
|
22
|
+
* Drop this grid's choice, so the `rowColor` prop rules again; the app hears
|
|
23
|
+
* of it (with the prop's colors) only when a choice was in force.
|
|
24
|
+
*/
|
|
25
|
+
export declare function clearRowColorChoice(ctrl: {
|
|
26
|
+
props: {
|
|
27
|
+
rowColor?: Config | null;
|
|
28
|
+
onRowColorChange?: (c: Config | null) => void;
|
|
29
|
+
};
|
|
30
|
+
}): void;
|
|
31
|
+
export {};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
const choices = new WeakMap();
|
|
2
|
+
// The WeakMap is not reactive; reading the version makes the rows repaint.
|
|
3
|
+
let version = $state(0);
|
|
4
|
+
/** The choice made for this grid, `undefined` when none was made (the prop rules). */
|
|
5
|
+
export function chosenRowColor(ctrl) {
|
|
6
|
+
void version;
|
|
7
|
+
return choices.has(ctrl) ? choices.get(ctrl) : undefined;
|
|
8
|
+
}
|
|
9
|
+
/** Color this grid's rows by `config` (null: no colors), and tell the app. */
|
|
10
|
+
export function chooseRowColor(ctrl, config) {
|
|
11
|
+
choices.set(ctrl, config);
|
|
12
|
+
version += 1;
|
|
13
|
+
ctrl.props.onRowColorChange?.(config);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Drop this grid's choice, so the `rowColor` prop rules again; the app hears
|
|
17
|
+
* of it (with the prop's colors) only when a choice was in force.
|
|
18
|
+
*/
|
|
19
|
+
export function clearRowColorChoice(ctrl) {
|
|
20
|
+
if (!choices.has(ctrl))
|
|
21
|
+
return;
|
|
22
|
+
choices.delete(ctrl);
|
|
23
|
+
version += 1;
|
|
24
|
+
ctrl.props.onRowColorChange?.(ctrl.props.rowColor ?? null);
|
|
25
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `rowColor` prop: a color per row from a select field's option colors,
|
|
3
|
+
* or from the first matching rule. The grid asks for rendered rows only
|
|
4
|
+
* (registerGridExtension's rowMarkColor / rowMarkLabel), so this never walks
|
|
5
|
+
* the data. Where the color is painted is CSS keyed on the root class.
|
|
6
|
+
*/
|
|
7
|
+
type Rule = {
|
|
8
|
+
when: (row: unknown) => boolean;
|
|
9
|
+
color: string;
|
|
10
|
+
label?: string;
|
|
11
|
+
};
|
|
12
|
+
type Config = {
|
|
13
|
+
field?: string;
|
|
14
|
+
rules?: ReadonlyArray<Rule>;
|
|
15
|
+
target?: 'header' | 'bar' | 'row';
|
|
16
|
+
};
|
|
17
|
+
type Ctrl = {
|
|
18
|
+
props: {
|
|
19
|
+
rowColor?: Config | null;
|
|
20
|
+
};
|
|
21
|
+
allColumns?: ReadonlyArray<{
|
|
22
|
+
columnDef: Record<string, unknown>;
|
|
23
|
+
}>;
|
|
24
|
+
};
|
|
25
|
+
/** The colors in force: one picked from the column menu, else the `rowColor` prop. */
|
|
26
|
+
export declare function rowColorOf(ctrl: Ctrl): Config | null | undefined;
|
|
27
|
+
export declare function rowMarkColor(ctrl: Ctrl, row: unknown): string | null;
|
|
28
|
+
export declare function rowMarkLabel(ctrl: Ctrl, row: unknown): string | null;
|
|
29
|
+
export declare function rowColorRootClass(ctrl: Ctrl): string | null;
|
|
30
|
+
/**
|
|
31
|
+
* Taller rows show more, as a table database does: from a 48px row height
|
|
32
|
+
* the root class names how many lines of text fit (2 to 6), and the fields
|
|
33
|
+
* styles wrap text and select pills to that and grow attachment thumbnails.
|
|
34
|
+
*/
|
|
35
|
+
export declare function tallRowClass(ctrl: Ctrl): string | null;
|
|
36
|
+
export {};
|