@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,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checkbox cells with the field's icon and color. The default icon is a
|
|
3
|
+
* box with a check; star, heart and the rest show filled when checked and as
|
|
4
|
+
* a faint outline when not. Clicking and Space still toggle through the grid
|
|
5
|
+
* (the column's editor is 'checkbox'); this only draws.
|
|
6
|
+
*/
|
|
7
|
+
import type { FieldCellProps } from './registry.svelte.js';
|
|
8
|
+
import { type IconName } from './palette.js';
|
|
9
|
+
declare const CheckboxCell: import("svelte").Component<FieldCellProps<{
|
|
10
|
+
icon?: IconName;
|
|
11
|
+
color?: string;
|
|
12
|
+
}>, {}, "">;
|
|
13
|
+
type CheckboxCell = ReturnType<typeof CheckboxCell>;
|
|
14
|
+
export default CheckboxCell;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* "Delete field?" for a link field with a field that links back from the
|
|
4
|
+
* other table, or with lookups, rollups and counts that read it: they are
|
|
5
|
+
* all deleted with it, so it says so before it does. Any field that
|
|
6
|
+
* formulas read asks too: they stay, and show #ERROR.
|
|
7
|
+
*/
|
|
8
|
+
import { SvModal } from '@svgrid/grid'
|
|
9
|
+
import { linkReaders } from './base-tables'
|
|
10
|
+
import { defId, removeField } from './field-ops'
|
|
11
|
+
import { formulaReaders } from './formula'
|
|
12
|
+
import { getLinkedTable } from './sources.svelte'
|
|
13
|
+
|
|
14
|
+
let { ctrl, columnId, onClose }: { ctrl: any; columnId: string; onClose: () => void } = $props()
|
|
15
|
+
|
|
16
|
+
let open = $state(true)
|
|
17
|
+
// svelte-ignore state_referenced_locally
|
|
18
|
+
const def = (ctrl.internalColumns as Array<Record<string, any>>).find((d) => defId(d) === columnId)
|
|
19
|
+
// svelte-ignore state_referenced_locally
|
|
20
|
+
const name = String(def?.header ?? columnId)
|
|
21
|
+
const table = getLinkedTable(def?.fieldProps?.table)
|
|
22
|
+
const back = table?.fields?.find((f) => f.field === def?.fieldProps?.inverse)?.header
|
|
23
|
+
// Lookups, rollups and counts that read either field: they go with it. The
|
|
24
|
+
// ones here are removed from this grid; a base removes the ones in the
|
|
25
|
+
// other table with the field back.
|
|
26
|
+
// svelte-ignore state_referenced_locally
|
|
27
|
+
const own = def ? linkReaders({ columns: ctrl.internalColumns as Array<Record<string, any>> }, def) : []
|
|
28
|
+
const theirs = def?.fieldProps?.inverse ? (table?.fields ?? []).filter((f) => f.fieldProps?.linkField === def.fieldProps.inverse && ['lookup', 'rollup', 'count'].includes(String(f.fieldType))) : []
|
|
29
|
+
const readers = [...own.map((d) => String(d.header ?? d.field)), ...theirs.map((f) => `${f.header} (${table!.name})`)]
|
|
30
|
+
const isLink = def?.fieldType === 'link'
|
|
31
|
+
// Formulas that read it, or a lookup deleted with it: they stay and show #ERROR.
|
|
32
|
+
// svelte-ignore state_referenced_locally
|
|
33
|
+
const columns = ctrl.internalColumns as Array<Record<string, any>>
|
|
34
|
+
const formulas = def ? [...new Set([def, ...own].flatMap((d) => formulaReaders(columns, d)))].map((d) => String(d.header ?? d.field)) : []
|
|
35
|
+
|
|
36
|
+
function close() {
|
|
37
|
+
open = false
|
|
38
|
+
onClose()
|
|
39
|
+
}
|
|
40
|
+
function remove() {
|
|
41
|
+
for (const d of own) removeField(ctrl, defId(d))
|
|
42
|
+
removeField(ctrl, columnId)
|
|
43
|
+
close()
|
|
44
|
+
}
|
|
45
|
+
</script>
|
|
46
|
+
|
|
47
|
+
<SvModal bind:open title={`Delete ${name}?`} width={440} onClose={close}>
|
|
48
|
+
{#if isLink}
|
|
49
|
+
<p class="sv-fdel-text">
|
|
50
|
+
{name} links to {table?.name ?? 'another table'}.
|
|
51
|
+
{#if back}The field there that links back, <strong>{back}</strong>, is deleted with it.{/if}
|
|
52
|
+
The links between the records go too.
|
|
53
|
+
</p>
|
|
54
|
+
{#if readers.length}
|
|
55
|
+
<p class="sv-fdel-text sv-fdel-note">These fields read it and are deleted too: {readers.join(', ')}.</p>
|
|
56
|
+
{/if}
|
|
57
|
+
{:else}
|
|
58
|
+
<p class="sv-fdel-text">{name} and its values are deleted.</p>
|
|
59
|
+
{/if}
|
|
60
|
+
{#if formulas.length}
|
|
61
|
+
<p class="sv-fdel-text sv-fdel-note sv-fdel-formulas">These formulas read it and will show #ERROR: {formulas.join(', ')}.</p>
|
|
62
|
+
{/if}
|
|
63
|
+
{#snippet footer()}
|
|
64
|
+
<div class="sv-fdel-foot">
|
|
65
|
+
<button type="button" class="sv-fdel-btn" onclick={close}>Cancel</button>
|
|
66
|
+
<button type="button" class="sv-fdel-btn is-danger" onclick={remove}>Delete field</button>
|
|
67
|
+
</div>
|
|
68
|
+
{/snippet}
|
|
69
|
+
</SvModal>
|
|
70
|
+
|
|
71
|
+
<style>
|
|
72
|
+
.sv-fdel-text { margin: 0; font-size: 14px; line-height: 1.5; color: var(--sg-fg, #0f172a); }
|
|
73
|
+
.sv-fdel-note { margin-top: 10px; font-size: 13px; color: var(--sg-muted, #64748b); }
|
|
74
|
+
.sv-fdel-foot { display: flex; justify-content: flex-end; gap: 8px; width: 100%; }
|
|
75
|
+
.sv-fdel-btn {
|
|
76
|
+
height: 32px; padding: 0 14px; font: inherit; font-size: 13px; cursor: pointer; border-radius: var(--sg-radius, 6px);
|
|
77
|
+
background: transparent; color: var(--sg-fg, #0f172a); border: 1px solid var(--sg-border, #e2e8f0);
|
|
78
|
+
}
|
|
79
|
+
.sv-fdel-btn.is-danger { background: var(--sg-danger, #dc2626); border-color: var(--sg-danger, #dc2626); color: #fff; }
|
|
80
|
+
</style>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
type $$ComponentProps = {
|
|
2
|
+
ctrl: any;
|
|
3
|
+
columnId: string;
|
|
4
|
+
onClose: () => void;
|
|
5
|
+
};
|
|
6
|
+
declare const DeleteFieldConfirm: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
7
|
+
type DeleteFieldConfirm = ReturnType<typeof DeleteFieldConfirm>;
|
|
8
|
+
export default DeleteFieldConfirm;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* "Delete record?" from a row's or a card's menu, as the selection bar asks
|
|
4
|
+
* before it deletes: the record goes, and its links from other records.
|
|
5
|
+
*/
|
|
6
|
+
import { SvModal } from '@svgrid/grid'
|
|
7
|
+
import { primaryIdOf } from './grid-access'
|
|
8
|
+
import { deleteRecord } from './view-model'
|
|
9
|
+
|
|
10
|
+
let { ctrl, api, row, onClose }: { ctrl: any; api: any; row: unknown; onClose: () => void } = $props()
|
|
11
|
+
|
|
12
|
+
let open = $state(true)
|
|
13
|
+
// svelte-ignore state_referenced_locally
|
|
14
|
+
const primary = (ctrl.internalColumns as Array<Record<string, any>>).find((d) => String(d.id ?? d.field) === primaryIdOf(ctrl))
|
|
15
|
+
// svelte-ignore state_referenced_locally
|
|
16
|
+
const name = String((primary?.field ? (row as Record<string, unknown> | null)?.[primary.field] : '') ?? '').trim()
|
|
17
|
+
|
|
18
|
+
function close() {
|
|
19
|
+
open = false
|
|
20
|
+
onClose()
|
|
21
|
+
}
|
|
22
|
+
function remove() {
|
|
23
|
+
deleteRecord(ctrl, api, row)
|
|
24
|
+
close()
|
|
25
|
+
}
|
|
26
|
+
</script>
|
|
27
|
+
|
|
28
|
+
<SvModal bind:open title="Delete record?" width={420} onClose={close}>
|
|
29
|
+
<p class="sv-frdel-text">
|
|
30
|
+
{#if name}<strong>{name}</strong> is deleted{:else}This record is deleted{/if}, and its links from other records go with it.
|
|
31
|
+
</p>
|
|
32
|
+
{#snippet footer()}
|
|
33
|
+
<div class="sv-frdel-foot">
|
|
34
|
+
<button type="button" class="sv-frdel-btn" onclick={close}>Cancel</button>
|
|
35
|
+
<button type="button" class="sv-frdel-btn is-danger" onclick={remove}>Delete record</button>
|
|
36
|
+
</div>
|
|
37
|
+
{/snippet}
|
|
38
|
+
</SvModal>
|
|
39
|
+
|
|
40
|
+
<style>
|
|
41
|
+
.sv-frdel-text { margin: 0; font-size: 14px; line-height: 1.5; color: var(--sg-fg, #0f172a); }
|
|
42
|
+
.sv-frdel-foot { display: flex; justify-content: flex-end; gap: 8px; width: 100%; }
|
|
43
|
+
.sv-frdel-btn {
|
|
44
|
+
height: 32px; padding: 0 14px; font: inherit; font-size: 13px; cursor: pointer; border-radius: var(--sg-radius, 6px);
|
|
45
|
+
background: transparent; color: var(--sg-fg, #0f172a); border: 1px solid var(--sg-border, #e2e8f0);
|
|
46
|
+
}
|
|
47
|
+
.sv-frdel-btn.is-danger { background: var(--sg-danger, #dc2626); border-color: var(--sg-danger, #dc2626); color: #fff; }
|
|
48
|
+
</style>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type $$ComponentProps = {
|
|
2
|
+
ctrl: any;
|
|
3
|
+
api: any;
|
|
4
|
+
row: unknown;
|
|
5
|
+
onClose: () => void;
|
|
6
|
+
};
|
|
7
|
+
declare const DeleteRecordConfirm: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
8
|
+
type DeleteRecordConfirm = ReturnType<typeof DeleteRecordConfirm>;
|
|
9
|
+
export default DeleteRecordConfirm;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* The grid mounts this for every cell of a column with a `fieldType` whose
|
|
4
|
+
* type draws its own cell (registerGridExtension's `cell` + `hasCell`). It
|
|
5
|
+
* hands the cell to that type with the column's merged properties.
|
|
6
|
+
*/
|
|
7
|
+
import { fieldPropsOf, getFieldType, type FieldCellProps } from './registry.svelte'
|
|
8
|
+
|
|
9
|
+
let { ctrl, row, column, value }: Omit<FieldCellProps, 'props'> = $props()
|
|
10
|
+
const type = $derived(getFieldType(column.columnDef.fieldType))
|
|
11
|
+
const props = $derived(fieldPropsOf(column.columnDef as { fieldType?: unknown; fieldProps?: Record<string, unknown> }))
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
{#if type?.cell}
|
|
15
|
+
<type.cell {ctrl} {row} {column} {value} {props} />
|
|
16
|
+
{:else}
|
|
17
|
+
{value == null ? '' : String(value)}
|
|
18
|
+
{/if}
|
|
19
|
+
|
|
20
|
+
<style>
|
|
21
|
+
/* The view bar's filter (`fieldFilter`) shows on the bar's Filter button. */
|
|
22
|
+
:global(.sv-fields-own-filter .sv-grid-advf-chip) { display: none; }
|
|
23
|
+
:global(.sv-fields-own-filter .sv-grid-toolbar:not(:has(> :not(.sv-grid-advf-chip)))) { display: none; }
|
|
24
|
+
/* rowColor (row-colors.ts): the grid sets --sv-row-mark on each colored row
|
|
25
|
+
and a root class naming the target. Background-image layers, not
|
|
26
|
+
box-shadow: the grid draws the selection outline with box-shadow on
|
|
27
|
+
cells, and layers leave the cell's own background colour underneath. */
|
|
28
|
+
/* The header target is a 3px stripe on the row's leading edge: the color
|
|
29
|
+
says which group a row is in without tinting the row number under it. */
|
|
30
|
+
:global(.sv-fields-rowcolor-header tbody .sv-grid-row-number-cell) {
|
|
31
|
+
background-image: linear-gradient(to right, var(--sv-row-mark, transparent) 3px, transparent 3px);
|
|
32
|
+
}
|
|
33
|
+
:global(.sv-fields-rowcolor-header:dir(rtl) tbody .sv-grid-row-number-cell) {
|
|
34
|
+
background-image: linear-gradient(to left, var(--sv-row-mark, transparent) 3px, transparent 3px);
|
|
35
|
+
}
|
|
36
|
+
:global(.sv-fields-rowcolor-bar tbody tr > td:first-child) {
|
|
37
|
+
background-image: linear-gradient(to right, var(--sv-row-mark, transparent) 3px, transparent 3px);
|
|
38
|
+
}
|
|
39
|
+
:global(.sv-fields-rowcolor-bar:dir(rtl) tbody tr > td:first-child) {
|
|
40
|
+
background-image: linear-gradient(to left, var(--sv-row-mark, transparent) 3px, transparent 3px);
|
|
41
|
+
}
|
|
42
|
+
:global(.sv-fields-rowcolor-row tbody tr > td) {
|
|
43
|
+
background-image: linear-gradient(color-mix(in srgb, var(--sv-row-mark, transparent) 10%, transparent), color-mix(in srgb, var(--sv-row-mark, transparent) 10%, transparent));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/* Tall rows (row-colors.ts, tallRowClass): content starts at the top and
|
|
47
|
+
uses the height - text wraps to as many lines as fit, select pills wrap,
|
|
48
|
+
attachment thumbnails grow, a long text keeps its line breaks. */
|
|
49
|
+
:global(.sv-fields-lines-2) { --sv-lines: 2; --sv-thumb: 40px; }
|
|
50
|
+
:global(.sv-fields-lines-3) { --sv-lines: 3; --sv-thumb: 56px; }
|
|
51
|
+
:global(.sv-fields-lines-4) { --sv-lines: 4; --sv-thumb: 72px; }
|
|
52
|
+
:global(.sv-fields-lines-5) { --sv-lines: 5; --sv-thumb: 92px; }
|
|
53
|
+
:global(.sv-fields-lines-6) { --sv-lines: 6; --sv-thumb: 108px; }
|
|
54
|
+
:global(.sv-fields-tall tbody > tr > td.sv-grid-cell) {
|
|
55
|
+
align-items: flex-start;
|
|
56
|
+
padding-block: 6px;
|
|
57
|
+
}
|
|
58
|
+
:global(.sv-fields-tall tbody > tr > td > .sv-grid-cell-line) {
|
|
59
|
+
display: -webkit-box;
|
|
60
|
+
-webkit-box-orient: vertical;
|
|
61
|
+
-webkit-line-clamp: var(--sv-lines, 2);
|
|
62
|
+
line-clamp: var(--sv-lines, 2);
|
|
63
|
+
white-space: normal;
|
|
64
|
+
overflow-wrap: anywhere;
|
|
65
|
+
line-height: 20px;
|
|
66
|
+
}
|
|
67
|
+
:global(.sv-fields-tall .sv-fsl) {
|
|
68
|
+
flex-wrap: wrap;
|
|
69
|
+
align-content: flex-start;
|
|
70
|
+
}
|
|
71
|
+
/* tbody td: one more than the attachment cell's own scoped rule, so this wins. */
|
|
72
|
+
:global(.sv-fields-tall tbody td .sv-att-thumb) {
|
|
73
|
+
width: var(--sv-thumb, 26px);
|
|
74
|
+
height: var(--sv-thumb, 26px);
|
|
75
|
+
}
|
|
76
|
+
:global(.sv-fields-tall .sv-frx-sep) {
|
|
77
|
+
display: block;
|
|
78
|
+
height: 0;
|
|
79
|
+
}
|
|
80
|
+
</style>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The grid mounts this for every cell of a column with a `fieldType` whose
|
|
3
|
+
* type draws its own cell (registerGridExtension's `cell` + `hasCell`). It
|
|
4
|
+
* hands the cell to that type with the column's merged properties.
|
|
5
|
+
*/
|
|
6
|
+
import { type FieldCellProps } from './registry.svelte.js';
|
|
7
|
+
declare const FieldCell: import("svelte").Component<Omit<FieldCellProps, "props">, {}, "">;
|
|
8
|
+
type FieldCell = ReturnType<typeof FieldCell>;
|
|
9
|
+
export default FieldCell;
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* The field editor: name, type, the type's properties, a description. Adds
|
|
4
|
+
* a field (column adder, Insert left / right) or edits one (Edit field). On a
|
|
5
|
+
* type change it says how many cells would be cleared before applying.
|
|
6
|
+
*/
|
|
7
|
+
import { SvModal } from '@svgrid/grid'
|
|
8
|
+
import PropertyInput from './PropertyInput.svelte'
|
|
9
|
+
import { listFieldTypes, getFieldType, originalColumn, type FieldEditorContext } from './registry.svelte'
|
|
10
|
+
import { addField, defId, nameTaken, plainDef, previewChange, updateField } from './field-ops'
|
|
11
|
+
import { columnResolver, formulaError } from './formula'
|
|
12
|
+
|
|
13
|
+
let {
|
|
14
|
+
ctrl,
|
|
15
|
+
mode,
|
|
16
|
+
columnId,
|
|
17
|
+
index = 'end',
|
|
18
|
+
onClose,
|
|
19
|
+
}: {
|
|
20
|
+
ctrl: any
|
|
21
|
+
mode: 'add' | 'edit'
|
|
22
|
+
columnId?: string
|
|
23
|
+
index?: number | 'end'
|
|
24
|
+
onClose: () => void
|
|
25
|
+
} = $props()
|
|
26
|
+
|
|
27
|
+
// svelte-ignore state_referenced_locally
|
|
28
|
+
const existing = mode === 'edit' && columnId ? ctrl.internalColumns.find((d: any) => defId(d) === columnId) : null
|
|
29
|
+
// svelte-ignore state_referenced_locally
|
|
30
|
+
const plain = existing ? plainDef(existing) : null
|
|
31
|
+
|
|
32
|
+
const allowed = $derived.by(() => {
|
|
33
|
+
const cfg = ctrl.props.columnAdder
|
|
34
|
+
const ids = cfg && typeof cfg === 'object' && Array.isArray(cfg.types) ? (cfg.types as string[]) : null
|
|
35
|
+
const types = listFieldTypes()
|
|
36
|
+
return ids ? ids.map((id) => types.find((t) => t.id === id)).filter((t) => !!t) : types.filter((t) => !t.editAs)
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
// A currency or percent column opens as a number field in that format.
|
|
40
|
+
// svelte-ignore state_referenced_locally
|
|
41
|
+
const alias = getFieldType(plain?.fieldType)?.editAs
|
|
42
|
+
let name = $state(String(plain?.header ?? ''))
|
|
43
|
+
let fieldType = $state(alias?.type ?? String(plain?.fieldType ?? 'text'))
|
|
44
|
+
let props = $state<Record<string, any>>({ ...((plain?.fieldProps as Record<string, unknown>) ?? {}), ...(alias?.props ?? {}) })
|
|
45
|
+
let description = $state(String(plain?.description ?? ''))
|
|
46
|
+
let search = $state('')
|
|
47
|
+
// The type list is open while choosing (a new field starts there) and folds
|
|
48
|
+
// into a selector once a type is picked, so its options sit near the top.
|
|
49
|
+
// svelte-ignore state_referenced_locally
|
|
50
|
+
let pickerOpen = $state(mode === 'add')
|
|
51
|
+
let open = $state(true)
|
|
52
|
+
|
|
53
|
+
const type = $derived(getFieldType(fieldType))
|
|
54
|
+
const shownTypes = $derived(allowed.filter((t) => !search || t.label.toLowerCase().includes(search.toLowerCase())))
|
|
55
|
+
// A field left unnamed is named after its type, numbered when taken
|
|
56
|
+
// ("Number", "Number 2"); an edited field keeps needing a name.
|
|
57
|
+
const fallbackName = $derived.by(() => {
|
|
58
|
+
const base = type?.label ?? 'Field'
|
|
59
|
+
let n = base
|
|
60
|
+
for (let i = 2; nameTaken(ctrl, n, columnId); i++) n = `${base} ${i}`
|
|
61
|
+
return n
|
|
62
|
+
})
|
|
63
|
+
const finalName = $derived(name.trim() || (mode === 'add' ? fallbackName : ''))
|
|
64
|
+
const nameError = $derived(!finalName ? 'A field needs a name' : nameTaken(ctrl, finalName, columnId) ? 'Another field has this name' : null)
|
|
65
|
+
const cleared = $derived(mode === 'edit' && columnId ? previewChange(ctrl, columnId, { name, fieldType, fieldProps: props }) : 0)
|
|
66
|
+
// The stored type: what updateField converts from on save, alias or not.
|
|
67
|
+
const fromType = plain?.fieldType ? String(plain.fieldType) : undefined
|
|
68
|
+
// An alias opened as its target (Currency as Number) converts on save too;
|
|
69
|
+
// say so only when that clears cells, or the type was changed on purpose.
|
|
70
|
+
const warn = $derived(mode === 'edit' && !!fromType && fromType !== fieldType && (fieldType !== alias?.type || cleared > 0))
|
|
71
|
+
|
|
72
|
+
// Event readers live here, not in the markup: AGENTS.md keeps `as` casts in <script>.
|
|
73
|
+
const inputValue = (e: Event) => (e.currentTarget as HTMLInputElement).value
|
|
74
|
+
|
|
75
|
+
function pickType(id: string) {
|
|
76
|
+
if (id === fieldType) return
|
|
77
|
+
fieldType = id
|
|
78
|
+
pickerOpen = false
|
|
79
|
+
search = ''
|
|
80
|
+
// Keep only the properties the new type has, starting from its defaults.
|
|
81
|
+
const next = getFieldType(id)
|
|
82
|
+
const keep: Record<string, any> = { ...(next?.defaults ?? {}) }
|
|
83
|
+
for (const p of next?.properties ?? []) if (props[p.key] !== undefined) keep[p.key] = props[p.key]
|
|
84
|
+
props = keep
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// What a property's dynamic choices and the formula see: the draft and every other field.
|
|
88
|
+
const editorCtx = $derived<FieldEditorContext>({
|
|
89
|
+
ctrl,
|
|
90
|
+
props: { ...(type?.defaults ?? {}), ...props },
|
|
91
|
+
columns: (ctrl.internalColumns as Array<Record<string, any>>).map((c) => originalColumn(c)).filter((c) => defId(c) !== columnId),
|
|
92
|
+
// A formula may not read its own field, by any of its names.
|
|
93
|
+
self: [plain?.field, columnId, plain?.header, finalName],
|
|
94
|
+
})
|
|
95
|
+
const shownProps = $derived((type?.properties ?? []).filter((p) => !p.visible || p.visible(editorCtx.props)))
|
|
96
|
+
// A formula that does not compile cannot be saved; the box shows why. An
|
|
97
|
+
// empty one can: its cells stay empty until it is written.
|
|
98
|
+
const formulaProblem = $derived.by(() => {
|
|
99
|
+
for (const p of shownProps) {
|
|
100
|
+
if (p.kind !== 'formula') continue
|
|
101
|
+
const src = String(editorCtx.props[p.key] ?? '')
|
|
102
|
+
const message = src.trim() ? formulaError(src, columnResolver(editorCtx.columns, editorCtx.self)) : null
|
|
103
|
+
if (message) return message
|
|
104
|
+
}
|
|
105
|
+
return null
|
|
106
|
+
})
|
|
107
|
+
// Every group a type may name; an empty one is not drawn.
|
|
108
|
+
const GROUPS = [
|
|
109
|
+
{ id: 'basic', label: 'Fields' },
|
|
110
|
+
{ id: 'number', label: 'Numbers and time' },
|
|
111
|
+
{ id: 'date', label: 'Dates' },
|
|
112
|
+
{ id: 'people', label: 'People' },
|
|
113
|
+
{ id: 'computed', label: 'Computed and automatic' },
|
|
114
|
+
{ id: 'relation', label: 'Other tables' },
|
|
115
|
+
] as const
|
|
116
|
+
// A group the list does not know (a typo in a registered type) shows under Fields.
|
|
117
|
+
const groupOf = (t: { group?: string }) => (GROUPS.some((g) => g.id === t.group) ? t.group : 'basic')
|
|
118
|
+
const grouped = $derived(
|
|
119
|
+
GROUPS.map((g) => ({ ...g, types: shownTypes.filter((t) => groupOf(t) === g.id) })).filter((g) => g.types.length),
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
function save() {
|
|
123
|
+
if (nameError || formulaProblem) return
|
|
124
|
+
const draft = { name: finalName, fieldType, fieldProps: $state.snapshot(props), description }
|
|
125
|
+
if (mode === 'edit' && columnId) updateField(ctrl, columnId, draft)
|
|
126
|
+
else addField(ctrl, draft, index)
|
|
127
|
+
close()
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function close() {
|
|
131
|
+
open = false
|
|
132
|
+
onClose()
|
|
133
|
+
}
|
|
134
|
+
</script>
|
|
135
|
+
|
|
136
|
+
<SvModal bind:open title={mode === 'edit' ? 'Edit field' : 'Add field'} width={500} onClose={close}>
|
|
137
|
+
<form class="sv-fed" onsubmit={(e) => { e.preventDefault(); save() }}>
|
|
138
|
+
<div class="sv-fed-group">
|
|
139
|
+
<label class="sv-fed-label" for="sv-fed-name">Name</label>
|
|
140
|
+
<!-- svelte-ignore a11y_autofocus -->
|
|
141
|
+
<input
|
|
142
|
+
id="sv-fed-name"
|
|
143
|
+
class="sv-fed-input"
|
|
144
|
+
placeholder={mode === 'add' ? fallbackName : 'Field name'}
|
|
145
|
+
bind:value={name}
|
|
146
|
+
autofocus
|
|
147
|
+
autocomplete="off"
|
|
148
|
+
aria-invalid={!!nameError && name.length > 0}
|
|
149
|
+
aria-describedby="sv-fed-name-error"
|
|
150
|
+
/>
|
|
151
|
+
{#if nameError && name.length > 0}<p id="sv-fed-name-error" class="sv-fed-error">{nameError}</p>{/if}
|
|
152
|
+
</div>
|
|
153
|
+
|
|
154
|
+
<div class="sv-fed-group">
|
|
155
|
+
<span class="sv-fed-label" id="sv-fed-type-label">Field type</span>
|
|
156
|
+
{#if !pickerOpen}
|
|
157
|
+
<button type="button" class="sv-fed-current" aria-expanded="false" aria-labelledby="sv-fed-type-label" onclick={() => (pickerOpen = true)}>
|
|
158
|
+
<span class="sv-fed-type-icon" aria-hidden="true">
|
|
159
|
+
{#if type?.icon}<svg viewBox="0 0 24 24" width="14" height="14"><path d={type.icon} fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" /></svg>{/if}
|
|
160
|
+
</span>
|
|
161
|
+
<span class="sv-fed-type-label">{type?.label ?? fieldType}</span>
|
|
162
|
+
<svg class="sv-fed-chevron" viewBox="0 0 24 24" width="14" height="14" aria-hidden="true"><path d="M6 9l6 6 6-6" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" /></svg>
|
|
163
|
+
</button>
|
|
164
|
+
{:else}
|
|
165
|
+
{#if allowed.length > 8}
|
|
166
|
+
<div class="sv-fed-search">
|
|
167
|
+
<svg viewBox="0 0 24 24" width="14" height="14" aria-hidden="true"><path d="M11 4a7 7 0 1 0 0 14 7 7 0 0 0 0-14zM20 20l-4-4" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" /></svg>
|
|
168
|
+
<input class="sv-fed-input" placeholder="Find a type" aria-label="Find a field type" bind:value={search} />
|
|
169
|
+
</div>
|
|
170
|
+
{/if}
|
|
171
|
+
<div class="sv-fed-types-scroll" role="radiogroup" aria-labelledby="sv-fed-type-label">
|
|
172
|
+
{#each grouped as g (g.id)}
|
|
173
|
+
<div class="sv-fed-type-group">{g.label}</div>
|
|
174
|
+
<div class="sv-fed-types">
|
|
175
|
+
{#each g.types as t (t.id)}
|
|
176
|
+
<button
|
|
177
|
+
type="button"
|
|
178
|
+
class="sv-fed-type"
|
|
179
|
+
class:is-on={t.id === fieldType}
|
|
180
|
+
role="radio"
|
|
181
|
+
aria-checked={t.id === fieldType}
|
|
182
|
+
onclick={() => pickType(t.id)}
|
|
183
|
+
>
|
|
184
|
+
<span class="sv-fed-type-icon" aria-hidden="true">
|
|
185
|
+
{#if t.icon}
|
|
186
|
+
<svg viewBox="0 0 24 24" width="14" height="14"><path d={t.icon} fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" /></svg>
|
|
187
|
+
{/if}
|
|
188
|
+
</span>
|
|
189
|
+
<span class="sv-fed-type-label">{t.label}</span>
|
|
190
|
+
</button>
|
|
191
|
+
{/each}
|
|
192
|
+
</div>
|
|
193
|
+
{:else}
|
|
194
|
+
<p class="sv-fed-none">No type matches "{search}".</p>
|
|
195
|
+
{/each}
|
|
196
|
+
</div>
|
|
197
|
+
{/if}
|
|
198
|
+
{#if type?.description}<p class="sv-fed-hint-line">{type.description}</p>{/if}
|
|
199
|
+
</div>
|
|
200
|
+
|
|
201
|
+
{#if shownProps.length}
|
|
202
|
+
<div class="sv-fed-group sv-fed-props">
|
|
203
|
+
{#each shownProps as p (p.key)}
|
|
204
|
+
<PropertyInput
|
|
205
|
+
def={p}
|
|
206
|
+
value={props[p.key] ?? type?.defaults?.[p.key]}
|
|
207
|
+
{fieldType}
|
|
208
|
+
ctx={editorCtx}
|
|
209
|
+
onChange={(v) => (props = { ...props, [p.key]: v, ...(p.alsoSets?.(v, editorCtx.props) ?? {}) })}
|
|
210
|
+
/>
|
|
211
|
+
{/each}
|
|
212
|
+
</div>
|
|
213
|
+
{/if}
|
|
214
|
+
|
|
215
|
+
<div class="sv-fed-group">
|
|
216
|
+
<label class="sv-fed-label" for="sv-fed-desc">Description <span class="sv-fed-optional">optional</span></label>
|
|
217
|
+
<textarea id="sv-fed-desc" class="sv-fed-input sv-fed-desc" rows="2" placeholder="What goes in this field" bind:value={description}></textarea>
|
|
218
|
+
</div>
|
|
219
|
+
|
|
220
|
+
{#if warn && fromType}
|
|
221
|
+
<p class="sv-fed-warning" role="status">
|
|
222
|
+
<svg viewBox="0 0 24 24" width="15" height="15" aria-hidden="true"><path d="M12 4 2.5 20h19zM12 10v4M12 17h.01" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /></svg>
|
|
223
|
+
<span>
|
|
224
|
+
{getFieldType(fromType)?.label ?? fromType} to {type?.label ?? fieldType} converts the values.
|
|
225
|
+
{cleared === 0 ? 'Every value converts.' : `${cleared} cell${cleared === 1 ? '' : 's'} will be cleared or cut short.`}
|
|
226
|
+
</span>
|
|
227
|
+
</p>
|
|
228
|
+
{/if}
|
|
229
|
+
</form>
|
|
230
|
+
{#snippet footer()}
|
|
231
|
+
<div class="sv-fed-footer">
|
|
232
|
+
<button type="button" class="sv-fed-btn" onclick={close}>Cancel</button>
|
|
233
|
+
<button type="button" class="sv-fed-btn is-primary" disabled={!!nameError || !!formulaProblem} title={formulaProblem ? `Fix the formula first: ${formulaProblem}` : undefined} onclick={save}>
|
|
234
|
+
{mode === 'edit' ? 'Save' : 'Create field'}
|
|
235
|
+
</button>
|
|
236
|
+
</div>
|
|
237
|
+
{/snippet}
|
|
238
|
+
</SvModal>
|
|
239
|
+
|
|
240
|
+
<style>
|
|
241
|
+
/* Only tokens every theme defines (bg, fg, border, muted, header-bg,
|
|
242
|
+
row-hover-bg, input-bg, input-border, accent, selection-bg, radius): the
|
|
243
|
+
dialog renders under <body>, outside the grid, and a missing token falls
|
|
244
|
+
back to its light default even in a dark theme. */
|
|
245
|
+
.sv-fed { display: flex; flex-direction: column; gap: 18px; }
|
|
246
|
+
.sv-fed-group { display: flex; flex-direction: column; gap: 6px; }
|
|
247
|
+
.sv-fed-props {
|
|
248
|
+
gap: 10px; padding: 12px; border-radius: var(--sg-radius, 6px);
|
|
249
|
+
background: var(--sg-header-bg, #f8fafc); border: 1px solid var(--sg-border, #e2e8f0);
|
|
250
|
+
}
|
|
251
|
+
.sv-fed-label { font-size: 12px; font-weight: 600; color: var(--sg-fg, #0f172a); }
|
|
252
|
+
.sv-fed-optional { font-weight: 400; color: var(--sg-muted, #64748b); }
|
|
253
|
+
.sv-fed-input {
|
|
254
|
+
width: 100%; box-sizing: border-box; height: 34px; padding: 0 10px; font: inherit; font-size: 14px;
|
|
255
|
+
border: 1px solid var(--sg-input-border, var(--sg-border, #e2e8f0)); border-radius: var(--sg-radius, 6px);
|
|
256
|
+
background: var(--sg-input-bg, var(--sg-bg, #fff)); color: var(--sg-fg, #0f172a);
|
|
257
|
+
transition: border-color 120ms ease, box-shadow 120ms ease;
|
|
258
|
+
}
|
|
259
|
+
.sv-fed-input::placeholder { color: var(--sg-muted, #94a3b8); }
|
|
260
|
+
.sv-fed-input:focus { outline: none; border-color: var(--sg-accent, #2563eb); box-shadow: 0 0 0 3px color-mix(in srgb, var(--sg-accent, #2563eb) 22%, transparent); }
|
|
261
|
+
.sv-fed-input[aria-invalid='true'] { border-color: var(--sg-danger, #dc2626); }
|
|
262
|
+
.sv-fed-desc { height: auto; min-height: 58px; padding: 8px 10px; resize: vertical; line-height: 1.4; }
|
|
263
|
+
.sv-fed-error { margin: 0; font-size: 12px; color: var(--sg-danger, #dc2626); }
|
|
264
|
+
.sv-fed-search { position: relative; display: flex; align-items: center; color: var(--sg-muted, #64748b); }
|
|
265
|
+
.sv-fed-search svg { position: absolute; inset-inline-start: 10px; pointer-events: none; }
|
|
266
|
+
.sv-fed-search .sv-fed-input { height: 30px; padding-inline-start: 30px; font-size: 13px; }
|
|
267
|
+
.sv-fed-current {
|
|
268
|
+
display: flex; align-items: center; gap: 10px; width: 100%; height: 38px; padding: 0 10px;
|
|
269
|
+
border: 1px solid var(--sg-input-border, var(--sg-border, #e2e8f0)); border-radius: var(--sg-radius, 6px);
|
|
270
|
+
background: var(--sg-input-bg, var(--sg-bg, #fff)); color: var(--sg-fg, #0f172a); font: inherit; font-size: 14px; text-align: start; cursor: pointer;
|
|
271
|
+
}
|
|
272
|
+
.sv-fed-current:hover { border-color: var(--sg-muted, #94a3b8); }
|
|
273
|
+
.sv-fed-current:focus-visible { outline: none; border-color: var(--sg-accent, #2563eb); box-shadow: 0 0 0 3px color-mix(in srgb, var(--sg-accent, #2563eb) 22%, transparent); }
|
|
274
|
+
.sv-fed-current .sv-fed-type-label { flex: 1; }
|
|
275
|
+
.sv-fed-chevron { flex: none; color: var(--sg-muted, #64748b); }
|
|
276
|
+
.sv-fed-types-scroll { max-height: 300px; overflow: auto; margin-top: 2px; padding-inline-end: 2px; }
|
|
277
|
+
.sv-fed-types { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 2px; }
|
|
278
|
+
.sv-fed-type-group {
|
|
279
|
+
margin: 10px 0 4px; font-size: 11px; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase;
|
|
280
|
+
color: var(--sg-muted, #64748b);
|
|
281
|
+
}
|
|
282
|
+
.sv-fed-type-group:first-child { margin-top: 2px; }
|
|
283
|
+
.sv-fed-type {
|
|
284
|
+
display: flex; align-items: center; gap: 10px; height: 34px; padding: 0 8px;
|
|
285
|
+
border: 1px solid transparent; border-radius: var(--sg-radius, 6px); background: none;
|
|
286
|
+
color: var(--sg-fg, #0f172a); font: inherit; font-size: 13px; text-align: start; cursor: pointer;
|
|
287
|
+
}
|
|
288
|
+
.sv-fed-type:hover { background: var(--sg-row-hover-bg, #f1f5f9); }
|
|
289
|
+
.sv-fed-type.is-on { background: var(--sg-selection-bg, #eef4ff); border-color: var(--sg-accent, #2563eb); }
|
|
290
|
+
.sv-fed-type:focus-visible { outline: 2px solid var(--sg-accent, #2563eb); outline-offset: 1px; }
|
|
291
|
+
.sv-fed-type-icon {
|
|
292
|
+
flex: none; display: inline-flex; align-items: center; justify-content: center;
|
|
293
|
+
width: 24px; height: 24px; border-radius: 6px;
|
|
294
|
+
background: var(--sg-header-bg, #f8fafc); border: 1px solid var(--sg-border, #e2e8f0);
|
|
295
|
+
color: var(--sg-muted, #64748b);
|
|
296
|
+
}
|
|
297
|
+
.sv-fed-type.is-on .sv-fed-type-icon { color: var(--sg-accent, #2563eb); border-color: color-mix(in srgb, var(--sg-accent, #2563eb) 40%, transparent); }
|
|
298
|
+
.sv-fed-type-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
299
|
+
.sv-fed-none { grid-column: 1 / -1; margin: 8px 0; font-size: 13px; color: var(--sg-muted, #64748b); }
|
|
300
|
+
.sv-fed-hint-line { margin: 2px 0 0; font-size: 12px; color: var(--sg-muted, #64748b); }
|
|
301
|
+
.sv-fed-warning {
|
|
302
|
+
display: flex; gap: 8px; align-items: flex-start; margin: 0; padding: 10px 12px;
|
|
303
|
+
border-radius: var(--sg-radius, 6px); font-size: 13px; line-height: 1.4; color: var(--sg-fg, #0f172a);
|
|
304
|
+
background: color-mix(in srgb, var(--sg-warning, #f59e0b) 14%, transparent);
|
|
305
|
+
border: 1px solid color-mix(in srgb, var(--sg-warning, #f59e0b) 35%, transparent);
|
|
306
|
+
}
|
|
307
|
+
.sv-fed-warning svg { flex: none; margin-top: 1px; color: var(--sg-warning, #d97706); }
|
|
308
|
+
.sv-fed-footer { display: flex; justify-content: flex-end; gap: 8px; width: 100%; }
|
|
309
|
+
.sv-fed-btn {
|
|
310
|
+
height: 34px; padding: 0 16px; font: inherit; font-size: 13px; font-weight: 500; cursor: pointer;
|
|
311
|
+
border: 1px solid var(--sg-border, #e2e8f0); border-radius: var(--sg-radius, 6px);
|
|
312
|
+
background: var(--sg-bg, #fff); color: var(--sg-fg, #0f172a);
|
|
313
|
+
}
|
|
314
|
+
.sv-fed-btn:hover { background: var(--sg-row-hover-bg, #f1f5f9); }
|
|
315
|
+
.sv-fed-btn:focus-visible { outline: 2px solid var(--sg-accent, #2563eb); outline-offset: 2px; }
|
|
316
|
+
/* Primary is the inverted pair (fg on bg), not the accent: on Ember the
|
|
317
|
+
accent means selection and focus. */
|
|
318
|
+
.sv-fed-btn.is-primary { background: var(--sg-fg, #0f172a); color: var(--sg-bg, #fff); border-color: var(--sg-fg, #0f172a); }
|
|
319
|
+
.sv-fed-btn.is-primary:hover { opacity: 0.9; }
|
|
320
|
+
.sv-fed-btn:disabled { opacity: 0.4; cursor: not-allowed; }
|
|
321
|
+
</style>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
type $$ComponentProps = {
|
|
2
|
+
ctrl: any;
|
|
3
|
+
mode: 'add' | 'edit';
|
|
4
|
+
columnId?: string;
|
|
5
|
+
index?: number | 'end';
|
|
6
|
+
onClose: () => void;
|
|
7
|
+
};
|
|
8
|
+
declare const FieldEditor: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
9
|
+
type FieldEditor = ReturnType<typeof FieldEditor>;
|
|
10
|
+
export default FieldEditor;
|