@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.
Files changed (270) 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 +11375 -10805
  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-DtBIaQno.js → index-BPU2KNc5.js} +396 -395
  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 +141 -20
  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/emit-project.js +25 -6
  246. package/dist/studio/sveltekit3.js +13 -7
  247. package/dist/studio/ui-components.generated.js +94 -2
  248. package/dist/upgrade-prompt.d.ts +1 -1
  249. package/dist/version.d.ts +2 -2
  250. package/dist/version.js +2 -2
  251. package/dist/wc/GridFooter-f5K0aLe_.js +145 -0
  252. package/dist/wc/GridMenus-FtSN_8t9.js +1369 -0
  253. package/dist/wc/PinSplitter-D-qtDhSM.js +132 -0
  254. package/dist/wc/{SvGrid.helpers-zBkDTryR.js → SvGrid.helpers-B2GEKrxS.js} +84 -36
  255. package/dist/wc/{SvGridCellEditor-CzUKEbkI.js → SvGridCellEditor-B_cLJrsp.js} +20 -9
  256. package/dist/wc/conditional-formatting-BXis_oP1.js +189 -0
  257. package/dist/wc/grid-extension.svelte-Bufq4B4C.js +20 -0
  258. package/dist/wc/sv-sheet-element.js +7561 -7618
  259. package/dist/wc/svelte-virtualizer.svelte-ehwOupl-.js +360 -0
  260. package/dist/wc/{validate-43C03DLP.js → validate-BaMO8UPE.js} +1 -1
  261. package/package.json +14 -3
  262. package/dist/designer/assets/GridMenus-CvcASlKv.js +0 -8
  263. package/dist/designer/assets/SvGrid.helpers-DE5mmORW.js +0 -1
  264. package/dist/designer/assets/SvGridCellEditor-C7NWcnNC.js +0 -4
  265. package/dist/designer/assets/SvListBox-BlmmzYcU.js +0 -110
  266. package/dist/designer/assets/index-KmSEY7Lb.css +0 -1
  267. package/dist/designer/assets/src-DqHCqori.js +0 -58
  268. package/dist/designer/assets/validate-B71dE1Cs.js +0 -1
  269. package/dist/wc/GridMenus-fWbBUiRH.js +0 -1088
  270. package/dist/wc/svelte-virtualizer.svelte-Dntdh8Ms.js +0 -581
@@ -0,0 +1,204 @@
1
+ <script lang="ts">
2
+ /**
3
+ * One property in the field editor, drawn for its kind: a number, text, a
4
+ * checkbox, a dropdown, a row of buttons, color swatches, icons, the select
5
+ * options list, a default value that follows the field type, a formula, or a
6
+ * pick of other fields.
7
+ */
8
+ import OptionsEditor from './OptionsEditor.svelte'
9
+ import { FORMULA_FUNCTIONS, columnResolver, formulaError } from './formula'
10
+ import { getFieldUsers } from './sources.svelte'
11
+ import type { FieldEditorContext, FieldPropertyDef } from './registry.svelte'
12
+
13
+ let {
14
+ def,
15
+ value,
16
+ fieldType,
17
+ ctx,
18
+ onChange,
19
+ }: { def: FieldPropertyDef; value: any; fieldType: string; ctx: FieldEditorContext; onChange: (v: unknown) => void } = $props()
20
+
21
+ const id = $derived(`sv-fed-${def.key}`)
22
+ const choices = $derived(
23
+ def.kind === 'choice' ? (typeof def.choices === 'function' ? def.choices(ctx) : def.choices) : [],
24
+ )
25
+ // The field names a formula can use: every other field, by its header.
26
+ const names = $derived(ctx.columns.map((c) => String(c.header ?? c.field ?? '')).filter(Boolean))
27
+ const formulaMessage = $derived(def.kind === 'formula' && String(value ?? '').trim() ? formulaError(String(value), columnResolver(ctx.columns, ctx.self)) : null)
28
+ const selectOptions = $derived(((ctx.props.options as Array<{ value: string }> | undefined) ?? []).map((o) => String(o.value)).filter(Boolean))
29
+ let formulaEl = $state<HTMLTextAreaElement | null>(null)
30
+ let showFunctions = $state(false)
31
+
32
+ // Event readers live here: AGENTS.md keeps `as` casts in <script>.
33
+ const inputValue = (e: Event) => (e.currentTarget as HTMLInputElement).value
34
+ const checkedOf = (e: Event) => (e.currentTarget as HTMLInputElement).checked
35
+ const numberOf = (e: Event) => {
36
+ const raw = inputValue(e)
37
+ return raw === '' ? undefined : Number(raw)
38
+ }
39
+
40
+ function insertField(name: string) {
41
+ const token = `{${name}}`
42
+ const el = formulaEl
43
+ const text = String(value ?? '')
44
+ if (!el) return onChange(text + token)
45
+ const at = el.selectionStart ?? text.length
46
+ onChange(text.slice(0, at) + token + text.slice(el.selectionEnd ?? at))
47
+ queueMicrotask(() => {
48
+ el.focus()
49
+ el.setSelectionRange(at + token.length, at + token.length)
50
+ })
51
+ }
52
+ const toggleIn = (list: unknown, v: string) => {
53
+ const arr = Array.isArray(list) ? (list as string[]) : []
54
+ return arr.includes(v) ? arr.filter((x) => x !== v) : [...arr, v]
55
+ }
56
+ </script>
57
+
58
+ {#if def.kind === 'checkbox'}
59
+ <label class="sv-pi-check">
60
+ <input type="checkbox" checked={!!value} aria-describedby={def.hint ? `${id}-hint` : undefined} onchange={(e) => onChange(checkedOf(e))} />
61
+ <span>{def.label}</span>
62
+ </label>
63
+ {#if def.hint}<p id={`${id}-hint`} class="sv-pi-hint sv-pi-hint-check">{def.hint}</p>{/if}
64
+ {:else if def.kind === 'options'}
65
+ <span class="sv-pi-label">{def.label}</span>
66
+ <OptionsEditor options={value ?? []} {onChange} />
67
+ {#if def.hint}<p class="sv-pi-hint">{def.hint}</p>{/if}
68
+ {:else}
69
+ <div class="sv-pi" class:is-wide={def.kind === 'formula' || def.kind === 'columns' || def.kind === 'color' || def.kind === 'icon' || (def.kind === 'default' && fieldType === 'multiSelect')}>
70
+ <label class="sv-pi-label" for={id}>{def.label}</label>
71
+ {#if def.kind === 'number'}
72
+ <input {id} class="sv-pi-input sv-pi-number" type="number" min={def.min} max={def.max} value={value ?? ''} oninput={(e) => onChange(numberOf(e))} />
73
+ {:else if def.kind === 'text'}
74
+ <input {id} class="sv-pi-input" placeholder={def.placeholder} value={String(value ?? '')} oninput={(e) => onChange(inputValue(e))} />
75
+ {:else if def.kind === 'choice'}
76
+ <select {id} class="sv-pi-input sv-pi-select" value={String(value ?? '')} onchange={(e) => onChange(inputValue(e))}>
77
+ {#if !choices.some((c) => c.value === String(value ?? ''))}<option value="" disabled>Choose...</option>{/if}
78
+ {#each choices as c (c.value)}<option value={c.value}>{c.label}</option>{/each}
79
+ </select>
80
+ {:else if def.kind === 'segmented'}
81
+ <div {id} class="sv-pi-seg" role="radiogroup" aria-label={def.label}>
82
+ {#each def.choices as c (c.value)}
83
+ <button type="button" role="radio" aria-checked={String(value) === c.value} class:is-on={String(value) === c.value} onclick={() => onChange(c.value)}>{c.label}</button>
84
+ {/each}
85
+ </div>
86
+ {:else if def.kind === 'color'}
87
+ <div {id} class="sv-pi-swatches" role="radiogroup" aria-label={def.label}>
88
+ {#each def.palette as c (c.value)}
89
+ <button type="button" role="radio" aria-checked={value === c.value} aria-label={c.label} title={c.label} class:is-on={value === c.value} style:--sw={c.value} onclick={() => onChange(c.value)}></button>
90
+ {/each}
91
+ </div>
92
+ {:else if def.kind === 'icon'}
93
+ <div {id} class="sv-pi-icons" role="radiogroup" aria-label={def.label}>
94
+ {#each def.icons as ic (ic.value)}
95
+ <button type="button" role="radio" aria-checked={value === ic.value} aria-label={ic.label} title={ic.label} class:is-on={value === ic.value} onclick={() => onChange(ic.value)}>
96
+ <svg viewBox="0 0 24 24" width="16" height="16" aria-hidden="true"><path d={ic.path} fill="none" stroke={value === ic.value ? (ctx.props.color ?? 'currentColor') : 'currentColor'} stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" /></svg>
97
+ </button>
98
+ {/each}
99
+ </div>
100
+ {:else if def.kind === 'default'}
101
+ {#if fieldType === 'checkbox'}
102
+ <label class="sv-pi-check sv-pi-inline"><input {id} type="checkbox" checked={!!value} onchange={(e) => onChange(checkedOf(e) || undefined)} /> <span>Checked</span></label>
103
+ {:else if fieldType === 'singleSelect'}
104
+ <select {id} class="sv-pi-input sv-pi-select" value={String(value ?? '')} onchange={(e) => onChange(inputValue(e) || undefined)}>
105
+ <option value="">None</option>
106
+ {#each selectOptions as o (o)}<option value={o}>{o}</option>{/each}
107
+ </select>
108
+ {:else if fieldType === 'multiSelect'}
109
+ <div {id} class="sv-pi-chips">
110
+ {#each selectOptions as o (o)}
111
+ <button type="button" class:is-on={Array.isArray(value) && value.includes(o)} aria-pressed={Array.isArray(value) && value.includes(o)} onclick={() => { const next = toggleIn(value, o); onChange(next.length ? next : undefined) }}>{o}</button>
112
+ {:else}
113
+ <span class="sv-pi-muted">Add options first.</span>
114
+ {/each}
115
+ </div>
116
+ {:else if fieldType === 'user'}
117
+ <select {id} class="sv-pi-input sv-pi-select" value={String(value ?? '')} onchange={(e) => onChange(inputValue(e) || undefined)}>
118
+ <option value="">Nobody</option>
119
+ {#each getFieldUsers() as u (u.id)}<option value={u.id}>{u.name}</option>{/each}
120
+ </select>
121
+ {:else if fieldType === 'number' || fieldType === 'currency' || fieldType === 'percent'}
122
+ <input {id} class="sv-pi-input sv-pi-number" type="number" value={value ?? ''} oninput={(e) => onChange(numberOf(e))} />
123
+ {:else}
124
+ <input {id} class="sv-pi-input" placeholder="Empty" value={String(value ?? '')} oninput={(e) => onChange(inputValue(e) || undefined)} />
125
+ {/if}
126
+ {:else if def.kind === 'formula'}
127
+ <textarea
128
+ {id}
129
+ bind:this={formulaEl}
130
+ class="sv-pi-input sv-pi-formula"
131
+ rows="3"
132
+ spellcheck="false"
133
+ placeholder={'IF({Budget} > 2000, "Large", "Small")'}
134
+ aria-invalid={!!formulaMessage}
135
+ value={String(value ?? '')}
136
+ oninput={(e) => onChange(inputValue(e))}
137
+ ></textarea>
138
+ {#if formulaMessage}<p class="sv-pi-error">{formulaMessage}</p>{/if}
139
+ <div class="sv-pi-fields" aria-label="Insert a field">
140
+ {#each names as n (n)}<button type="button" onclick={() => insertField(n)}>{n}</button>{/each}
141
+ </div>
142
+ <button type="button" class="sv-pi-more" aria-expanded={showFunctions} onclick={() => (showFunctions = !showFunctions)}>
143
+ {showFunctions ? 'Hide functions' : 'Functions'}
144
+ </button>
145
+ {#if showFunctions}<p class="sv-pi-functions">{FORMULA_FUNCTIONS.join(', ')}</p>{/if}
146
+ {:else if def.kind === 'columns'}
147
+ <div {id} class="sv-pi-chips">
148
+ {#each ctx.columns as c (String(c.id ?? c.field))}
149
+ {@const cid = String(c.id ?? c.field)}
150
+ <button type="button" class:is-on={Array.isArray(value) && value.includes(cid)} aria-pressed={Array.isArray(value) && value.includes(cid)} onclick={() => onChange(toggleIn(value, cid))}>{String(c.header ?? cid)}</button>
151
+ {/each}
152
+ </div>
153
+ {/if}
154
+ {#if def.hint}<p class="sv-pi-hint">{def.hint}</p>{/if}
155
+ </div>
156
+ {/if}
157
+
158
+ <style>
159
+ .sv-pi { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 6px 12px; }
160
+ .sv-pi.is-wide { grid-template-columns: 1fr; }
161
+ .sv-pi-hint, .sv-pi-error, .sv-pi-functions { grid-column: 1 / -1; margin: 0; font-size: 12px; color: var(--sg-muted, #64748b); }
162
+ .sv-pi-error { color: var(--sg-danger, #dc2626); }
163
+ /* Under the checkbox's label, past the box and the gap. */
164
+ .sv-pi-hint-check { margin-top: -4px; padding-inline-start: 23px; }
165
+ .sv-pi-functions { font-family: ui-monospace, monospace; line-height: 1.5; }
166
+ .sv-pi-label { font-size: 13px; color: var(--sg-fg, #0f172a); }
167
+ .sv-pi-muted { font-size: 12px; color: var(--sg-muted, #64748b); }
168
+ .sv-pi-input {
169
+ box-sizing: border-box; height: 32px; padding: 0 10px; font: inherit; font-size: 13px;
170
+ border: 1px solid var(--sg-input-border, var(--sg-border, #e2e8f0)); border-radius: var(--sg-radius, 6px);
171
+ background: var(--sg-input-bg, var(--sg-bg, #fff)); color: var(--sg-fg, #0f172a);
172
+ }
173
+ .sv-pi-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); }
174
+ .sv-pi-input[aria-invalid='true'] { border-color: var(--sg-danger, #dc2626); }
175
+ .sv-pi-number { width: 110px; }
176
+ .sv-pi-select { min-width: 170px; max-width: 240px; }
177
+ .sv-pi-formula { height: auto; padding: 8px 10px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 13px; line-height: 1.45; resize: vertical; }
178
+ .sv-pi-check { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--sg-fg, #0f172a); cursor: pointer; }
179
+ .sv-pi-check input { width: 15px; height: 15px; accent-color: var(--sg-accent, #2563eb); }
180
+ .sv-pi-seg { display: inline-flex; padding: 2px; border-radius: var(--sg-radius, 6px); background: var(--sg-bg, #fff); border: 1px solid var(--sg-border, #e2e8f0); }
181
+ .sv-pi-seg button { height: 26px; padding: 0 10px; border: 0; border-radius: 4px; background: none; color: var(--sg-muted, #64748b); font: inherit; font-size: 12px; cursor: pointer; }
182
+ .sv-pi-seg button.is-on { background: var(--sg-selection-bg, #eef4ff); color: var(--sg-fg, #0f172a); font-weight: 500; }
183
+ .sv-pi-swatches, .sv-pi-icons, .sv-pi-chips, .sv-pi-fields { display: flex; flex-wrap: wrap; gap: 6px; }
184
+ .sv-pi-swatches button {
185
+ width: 22px; height: 22px; padding: 0; border-radius: 999px; cursor: pointer; background: var(--sw);
186
+ border: 2px solid var(--sg-bg, #fff); box-shadow: 0 0 0 1px var(--sg-border, #e2e8f0);
187
+ }
188
+ .sv-pi-swatches button.is-on { box-shadow: 0 0 0 2px var(--sg-fg, #0f172a); }
189
+ .sv-pi-icons button {
190
+ display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 30px; padding: 0;
191
+ border: 1px solid var(--sg-border, #e2e8f0); border-radius: var(--sg-radius, 6px); background: var(--sg-bg, #fff); color: var(--sg-muted, #64748b); cursor: pointer;
192
+ }
193
+ .sv-pi-icons button.is-on { border-color: var(--sg-accent, #2563eb); background: var(--sg-selection-bg, #eef4ff); color: var(--sg-fg, #0f172a); }
194
+ .sv-pi-chips button, .sv-pi-fields button {
195
+ height: 24px; padding: 0 9px; border-radius: 999px; font: inherit; font-size: 12px; cursor: pointer;
196
+ border: 1px solid var(--sg-border, #e2e8f0); background: var(--sg-bg, #fff); color: var(--sg-fg, #0f172a);
197
+ }
198
+ .sv-pi-chips button.is-on { border-color: var(--sg-accent, #2563eb); background: var(--sg-selection-bg, #eef4ff); }
199
+ .sv-pi-fields button { font-family: ui-monospace, monospace; font-size: 11px; }
200
+ .sv-pi-fields button::before { content: '{'; color: var(--sg-muted, #64748b); }
201
+ .sv-pi-fields button::after { content: '}'; color: var(--sg-muted, #64748b); }
202
+ .sv-pi-more { justify-self: start; padding: 0; border: 0; background: none; color: var(--sg-muted, #64748b); font: inherit; font-size: 12px; text-decoration: underline; cursor: pointer; }
203
+ .sv-pi-swatches button:focus-visible, .sv-pi-icons button:focus-visible, .sv-pi-seg button:focus-visible, .sv-pi-chips button:focus-visible { outline: 2px solid var(--sg-accent, #2563eb); outline-offset: 2px; }
204
+ </style>
@@ -0,0 +1,11 @@
1
+ import type { FieldEditorContext, FieldPropertyDef } from './registry.svelte.js';
2
+ type $$ComponentProps = {
3
+ def: FieldPropertyDef;
4
+ value: any;
5
+ fieldType: string;
6
+ ctx: FieldEditorContext;
7
+ onChange: (v: unknown) => void;
8
+ };
9
+ declare const PropertyInput: import("svelte").Component<$$ComponentProps, {}, "">;
10
+ type PropertyInput = ReturnType<typeof PropertyInput>;
11
+ export default PropertyInput;
@@ -0,0 +1,75 @@
1
+ <script lang="ts">
2
+ /**
3
+ * Rating cells: the field's icon `max` times in its color, the first `value`
4
+ * filled. In an editable grid a click on an icon sets the rating (a click on
5
+ * the current one clears it), through the grid's own edit commit, so undo,
6
+ * `onCellValueChange` and validation behave as for any edit. Screen readers
7
+ * hear "3 of 5".
8
+ */
9
+ import type { FieldCellProps } from './registry.svelte'
10
+ import { ICONS, STROKE_ICONS, type IconName } from './palette'
11
+
12
+ let { ctrl, row, column, value, props }: FieldCellProps<{ max?: number; icon?: IconName; color?: string }> = $props()
13
+ const max = $derived(Math.max(1, Math.min(10, Math.round(Number(props.max) || 5))))
14
+ const n = $derived(Math.max(0, Math.min(max, Math.round(Number(value) || 0))))
15
+ const icon = $derived<IconName>(props.icon && props.icon in ICONS ? props.icon : 'star')
16
+ const color = $derived(props.color || '#fcb400')
17
+ const items = $derived(Array.from({ length: max }, (_, i) => i))
18
+ const g = $derived(ctrl as any)
19
+ const interactive = $derived(!!g?.editingEnabled && column.columnDef.editable !== false)
20
+ let hover = $state<number | null>(null)
21
+ // Over an icon or the gap after it: the icon under the pointer, so the
22
+ // preview does not flicker between icons.
23
+ function track(e: PointerEvent) {
24
+ if (!interactive) return
25
+ const el = e.currentTarget as HTMLElement
26
+ const box = el.getBoundingClientRect()
27
+ const x = getComputedStyle(el).direction === 'rtl' ? box.right - e.clientX : e.clientX - box.left
28
+ hover = Math.max(0, Math.min(max - 1, Math.floor((x / box.width) * max)))
29
+ }
30
+
31
+ function set(i: number) {
32
+ if (!interactive) return
33
+ const next = i + 1 === n ? 0 : i + 1
34
+ const rowIndex = (g.allRows as Array<{ id: string }>).findIndex((r) => r.id === row.id)
35
+ if (rowIndex < 0 || !g.startEditing?.(rowIndex, column.id)) return
36
+ g.updateEditingCellValue?.(next)
37
+ g.saveEditingCell?.()
38
+ }
39
+ </script>
40
+
41
+ <span
42
+ class="sv-frt"
43
+ class:is-interactive={interactive}
44
+ role="img"
45
+ aria-label={`${n} of ${max}`}
46
+ style:--c={color}
47
+ onpointermove={track}
48
+ onpointerleave={() => (hover = null)}
49
+ >
50
+ {#each items as i (i)}
51
+ {@const filled = hover !== null ? i <= hover : i < n}
52
+ {@const preview = hover !== null && filled && i >= n}
53
+ <!-- svelte-ignore a11y_click_events_have_key_events -->
54
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
55
+ <svg
56
+ class="sv-frt-icon"
57
+ class:is-on={filled}
58
+ class:is-preview={preview}
59
+ viewBox="0 0 24 24"
60
+ width="15"
61
+ height="15"
62
+ aria-hidden="true"
63
+ onclick={() => set(i)}
64
+ >
65
+ <path d={ICONS[icon]} fill={filled && !STROKE_ICONS.has(icon) ? 'var(--c)' : 'none'} stroke={filled ? 'var(--c)' : 'currentColor'} stroke-width="1.7" stroke-linejoin="round" stroke-linecap="round" />
66
+ </svg>
67
+ {/each}
68
+ </span>
69
+
70
+ <style>
71
+ .sv-frt { display: inline-flex; gap: 1px; align-items: center; color: color-mix(in srgb, var(--sg-muted, #94a3b8) 55%, transparent); }
72
+ .sv-frt.is-interactive .sv-frt-icon { cursor: pointer; }
73
+ .sv-frt-icon { flex: none; }
74
+ .sv-frt-icon.is-preview { opacity: 0.55; }
75
+ </style>
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Rating cells: the field's icon `max` times in its color, the first `value`
3
+ * filled. In an editable grid a click on an icon sets the rating (a click on
4
+ * the current one clears it), through the grid's own edit commit, so undo,
5
+ * `onCellValueChange` and validation behave as for any edit. Screen readers
6
+ * hear "3 of 5".
7
+ */
8
+ import type { FieldCellProps } from './registry.svelte.js';
9
+ import { type IconName } from './palette.js';
10
+ declare const RatingCell: import("svelte").Component<FieldCellProps<{
11
+ max?: number;
12
+ icon?: IconName;
13
+ color?: string;
14
+ }>, {}, "">;
15
+ type RatingCell = ReturnType<typeof RatingCell>;
16
+ export default RatingCell;
@@ -0,0 +1,82 @@
1
+ <script lang="ts">
2
+ /**
3
+ * The rating field's editor (registered as 'fieldRating'): the field's icon
4
+ * up to its maximum. The icons under the pointer show what a click sets.
5
+ * Left / Right or a digit change it, a click sets it,
6
+ * Enter keeps it, Escape leaves the cell as it was, 0 or Backspace clears.
7
+ */
8
+ import { fieldPropsOf } from './registry.svelte'
9
+ import { ICONS, STROKE_ICONS, type IconName } from './palette'
10
+
11
+ let {
12
+ value,
13
+ columnDef,
14
+ onCommit,
15
+ onCancel,
16
+ }: { value: unknown; columnDef?: Record<string, unknown>; onCommit: (v?: unknown) => void; onCancel: () => void } = $props()
17
+
18
+ const props = $derived(fieldPropsOf((columnDef ?? {}) as { fieldType?: unknown; fieldProps?: Record<string, unknown> }) as { max?: number; icon?: IconName; color?: string })
19
+ const max = $derived(Math.max(1, Math.min(10, Math.round(Number(props.max) || 5))))
20
+ const icon = $derived<IconName>(props.icon && props.icon in ICONS ? props.icon : 'star')
21
+ // svelte-ignore state_referenced_locally
22
+ let n = $state(Math.max(0, Math.round(Number(value) || 0)))
23
+ const items = $derived(Array.from({ length: max }, (_, i) => i))
24
+ // The icon under the pointer, shown filled as a preview of the click.
25
+ let hover = $state<number | null>(null)
26
+ const shown = $derived(hover === null ? n : hover + 1)
27
+ function track(e: PointerEvent) {
28
+ const el = e.currentTarget as HTMLElement
29
+ const icons = el.querySelectorAll('svg')
30
+ const first = icons[0]?.getBoundingClientRect()
31
+ const last = icons[icons.length - 1]?.getBoundingClientRect()
32
+ if (!first || !last) return
33
+ const rtl = getComputedStyle(el).direction === 'rtl'
34
+ const x = rtl ? first.right - e.clientX : e.clientX - first.left
35
+ const span = rtl ? first.right - last.left : last.right - first.left
36
+ hover = x < 0 || x > span ? null : Math.max(0, Math.min(max - 1, Math.floor((x / span) * max)))
37
+ }
38
+
39
+ function focusOnMount(el: HTMLElement) {
40
+ queueMicrotask(() => el.focus())
41
+ }
42
+ function onKey(e: KeyboardEvent) {
43
+ if (e.key === 'ArrowRight' || e.key === 'ArrowUp') n = Math.min(max, n + 1)
44
+ else if (e.key === 'ArrowLeft' || e.key === 'ArrowDown') n = Math.max(0, n - 1)
45
+ else if (/^\d$/.test(e.key)) n = Math.min(max, Number(e.key))
46
+ else if (e.key === 'Backspace' || e.key === 'Delete') n = 0
47
+ else if (e.key === 'Enter' || e.key === 'Tab') onCommit(n)
48
+ else if (e.key === 'Escape') onCancel()
49
+ else return
50
+ e.preventDefault()
51
+ e.stopPropagation()
52
+ }
53
+ </script>
54
+
55
+ <span
56
+ class="sv-fre"
57
+ role="slider"
58
+ tabindex="0"
59
+ aria-valuemin={0}
60
+ aria-valuemax={max}
61
+ aria-valuenow={n}
62
+ aria-label={`Rating, ${n} of ${max}`}
63
+ style:--c={props.color || '#fcb400'}
64
+ use:focusOnMount
65
+ onkeydown={onKey}
66
+ onpointermove={track}
67
+ onpointerleave={() => (hover = null)}
68
+ >
69
+ {#each items as i (i)}
70
+ <!-- svelte-ignore a11y_click_events_have_key_events -->
71
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
72
+ <svg viewBox="0 0 24 24" width="17" height="17" aria-hidden="true" onmousedown={(e) => e.preventDefault()} onclick={() => onCommit(i + 1 === n ? 0 : i + 1)} class:is-preview={hover !== null && i < shown && i >= n}>
73
+ <path d={ICONS[icon]} fill={i < shown && !STROKE_ICONS.has(icon) ? 'var(--c)' : 'none'} stroke={i < shown ? 'var(--c)' : 'currentColor'} stroke-width="1.7" stroke-linejoin="round" stroke-linecap="round" />
74
+ </svg>
75
+ {/each}
76
+ </span>
77
+
78
+ <style>
79
+ .sv-fre { display: inline-flex; align-items: center; gap: 2px; height: 100%; padding: 0 4px; outline: none; color: var(--sg-muted, #94a3b8); }
80
+ .sv-fre svg { cursor: pointer; flex: none; }
81
+ .sv-fre svg.is-preview { opacity: 0.55; }
82
+ </style>
@@ -0,0 +1,9 @@
1
+ type $$ComponentProps = {
2
+ value: unknown;
3
+ columnDef?: Record<string, unknown>;
4
+ onCommit: (v?: unknown) => void;
5
+ onCancel: () => void;
6
+ };
7
+ declare const RatingEditor: import("svelte").Component<$$ComponentProps, {}, "">;
8
+ type RatingEditor = ReturnType<typeof RatingEditor>;
9
+ export default RatingEditor;