@svgrid/enterprise 3.1.8 → 3.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (268) hide show
  1. package/README.md +1 -0
  2. package/dist/SvAlertRuleEditor.svelte +16 -5
  3. package/dist/SvGridAlerts.svelte +8 -0
  4. package/dist/SvGridAlerts.svelte.d.ts +4 -0
  5. package/dist/SvGridBoard.svelte +69 -10
  6. package/dist/SvGridBulkEditDrawer.svelte +13 -5
  7. package/dist/SvGridGallery.svelte +286 -0
  8. package/dist/SvGridGallery.svelte.d.ts +30 -0
  9. package/dist/SvGridScheduler.svelte +33 -11
  10. package/dist/SvGridSelectionBar.svelte +47 -0
  11. package/dist/advanced-filter/expr-columns-from-grid.d.ts +1 -0
  12. package/dist/advanced-filter/expr-columns-from-grid.js +11 -7
  13. package/dist/advanced-filter-enable.d.ts +6 -0
  14. package/dist/advanced-filter-enable.js +8 -0
  15. package/dist/alerts/alert-engine.d.ts +7 -0
  16. package/dist/alerts/alert-engine.js +5 -2
  17. package/dist/alerts/condition-editor.d.ts +26 -0
  18. package/dist/alerts/condition-editor.js +17 -0
  19. package/dist/base/index.d.ts +20 -0
  20. package/dist/base/index.js +20 -0
  21. package/dist/bulk-edit.d.ts +11 -0
  22. package/dist/bulk-edit.js +18 -1
  23. package/dist/cdn/svgrid-enterprise.svelte-external.js +11197 -10639
  24. package/dist/designer/assets/GridFooter-Cu8_yBlQ.js +2 -0
  25. package/dist/designer/assets/GridMenus-BUjkkAU2.js +6 -0
  26. package/dist/designer/assets/PinSplitter-BgTpgh1d.css +1 -0
  27. package/dist/designer/assets/PinSplitter-C5AwA1xV.js +1 -0
  28. package/dist/designer/assets/SvGrid.helpers-CIrmIo9U.js +1 -0
  29. package/dist/designer/assets/SvGridCellEditor-CJxThKL_.js +4 -0
  30. package/dist/designer/assets/SvListBox-CS7oUAiX.js +2 -0
  31. package/dist/designer/assets/conditional-formatting-MDWbF8_Y.js +1 -0
  32. package/dist/designer/assets/grid-extension.svelte-BZ7AqyJI.js +1 -0
  33. package/dist/designer/assets/{index-Obk8sI77.js → index-BPU2KNc5.js} +307 -307
  34. package/dist/designer/assets/index-BmvG99kR.css +1 -0
  35. package/dist/designer/assets/sparkline-C-NcnB2i.js +1 -0
  36. package/dist/designer/assets/src-C_U1NKOY.js +58 -0
  37. package/dist/designer/assets/sv-grid-scrollbar-B9N6Wuj0.js +109 -0
  38. package/dist/designer/assets/validate-H5u2HEQh.js +1 -0
  39. package/dist/designer/index.html +11 -7
  40. package/dist/expressions/compile.js +10 -0
  41. package/dist/expressions/evaluate.js +18 -0
  42. package/dist/expressions/expression-types.d.ts +10 -0
  43. package/dist/expressions/kinds.d.ts +28 -0
  44. package/dist/expressions/kinds.js +19 -0
  45. package/dist/expressions/parse.js +9 -1
  46. package/dist/fields/AttachmentCell.svelte +242 -0
  47. package/dist/fields/AttachmentCell.svelte.d.ts +5 -0
  48. package/dist/fields/AttachmentDialog.svelte +357 -0
  49. package/dist/fields/AttachmentDialog.svelte.d.ts +13 -0
  50. package/dist/fields/AttachmentEditor.svelte +41 -0
  51. package/dist/fields/AttachmentEditor.svelte.d.ts +11 -0
  52. package/dist/fields/AttachmentPreview.svelte +72 -0
  53. package/dist/fields/AttachmentPreview.svelte.d.ts +8 -0
  54. package/dist/fields/BarcodeCell.svelte +20 -0
  55. package/dist/fields/BarcodeCell.svelte.d.ts +5 -0
  56. package/dist/fields/BaseAutomations.svelte +558 -0
  57. package/dist/fields/BaseAutomations.svelte.d.ts +18 -0
  58. package/dist/fields/BaseChartView.svelte +47 -0
  59. package/dist/fields/BaseChartView.svelte.d.ts +8 -0
  60. package/dist/fields/BaseTableView.svelte +185 -0
  61. package/dist/fields/BaseTableView.svelte.d.ts +37 -0
  62. package/dist/fields/BaseTabs.svelte +308 -0
  63. package/dist/fields/BaseTabs.svelte.d.ts +21 -0
  64. package/dist/fields/ButtonCell.svelte +47 -0
  65. package/dist/fields/ButtonCell.svelte.d.ts +20 -0
  66. package/dist/fields/CheckboxCell.svelte +46 -0
  67. package/dist/fields/CheckboxCell.svelte.d.ts +14 -0
  68. package/dist/fields/DeleteFieldConfirm.svelte +80 -0
  69. package/dist/fields/DeleteFieldConfirm.svelte.d.ts +8 -0
  70. package/dist/fields/DeleteRecordConfirm.svelte +48 -0
  71. package/dist/fields/DeleteRecordConfirm.svelte.d.ts +9 -0
  72. package/dist/fields/FieldCell.svelte +80 -0
  73. package/dist/fields/FieldCell.svelte.d.ts +9 -0
  74. package/dist/fields/FieldEditor.svelte +321 -0
  75. package/dist/fields/FieldEditor.svelte.d.ts +10 -0
  76. package/dist/fields/FieldInput.svelte +188 -0
  77. package/dist/fields/FieldInput.svelte.d.ts +29 -0
  78. package/dist/fields/FieldsHeaderEnd.svelte +146 -0
  79. package/dist/fields/FieldsHeaderEnd.svelte.d.ts +6 -0
  80. package/dist/fields/FootRowAdder.svelte +8 -0
  81. package/dist/fields/FootRowAdder.svelte.d.ts +6 -0
  82. package/dist/fields/GroupHeader.svelte +127 -0
  83. package/dist/fields/GroupHeader.svelte.d.ts +24 -0
  84. package/dist/fields/LinkCell.svelte +46 -0
  85. package/dist/fields/LinkCell.svelte.d.ts +9 -0
  86. package/dist/fields/LinkPickerEditor.svelte +172 -0
  87. package/dist/fields/LinkPickerEditor.svelte.d.ts +9 -0
  88. package/dist/fields/LinkPreview.svelte +60 -0
  89. package/dist/fields/LinkPreview.svelte.d.ts +7 -0
  90. package/dist/fields/LinkedRecordView.svelte +94 -0
  91. package/dist/fields/LinkedRecordView.svelte.d.ts +9 -0
  92. package/dist/fields/LinkedRecordsCell.svelte +59 -0
  93. package/dist/fields/LinkedRecordsCell.svelte.d.ts +11 -0
  94. package/dist/fields/LongTextEditor.svelte +157 -0
  95. package/dist/fields/LongTextEditor.svelte.d.ts +11 -0
  96. package/dist/fields/NumberEditor.svelte +309 -0
  97. package/dist/fields/NumberEditor.svelte.d.ts +12 -0
  98. package/dist/fields/OptionsEditor.svelte +117 -0
  99. package/dist/fields/OptionsEditor.svelte.d.ts +11 -0
  100. package/dist/fields/PercentCell.svelte +21 -0
  101. package/dist/fields/PercentCell.svelte.d.ts +8 -0
  102. package/dist/fields/PropertyInput.svelte +204 -0
  103. package/dist/fields/PropertyInput.svelte.d.ts +11 -0
  104. package/dist/fields/RatingCell.svelte +75 -0
  105. package/dist/fields/RatingCell.svelte.d.ts +16 -0
  106. package/dist/fields/RatingEditor.svelte +82 -0
  107. package/dist/fields/RatingEditor.svelte.d.ts +9 -0
  108. package/dist/fields/RecordView.svelte +310 -0
  109. package/dist/fields/RecordView.svelte.d.ts +11 -0
  110. package/dist/fields/RichTextCell.svelte +30 -0
  111. package/dist/fields/RichTextCell.svelte.d.ts +5 -0
  112. package/dist/fields/RowAdder.svelte +93 -0
  113. package/dist/fields/RowAdder.svelte.d.ts +7 -0
  114. package/dist/fields/RowHeader.svelte +99 -0
  115. package/dist/fields/RowHeader.svelte.d.ts +11 -0
  116. package/dist/fields/SelectCell.svelte +35 -0
  117. package/dist/fields/SelectCell.svelte.d.ts +15 -0
  118. package/dist/fields/SelectEditor.svelte +350 -0
  119. package/dist/fields/SelectEditor.svelte.d.ts +17 -0
  120. package/dist/fields/SummaryCell.svelte +160 -0
  121. package/dist/fields/SummaryCell.svelte.d.ts +11 -0
  122. package/dist/fields/SvBase.svelte +545 -0
  123. package/dist/fields/SvBase.svelte.d.ts +30 -0
  124. package/dist/fields/SvBaseForm.svelte +295 -0
  125. package/dist/fields/SvBaseForm.svelte.d.ts +22 -0
  126. package/dist/fields/SvBaseViewBar.svelte +644 -0
  127. package/dist/fields/SvBaseViewBar.svelte.d.ts +26 -0
  128. package/dist/fields/UserCell.svelte +39 -0
  129. package/dist/fields/UserCell.svelte.d.ts +9 -0
  130. package/dist/fields/UserFace.svelte +30 -0
  131. package/dist/fields/UserFace.svelte.d.ts +12 -0
  132. package/dist/fields/activity.svelte.d.ts +50 -0
  133. package/dist/fields/activity.svelte.js +110 -0
  134. package/dist/fields/attachments.d.ts +95 -0
  135. package/dist/fields/attachments.js +145 -0
  136. package/dist/fields/automation-outbound.d.ts +46 -0
  137. package/dist/fields/automation-outbound.js +61 -0
  138. package/dist/fields/automation-server.d.ts +53 -0
  139. package/dist/fields/automation-server.js +333 -0
  140. package/dist/fields/automations.svelte.d.ts +208 -0
  141. package/dist/fields/automations.svelte.js +437 -0
  142. package/dist/fields/bar-request.svelte.d.ts +16 -0
  143. package/dist/fields/bar-request.svelte.js +15 -0
  144. package/dist/fields/base-alerts.d.ts +24 -0
  145. package/dist/fields/base-alerts.js +64 -0
  146. package/dist/fields/base-connect.d.ts +82 -0
  147. package/dist/fields/base-connect.js +271 -0
  148. package/dist/fields/base-schema.d.ts +104 -0
  149. package/dist/fields/base-schema.js +266 -0
  150. package/dist/fields/base-sql.d.ts +62 -0
  151. package/dist/fields/base-sql.js +251 -0
  152. package/dist/fields/base-sync.d.ts +142 -0
  153. package/dist/fields/base-sync.js +499 -0
  154. package/dist/fields/base-tables.d.ts +89 -0
  155. package/dist/fields/base-tables.js +349 -0
  156. package/dist/fields/builtin-types.d.ts +13 -0
  157. package/dist/fields/builtin-types.js +773 -0
  158. package/dist/fields/button.d.ts +2 -0
  159. package/dist/fields/button.js +17 -0
  160. package/dist/fields/chart-view.d.ts +35 -0
  161. package/dist/fields/chart-view.js +154 -0
  162. package/dist/fields/column-order.d.ts +6 -0
  163. package/dist/fields/column-order.js +12 -0
  164. package/dist/fields/convert.d.ts +16 -0
  165. package/dist/fields/convert.js +176 -0
  166. package/dist/fields/copy-text.d.ts +13 -0
  167. package/dist/fields/copy-text.js +45 -0
  168. package/dist/fields/editor-request.svelte.d.ts +71 -0
  169. package/dist/fields/editor-request.svelte.js +52 -0
  170. package/dist/fields/field-ops.d.ts +72 -0
  171. package/dist/fields/field-ops.js +334 -0
  172. package/dist/fields/filter-model.d.ts +84 -0
  173. package/dist/fields/filter-model.js +446 -0
  174. package/dist/fields/format.d.ts +109 -0
  175. package/dist/fields/format.js +288 -0
  176. package/dist/fields/formula.d.ts +50 -0
  177. package/dist/fields/formula.js +530 -0
  178. package/dist/fields/grid-access.d.ts +60 -0
  179. package/dist/fields/grid-access.js +120 -0
  180. package/dist/fields/index.d.ts +34 -0
  181. package/dist/fields/index.js +312 -0
  182. package/dist/fields/linked-fields.d.ts +8 -0
  183. package/dist/fields/linked-fields.js +40 -0
  184. package/dist/fields/links.d.ts +10 -0
  185. package/dist/fields/links.js +46 -0
  186. package/dist/fields/name-list.d.ts +16 -0
  187. package/dist/fields/name-list.js +49 -0
  188. package/dist/fields/palette.d.ts +47 -0
  189. package/dist/fields/palette.js +69 -0
  190. package/dist/fields/record-delete.svelte.d.ts +12 -0
  191. package/dist/fields/record-delete.svelte.js +5 -0
  192. package/dist/fields/record-menu.d.ts +9 -0
  193. package/dist/fields/record-menu.js +78 -0
  194. package/dist/fields/registry.svelte.d.ts +176 -0
  195. package/dist/fields/registry.svelte.js +51 -0
  196. package/dist/fields/rich-text.d.ts +23 -0
  197. package/dist/fields/rich-text.js +48 -0
  198. package/dist/fields/row-color-choice.svelte.d.ts +31 -0
  199. package/dist/fields/row-color-choice.svelte.js +25 -0
  200. package/dist/fields/row-colors.d.ts +36 -0
  201. package/dist/fields/row-colors.js +90 -0
  202. package/dist/fields/row-height.d.ts +28 -0
  203. package/dist/fields/row-height.js +50 -0
  204. package/dist/fields/sources.svelte.d.ts +80 -0
  205. package/dist/fields/sources.svelte.js +131 -0
  206. package/dist/fields/summaries.d.ts +18 -0
  207. package/dist/fields/summaries.js +138 -0
  208. package/dist/fields/view-model.d.ts +129 -0
  209. package/dist/fields/view-model.js +492 -0
  210. package/dist/fields/viewbar/ChartPanel.svelte +61 -0
  211. package/dist/fields/viewbar/ChartPanel.svelte.d.ts +9 -0
  212. package/dist/fields/viewbar/ColorPanel.svelte +112 -0
  213. package/dist/fields/viewbar/ColorPanel.svelte.d.ts +9 -0
  214. package/dist/fields/viewbar/ConditionValue.svelte +153 -0
  215. package/dist/fields/viewbar/ConditionValue.svelte.d.ts +15 -0
  216. package/dist/fields/viewbar/FieldIcon.svelte +18 -0
  217. package/dist/fields/viewbar/FieldIcon.svelte.d.ts +9 -0
  218. package/dist/fields/viewbar/FilterPanel.svelte +192 -0
  219. package/dist/fields/viewbar/FilterPanel.svelte.d.ts +13 -0
  220. package/dist/fields/viewbar/GanttPanel.svelte +60 -0
  221. package/dist/fields/viewbar/GanttPanel.svelte.d.ts +10 -0
  222. package/dist/fields/viewbar/HideFieldsPanel.svelte +104 -0
  223. package/dist/fields/viewbar/HideFieldsPanel.svelte.d.ts +7 -0
  224. package/dist/fields/viewbar/SortPanel.svelte +85 -0
  225. package/dist/fields/viewbar/SortPanel.svelte.d.ts +8 -0
  226. package/dist/fields/viewbar/ViewsMenu.svelte +250 -0
  227. package/dist/fields/viewbar/ViewsMenu.svelte.d.ts +15 -0
  228. package/dist/fields/viewbar/panel-focus.d.ts +3 -0
  229. package/dist/fields/viewbar/panel-focus.js +22 -0
  230. package/dist/fields/viewbar/sort-state.d.ts +20 -0
  231. package/dist/fields/viewbar/sort-state.js +24 -0
  232. package/dist/gallery.d.ts +7 -0
  233. package/dist/gallery.js +36 -0
  234. package/dist/gantt/SvGridGantt.svelte +88 -16
  235. package/dist/gantt/gantt-config.d.ts +28 -0
  236. package/dist/index.d.ts +3 -0
  237. package/dist/index.js +6 -0
  238. package/dist/install.js +3 -0
  239. package/dist/license-core.d.ts +3 -3
  240. package/dist/license.js +1 -0
  241. package/dist/node/studio.js +105 -4
  242. package/dist/scheduler-config.d.ts +11 -0
  243. package/dist/sources/introspect-supabase.js +4 -1
  244. package/dist/sources/rest.js +6 -2
  245. package/dist/studio/ui-components.generated.js +93 -1
  246. package/dist/upgrade-prompt.d.ts +1 -1
  247. package/dist/version.d.ts +2 -2
  248. package/dist/version.js +2 -2
  249. package/dist/wc/GridFooter-f5K0aLe_.js +145 -0
  250. package/dist/wc/GridMenus-FtSN_8t9.js +1369 -0
  251. package/dist/wc/PinSplitter-D-qtDhSM.js +132 -0
  252. package/dist/wc/{SvGrid.helpers-zBkDTryR.js → SvGrid.helpers-B2GEKrxS.js} +84 -36
  253. package/dist/wc/{SvGridCellEditor-CzUKEbkI.js → SvGridCellEditor-B_cLJrsp.js} +20 -9
  254. package/dist/wc/conditional-formatting-BXis_oP1.js +189 -0
  255. package/dist/wc/grid-extension.svelte-Bufq4B4C.js +20 -0
  256. package/dist/wc/sv-sheet-element.js +7556 -7617
  257. package/dist/wc/svelte-virtualizer.svelte-ehwOupl-.js +360 -0
  258. package/dist/wc/{validate-43C03DLP.js → validate-BaMO8UPE.js} +1 -1
  259. package/package.json +14 -3
  260. package/dist/designer/assets/GridMenus-CvcASlKv.js +0 -8
  261. package/dist/designer/assets/SvGrid.helpers-DE5mmORW.js +0 -1
  262. package/dist/designer/assets/SvGridCellEditor-C7NWcnNC.js +0 -4
  263. package/dist/designer/assets/SvListBox-BlmmzYcU.js +0 -110
  264. package/dist/designer/assets/index-KmSEY7Lb.css +0 -1
  265. package/dist/designer/assets/src-DqHCqori.js +0 -58
  266. package/dist/designer/assets/validate-B71dE1Cs.js +0 -1
  267. package/dist/wc/GridMenus-fWbBUiRH.js +0 -1088
  268. package/dist/wc/svelte-virtualizer.svelte-Dntdh8Ms.js +0 -581
@@ -0,0 +1,188 @@
1
+ <script lang="ts">
2
+ /**
3
+ * One field's value outside the grid (the expanded record, the form view):
4
+ * drawn as its cell draws it, and on a click the editor its cell uses (the
5
+ * number box, the select panel, the date picker...) or a plain box. A
6
+ * checkbox toggles at once. The parent writes the value (`onCommit`) and
7
+ * decides which field is being edited, so Tab can move between them.
8
+ */
9
+ import { SvDateTimePicker, getCellEditor, resolveEditorProps } from '@svgrid/grid'
10
+ import FieldCell from './FieldCell.svelte'
11
+ import { typeDrawsCell } from './registry.svelte'
12
+
13
+ type Col = { id: string; columnDef: Record<string, any> }
14
+ let {
15
+ ctrl,
16
+ column,
17
+ value,
18
+ row,
19
+ rowId = '',
20
+ label,
21
+ editable,
22
+ editing,
23
+ placeholder = 'Empty',
24
+ onStart,
25
+ onStop,
26
+ onCommit,
27
+ onTab,
28
+ addOptions = true,
29
+ }: {
30
+ ctrl: any
31
+ column: Col
32
+ value: unknown
33
+ /** The row the value belongs to (none in a form). */
34
+ row?: { id: string; original: unknown } | null
35
+ rowId?: string
36
+ label: string
37
+ editable: boolean
38
+ editing: boolean
39
+ placeholder?: string
40
+ onStart: () => void
41
+ onStop: () => void
42
+ onCommit: (value: unknown) => void
43
+ /** Tab or Shift+Tab out of the editor, after its value was committed. */
44
+ onTab?: (dir: 1 | -1) => void
45
+ /** False in a form: a select offers only the field's options, never "Add option". */
46
+ addOptions?: boolean
47
+ } = $props()
48
+
49
+ let draft: unknown = undefined
50
+ const reg = $derived(getCellEditor(String(column.columnDef.editorType ?? 'text')))
51
+ const drawsCell = $derived(!!column.columnDef.fieldType && column.columnDef.cell == null && typeDrawsCell(column.columnDef))
52
+ // Stars and a checkbox say what an empty value is; other cells would draw nothing.
53
+ const drawnEmpty = $derived(column.columnDef.fieldType === 'rating' || column.columnDef.fieldType === 'checkbox')
54
+ // An empty value shows the placeholder, not an empty drawing.
55
+ const blank = $derived(value == null || value === '' || (Array.isArray(value) && value.length === 0))
56
+ const text = $derived.by(() => {
57
+ const f = column.columnDef.formatter as ((x: { value: unknown; row: unknown; column: unknown }) => unknown) | undefined
58
+ // `{ id, original }`, the shape a grid row has: in a form, the draft with id ''.
59
+ if (f) return String(f({ value, row: row ?? null, column }) ?? '')
60
+ if (Array.isArray(value)) return value.join(', ')
61
+ return value == null ? '' : String(value)
62
+ })
63
+
64
+ function start() {
65
+ if (!editable) return
66
+ if (column.columnDef.editorType === 'checkbox') return onCommit(!value)
67
+ draft = value
68
+ onStart()
69
+ }
70
+ const commit = (v: unknown) => {
71
+ onStop()
72
+ if (v !== undefined) onCommit(v)
73
+ }
74
+ function editorProps(r: NonNullable<ReturnType<typeof getCellEditor>>) {
75
+ const props = resolveEditorProps(r, {
76
+ value,
77
+ rowId,
78
+ columnId: column.id,
79
+ columnDef: column.columnDef,
80
+ row: row?.original,
81
+ grid: ctrl,
82
+ typed: false,
83
+ inCell: false,
84
+ onChange: (v: unknown) => (draft = v),
85
+ onCommit: (v?: unknown) => commit(v === undefined ? draft : v),
86
+ onCancel: onStop,
87
+ onRequestClose: onStop,
88
+ onCommitAndMove: (v: unknown, dir: 1 | -1) => {
89
+ commit(v === undefined ? draft : v)
90
+ onTab?.(dir)
91
+ },
92
+ onCommitAndMoveDown: (v?: unknown) => commit(v === undefined ? draft : v),
93
+ })
94
+ // Editors that do not read it ignore it.
95
+ return addOptions ? props : { ...props, addOptions: false }
96
+ }
97
+ function plainKey(e: KeyboardEvent, multiline: boolean) {
98
+ const el = e.currentTarget as HTMLInputElement | HTMLTextAreaElement
99
+ if (e.key === 'Escape') {
100
+ e.preventDefault()
101
+ e.stopPropagation()
102
+ onStop()
103
+ } else if (e.key === 'Enter' && (!multiline || e.ctrlKey || e.metaKey)) {
104
+ e.preventDefault()
105
+ commit(el.value)
106
+ } else if (e.key === 'Tab') {
107
+ e.preventDefault()
108
+ commit(el.value)
109
+ onTab?.(e.shiftKey ? -1 : 1)
110
+ }
111
+ }
112
+ function focusOnMount(el: HTMLInputElement | HTMLTextAreaElement) {
113
+ queueMicrotask(() => {
114
+ el.focus()
115
+ el.select()
116
+ })
117
+ }
118
+ const blurCommit = (e: Event) => {
119
+ if (editing) commit((e.currentTarget as HTMLInputElement).value)
120
+ }
121
+ </script>
122
+
123
+ {#if editing}
124
+ <div class="sv-frv-box is-editing">
125
+ {#if reg}
126
+ <reg.component {...editorProps(reg)} />
127
+ {:else if column.columnDef.editorType === 'date' || column.columnDef.editorType === 'datetime'}
128
+ <SvDateTimePicker
129
+ value={value as string | number | Date | null}
130
+ formatString={column.columnDef.editorFormatString ?? (column.columnDef.editorType === 'date' ? 'yyyy-MM-dd' : 'yyyy-MM-dd HH:mm')}
131
+ dropDownDisplayMode={column.columnDef.editorType === 'date' ? 'calendar' : 'both'}
132
+ autoOpen
133
+ block
134
+ onChange={(d) => (draft = d)}
135
+ onCommit={() => commit(draft)}
136
+ onCancel={onStop}
137
+ />
138
+ {:else if column.columnDef.editorType === 'textarea'}
139
+ <textarea class="sv-frv-input" rows="4" value={String(value ?? '')} use:focusOnMount onkeydown={(e) => plainKey(e, true)} onblur={blurCommit}></textarea>
140
+ {:else}
141
+ <input class="sv-frv-input" value={String(value ?? '')} use:focusOnMount onkeydown={(e) => plainKey(e, false)} onblur={blurCommit} />
142
+ {/if}
143
+ </div>
144
+ {:else}
145
+ <!-- A box acting as a button, not a <button>: a cell drawn in it can hold
146
+ buttons of its own (a linked record's chip), and buttons do not nest. -->
147
+ <div
148
+ class="sv-frv-box"
149
+ class:is-readonly={!editable}
150
+ role="button"
151
+ tabindex={editable ? 0 : -1}
152
+ aria-disabled={!editable}
153
+ aria-label={`${label}: ${text || 'empty'}${editable ? ', edit' : ''}`}
154
+ onclick={start}
155
+ onkeydown={(e) => {
156
+ if (e.target !== e.currentTarget || (e.key !== 'Enter' && e.key !== ' ')) return
157
+ e.preventDefault()
158
+ start()
159
+ }}
160
+ >
161
+ {#if drawsCell && (!blank || drawnEmpty)}
162
+ <FieldCell {ctrl} row={row ?? { id: rowId, original: {} }} column={column as never} {value} />
163
+ {:else if text}
164
+ <span class="sv-frv-text">{text}</span>
165
+ {:else}
166
+ <span class="sv-frv-empty">{editable ? placeholder : ''}</span>
167
+ {/if}
168
+ </div>
169
+ {/if}
170
+
171
+ <style>
172
+ .sv-frv-box {
173
+ position: relative; display: flex; align-items: center; min-height: 36px; width: 100%; box-sizing: border-box;
174
+ padding: 0 10px; text-align: start; font: inherit; font-size: 14px; color: var(--sg-fg, #0f172a);
175
+ border: 1px solid var(--sg-border, #e2e8f0); border-radius: var(--sg-radius, 6px); background: var(--sg-input-bg, var(--sg-bg, #fff));
176
+ cursor: pointer;
177
+ }
178
+ .sv-frv-box:hover:not(.is-readonly) { border-color: var(--sg-input-border, var(--sg-border, #cbd5e1)); }
179
+ .sv-frv-box:focus-visible { outline: 2px solid var(--sg-accent, #2563eb); outline-offset: 1px; }
180
+ .sv-frv-box.is-readonly { cursor: default; background: var(--sg-header-bg, #f8fafc); }
181
+ .sv-frv-box.is-editing { padding: 0; border-color: var(--sg-accent, #2563eb); cursor: auto; }
182
+ .sv-frv-text { white-space: pre-wrap; padding: 8px 0; }
183
+ .sv-frv-empty { color: var(--sg-muted, #94a3b8); font-size: 13px; }
184
+ .sv-frv-input {
185
+ width: 100%; box-sizing: border-box; min-height: 34px; padding: 8px 10px; border: 0; outline: none; resize: vertical;
186
+ font: inherit; font-size: 14px; background: none; color: var(--sg-fg, #0f172a);
187
+ }
188
+ </style>
@@ -0,0 +1,29 @@
1
+ type Col = {
2
+ id: string;
3
+ columnDef: Record<string, any>;
4
+ };
5
+ type $$ComponentProps = {
6
+ ctrl: any;
7
+ column: Col;
8
+ value: unknown;
9
+ /** The row the value belongs to (none in a form). */
10
+ row?: {
11
+ id: string;
12
+ original: unknown;
13
+ } | null;
14
+ rowId?: string;
15
+ label: string;
16
+ editable: boolean;
17
+ editing: boolean;
18
+ placeholder?: string;
19
+ onStart: () => void;
20
+ onStop: () => void;
21
+ onCommit: (value: unknown) => void;
22
+ /** Tab or Shift+Tab out of the editor, after its value was committed. */
23
+ onTab?: (dir: 1 | -1) => void;
24
+ /** False in a form: a select offers only the field's options, never "Add option". */
25
+ addOptions?: boolean;
26
+ };
27
+ declare const FieldInput: import("svelte").Component<$$ComponentProps, {}, "">;
28
+ type FieldInput = ReturnType<typeof FieldInput>;
29
+ export default FieldInput;
@@ -0,0 +1,146 @@
1
+ <script lang="ts">
2
+ /**
3
+ * The last child of a grid's header row (registerGridExtension's `headerEnd`):
4
+ * the "+" cell of the `columnAdder` prop, and the host of this grid's field
5
+ * editor (opened by the "+" and the column-menu field actions) and record
6
+ * view (opened by a row header's expand button).
7
+ */
8
+ import { untrack } from 'svelte'
9
+ import FieldEditor from './FieldEditor.svelte'
10
+ import { primaryIdOf } from './grid-access'
11
+ import RecordView from './RecordView.svelte'
12
+ import LinkedRecordView from './LinkedRecordView.svelte'
13
+ import DeleteFieldConfirm from './DeleteFieldConfirm.svelte'
14
+ import DeleteRecordConfirm from './DeleteRecordConfirm.svelte'
15
+ import { askDeleteRecord, getDeleteRecordRequest } from './record-delete.svelte'
16
+ import LinkPreview from './LinkPreview.svelte'
17
+ import {
18
+ closeFieldEditor,
19
+ closeLinkedRecord,
20
+ closeRecord,
21
+ getFieldEditorRequest,
22
+ getDeleteFieldRequest,
23
+ askDeleteField,
24
+ getLinkPreview,
25
+ getLinkedRecords,
26
+ getRecordRequest,
27
+ openFieldEditor,
28
+ } from './editor-request.svelte'
29
+
30
+ let { ctrl }: { ctrl: any } = $props()
31
+
32
+ const request = $derived(getFieldEditorRequest())
33
+ const mine = $derived(request && request.ctrl === ctrl ? request : null)
34
+ const deleting = $derived.by(() => {
35
+ const d = getDeleteFieldRequest()
36
+ return d && d.ctrl === ctrl ? d : null
37
+ })
38
+ const adder = $derived(!!ctrl.props.columnAdder)
39
+ const record = $derived(getRecordRequest())
40
+ const myRecord = $derived(record && record.ctrl === ctrl ? record : null)
41
+ // Linked records opened from this grid's chips, stacked, and the chip preview.
42
+ const linked = $derived(getLinkedRecords().filter((r) => r.ctrl === ctrl))
43
+ const preview = $derived.by(() => {
44
+ const p = getLinkPreview()
45
+ return p && p.ctrl === ctrl ? p : null
46
+ })
47
+
48
+ // Rows drag into a new order (`rowDragManaged`) only while nothing sorts or
49
+ // groups them: in a sorted table the order is the sort's.
50
+ $effect(() => {
51
+ // Only a grid whose app turned dragging on (our override is set only then).
52
+ const overridden = 'rowDragManaged' in (ctrl.optionOverrides ?? {})
53
+ if (!overridden && ctrl.props.rowDragManaged !== true) return
54
+ void ctrl.gridStateVersion
55
+ const s = ctrl.grid?.getState?.() ?? {}
56
+ const ordered = (s.sorting?.length ?? 0) > 0 || (s.grouping?.length ?? 0) > 0
57
+ const want = ordered ? false : undefined
58
+ untrack(() => {
59
+ if (ctrl.optionOverrides?.rowDragManaged !== want) ctrl.buildApi?.().setOption('rowDragManaged', want)
60
+ })
61
+ })
62
+
63
+ // `primaryField`: first, pinned and shown, whatever the column menu or a
64
+ // restored view did.
65
+ const primary = $derived(primaryIdOf(ctrl))
66
+ $effect(() => {
67
+ if (!primary) return
68
+ const pin = ctrl.columnPinning as { left: string[]; right: string[] }
69
+ const hidden = !!ctrl.hiddenColumns[primary]
70
+ untrack(() => {
71
+ if (hidden) {
72
+ const next = { ...ctrl.hiddenColumns }
73
+ delete next[primary]
74
+ ctrl.hiddenColumns = next
75
+ }
76
+ if (pin.left[0] !== primary || pin.right.includes(primary)) {
77
+ ctrl.columnPinning = { left: [primary, ...pin.left.filter((id) => id !== primary)], right: pin.right.filter((id) => id !== primary) }
78
+ }
79
+ })
80
+ })
81
+ </script>
82
+
83
+ {#if adder}
84
+ <th class="sv-grid-column sv-field-column-adder" role="columnheader" aria-label="Add a field">
85
+ <button
86
+ type="button"
87
+ class="sv-field-column-adder-button"
88
+ aria-label="Add a field"
89
+ title="Add a field"
90
+ onclick={() => openFieldEditor({ ctrl, mode: 'add', index: 'end' })}
91
+ >
92
+ <svg viewBox="0 0 24 24" width="16" height="16" aria-hidden="true"><path d="M12 5v14M5 12h14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" /></svg>
93
+ </button>
94
+ </th>
95
+ {/if}
96
+ {#if mine}
97
+ {#key mine}
98
+ <FieldEditor {ctrl} mode={mine.mode} columnId={mine.columnId} index={mine.index} onClose={closeFieldEditor} />
99
+ {/key}
100
+ {/if}
101
+ {#if deleting}
102
+ {#key deleting}
103
+ <DeleteFieldConfirm {ctrl} columnId={deleting.columnId} onClose={() => askDeleteField(null)} />
104
+ {/key}
105
+ {/if}
106
+ {#if getDeleteRecordRequest()?.ctrl === ctrl}
107
+ {@const r = getDeleteRecordRequest()!}
108
+ {#key r}
109
+ <DeleteRecordConfirm {ctrl} api={r.api} row={r.row} onClose={() => askDeleteRecord(null)} />
110
+ {/key}
111
+ {/if}
112
+ {#if myRecord}
113
+ {#key myRecord}
114
+ <RecordView {ctrl} rowId={myRecord.rowId} editPrimary={myRecord.editPrimary} onClose={closeRecord} />
115
+ {/key}
116
+ {/if}
117
+ {#each linked as r, i (`${i}:${r.table}:${r.rowId}`)}
118
+ <LinkedRecordView {ctrl} table={r.table} rowId={r.rowId} onClose={closeLinkedRecord} />
119
+ {/each}
120
+ {#if preview}
121
+ <LinkPreview request={preview} />
122
+ {/if}
123
+
124
+ <style>
125
+ .sv-field-column-adder {
126
+ flex: none;
127
+ width: 44px;
128
+ min-width: 44px;
129
+ max-width: 44px;
130
+ padding: 0;
131
+ }
132
+ .sv-field-column-adder-button {
133
+ display: inline-flex;
134
+ align-items: center;
135
+ justify-content: center;
136
+ width: 100%;
137
+ height: 100%;
138
+ min-height: 32px;
139
+ border: 0;
140
+ background: transparent;
141
+ color: var(--sg-muted, #64748b);
142
+ cursor: pointer;
143
+ }
144
+ .sv-field-column-adder-button:hover { color: var(--sg-fg, #0f172a); background: var(--sg-row-hover-bg, #f1f5f9); }
145
+ .sv-field-column-adder-button:focus-visible { outline: 2px solid var(--sg-accent, #2563eb); outline-offset: -2px; }
146
+ </style>
@@ -0,0 +1,6 @@
1
+ type $$ComponentProps = {
2
+ ctrl: any;
3
+ };
4
+ declare const FieldsHeaderEnd: import("svelte").Component<$$ComponentProps, {}, "">;
5
+ type FieldsHeaderEnd = ReturnType<typeof FieldsHeaderEnd>;
6
+ export default FieldsHeaderEnd;
@@ -0,0 +1,8 @@
1
+ <script lang="ts">
2
+ /** The "+ Add row" line in the grid's footer, under the summary row. */
3
+ import RowAdder from './RowAdder.svelte'
4
+
5
+ let { ctrl }: { ctrl: any } = $props()
6
+ </script>
7
+
8
+ <RowAdder {ctrl} foot />
@@ -0,0 +1,6 @@
1
+ type $$ComponentProps = {
2
+ ctrl: any;
3
+ };
4
+ declare const FootRowAdder: import("svelte").Component<$$ComponentProps, {}, "">;
5
+ type FootRowAdder = ReturnType<typeof FootRowAdder>;
6
+ export default FootRowAdder;
@@ -0,0 +1,127 @@
1
+ <script lang="ts">
2
+ /**
3
+ * A group's header in a table grouped by fields: the field's name over its
4
+ * value, drawn as the cell draws it (a select's pill, a person's avatar),
5
+ * the number of records, the summaries the fields picked for this group
6
+ * ("Budget Sum $4,300"), and "+" to add a record that is already in it.
7
+ */
8
+ import { tick } from 'svelte'
9
+ import FieldCell from './FieldCell.svelte'
10
+ import { newRowValues } from './field-ops'
11
+ import { typeDrawsCell } from './registry.svelte'
12
+ import { groupLeaves, leafFilter } from './grid-access'
13
+
14
+ type Row = {
15
+ id: string
16
+ depth: number
17
+ original: Record<string, unknown>
18
+ subRows?: Row[]
19
+ getCanExpand?: () => boolean
20
+ getIsExpanded?: () => boolean
21
+ toggleExpanded?: () => void
22
+ __treeRow?: boolean
23
+ }
24
+ type Col = { id: string; columnDef: Record<string, any> }
25
+ let { ctrl, row, column, value }: { ctrl: any; row: Row; column: Col | undefined; value: unknown; count: number } = $props()
26
+
27
+ // The group's records the view's filter keeps (the grid groups before it filters).
28
+ const records = $derived(groupLeaves(row, leafFilter(ctrl)))
29
+ // The first record's own value: the group key is text, the record has the value (an array, a number).
30
+ const raw = $derived(column?.columnDef.field ? (records[0]?.original?.[column.columnDef.field] ?? value) : value)
31
+ const draws = $derived(!!column?.columnDef.fieldType && column.columnDef.cell == null && typeDrawsCell(column.columnDef))
32
+ const empty = $derived(raw == null || raw === '' || (Array.isArray(raw) && raw.length === 0))
33
+ const label = $derived(column ? (typeof column.columnDef.header === 'string' ? column.columnDef.header : column.id) : '')
34
+
35
+ // The fields with a summary chosen, computed over this group's records.
36
+ const summaries = $derived.by(() => {
37
+ const out: Array<{ id: string; label: string; text: string }> = []
38
+ for (const c of (ctrl.allColumns ?? []) as Col[]) {
39
+ const fn = c.columnDef.summary
40
+ if (typeof fn !== 'function' || c.id === column?.id) continue
41
+ const text = String(fn([], records.map((r) => r.original)) ?? '')
42
+ if (text) out.push({ id: c.id, label: typeof c.columnDef.header === 'string' ? c.columnDef.header : c.id, text })
43
+ }
44
+ return out
45
+ })
46
+
47
+ /** A new record with this group's values (and its parent groups'), as "+ Add row" makes one. */
48
+ async function add() {
49
+ const api = ctrl.buildApi?.()
50
+ const first = records[0]
51
+ if (!api || !first) return
52
+ const grouped: string[] = ctrl.grid?.getState?.().grouping ?? []
53
+ const values: Record<string, unknown> = {}
54
+ for (const id of grouped.slice(0, row.depth + 1)) {
55
+ const def = ((ctrl.allColumns ?? []) as Col[]).find((c) => c.id === id)?.columnDef ?? ((ctrl.internalColumns ?? []) as Array<Record<string, any>>).find((d) => String(d.id ?? d.field) === id)
56
+ const field = def?.field
57
+ if (field && !def?.fieldFn) values[field] = copy(first.original[field])
58
+ }
59
+ const cfg = ctrl.props.rowAdder
60
+ const defaults = cfg && typeof cfg === 'object' && typeof cfg.defaults === 'function' ? cfg.defaults() : {}
61
+ const next: Record<string, unknown> = newRowValues(ctrl, { ...defaults, ...values })
62
+ api.addRow(next, 'bottom')
63
+ // Open the group, so the new record shows.
64
+ if (!row.getIsExpanded?.()) row.toggleExpanded?.()
65
+ await tick()
66
+ const index = (ctrl.allRows as Array<{ original: unknown }>).findIndex((r) => r.original === next)
67
+ if (index >= 0) {
68
+ api.scrollToRow(index)
69
+ await tick()
70
+ for (const c of ctrl.allColumns as Array<{ id: string }>) {
71
+ if (api.startEditing(index, c.id)) break
72
+ }
73
+ }
74
+ ctrl.props.onRowAdd?.({ row: next })
75
+ }
76
+ /** A list value (tags) is copied, not shared with the record it came from. */
77
+ const copy = (v: unknown): unknown => (Array.isArray(v) ? [...v] : v)
78
+ </script>
79
+
80
+ <span class="sv-fgh">
81
+ <span class="sv-fgh-key">
82
+ <span class="sv-fgh-name">{label}</span>
83
+ <span class="sv-fgh-value">
84
+ {#if empty}
85
+ <span class="sv-fgh-empty">Empty</span>
86
+ {:else if draws && column}
87
+ <FieldCell {ctrl} row={{ id: row.id, original: records[0]?.original ?? {} }} {column} value={raw} />
88
+ {:else}
89
+ {column?.columnDef.formatter ? String(column.columnDef.formatter({ value: raw, row: records[0] ?? null, column }) ?? '') : String(raw)}
90
+ {/if}
91
+ </span>
92
+ </span>
93
+ <span class="sv-fgh-count">{records.length} {records.length === 1 ? 'record' : 'records'}</span>
94
+ {#each summaries as s (s.id)}
95
+ <span class="sv-fgh-sum"><span class="sv-fgh-sum-label">{s.label}</span>{s.text}</span>
96
+ {/each}
97
+ {#if ctrl.props.rowAdder && ctrl.editingEnabled}
98
+ <button
99
+ type="button"
100
+ class="sv-fgh-add"
101
+ aria-label={`Add a record to ${label} ${empty ? 'Empty' : String(value ?? '')}`}
102
+ title="Add a record to this group"
103
+ onclick={(e) => {
104
+ e.stopPropagation()
105
+ void add()
106
+ }}
107
+ >
108
+ <svg viewBox="0 0 24 24" width="14" height="14" aria-hidden="true"><path d="M12 5v14M5 12h14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" /></svg>
109
+ </button>
110
+ {/if}
111
+ </span>
112
+
113
+ <style>
114
+ .sv-fgh { display: inline-flex; align-items: center; gap: 14px; min-width: 0; }
115
+ .sv-fgh-key { display: inline-flex; flex-direction: column; justify-content: center; gap: 4px; line-height: 1.2; min-width: 0; }
116
+ .sv-fgh-name { font-size: 11px; color: var(--sg-muted, #64748b); }
117
+ .sv-fgh-value { display: inline-flex; align-items: center; font-weight: 600; min-height: 20px; }
118
+ .sv-fgh-empty { color: var(--sg-muted, #64748b); font-weight: 400; font-style: italic; }
119
+ .sv-fgh-count { font-size: 12px; color: var(--sg-muted, #64748b); }
120
+ .sv-fgh-sum { font-size: 12px; font-variant-numeric: tabular-nums; }
121
+ .sv-fgh-sum-label { color: var(--sg-muted, #64748b); margin-inline-end: 4px; }
122
+ .sv-fgh-add {
123
+ display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px; padding: 0;
124
+ border: 0; border-radius: 6px; background: none; color: var(--sg-muted, #64748b); cursor: pointer;
125
+ }
126
+ .sv-fgh-add:hover { background: var(--sg-row-hover-bg, #f1f5f9); color: var(--sg-fg, #0f172a); }
127
+ </style>
@@ -0,0 +1,24 @@
1
+ type Row = {
2
+ id: string;
3
+ depth: number;
4
+ original: Record<string, unknown>;
5
+ subRows?: Row[];
6
+ getCanExpand?: () => boolean;
7
+ getIsExpanded?: () => boolean;
8
+ toggleExpanded?: () => void;
9
+ __treeRow?: boolean;
10
+ };
11
+ type Col = {
12
+ id: string;
13
+ columnDef: Record<string, any>;
14
+ };
15
+ type $$ComponentProps = {
16
+ ctrl: any;
17
+ row: Row;
18
+ column: Col | undefined;
19
+ value: unknown;
20
+ count: number;
21
+ };
22
+ declare const GroupHeader: import("svelte").Component<$$ComponentProps, {}, "">;
23
+ type GroupHeader = ReturnType<typeof GroupHeader>;
24
+ export default GroupHeader;
@@ -0,0 +1,46 @@
1
+ <script lang="ts">
2
+ /**
3
+ * URL, email and phone cells: the value as a link when it is a valid one of
4
+ * its kind (see links.ts), plain text otherwise. A plain click on the link
5
+ * follows it; clicking elsewhere in the cell selects it as usual.
6
+ */
7
+ import type { FieldCellProps } from './registry.svelte'
8
+ import { linkHref, linkText, type LinkKind } from './links'
9
+
10
+ let { value, column }: FieldCellProps = $props()
11
+ const kind = $derived((column.columnDef.fieldType as LinkKind) ?? 'url')
12
+ const href = $derived(linkHref(kind, value))
13
+ const text = $derived(linkText(kind, value))
14
+ </script>
15
+
16
+ {#if href}
17
+ <a
18
+ class="sv-field-link"
19
+ {href}
20
+ target={kind === 'url' ? '_blank' : undefined}
21
+ rel={kind === 'url' ? 'noopener noreferrer' : undefined}
22
+ onpointerdown={(e) => e.stopPropagation()}
23
+ >{text}</a>
24
+ {:else}
25
+ <span class="sv-field-link-text">{text}</span>
26
+ {/if}
27
+
28
+ <style>
29
+ /* Text colour with an underline, not the accent: on themes where the accent
30
+ marks selection (Ember), a column of accent links reads as selected. */
31
+ .sv-field-link {
32
+ color: inherit;
33
+ text-decoration: underline;
34
+ text-decoration-color: var(--sg-muted, #94a3b8);
35
+ text-underline-offset: 2px;
36
+ overflow: hidden;
37
+ text-overflow: ellipsis;
38
+ white-space: nowrap;
39
+ }
40
+ .sv-field-link:hover { text-decoration-color: currentColor; }
41
+ .sv-field-link-text {
42
+ overflow: hidden;
43
+ text-overflow: ellipsis;
44
+ white-space: nowrap;
45
+ }
46
+ </style>
@@ -0,0 +1,9 @@
1
+ /**
2
+ * URL, email and phone cells: the value as a link when it is a valid one of
3
+ * its kind (see links.ts), plain text otherwise. A plain click on the link
4
+ * follows it; clicking elsewhere in the cell selects it as usual.
5
+ */
6
+ import type { FieldCellProps } from './registry.svelte.js';
7
+ declare const LinkCell: import("svelte").Component<FieldCellProps, {}, "">;
8
+ type LinkCell = ReturnType<typeof LinkCell>;
9
+ export default LinkCell;