@svgrid/grid 3.0.0 → 3.0.2

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 (304) hide show
  1. package/CHANGELOG.md +116 -88
  2. package/README.md +199 -199
  3. package/dist/FlexRender.svelte +96 -96
  4. package/dist/GridFooter.svelte +190 -181
  5. package/dist/GridFooter.svelte.d.ts +8 -0
  6. package/dist/GridMenus.svelte +18 -10
  7. package/dist/GridMenus.svelte.d.ts +2 -1
  8. package/dist/SvAutoComplete.svelte +169 -169
  9. package/dist/SvAvatar.svelte +75 -75
  10. package/dist/SvCalendar.svelte +503 -503
  11. package/dist/SvCarousel.svelte +141 -141
  12. package/dist/SvCheckBox.svelte +102 -102
  13. package/dist/SvCircularProgress.svelte +109 -109
  14. package/dist/SvColorInput.svelte +181 -181
  15. package/dist/SvComboBox.svelte +279 -279
  16. package/dist/SvContextMenu.svelte +116 -116
  17. package/dist/SvCountryInput.svelte +163 -163
  18. package/dist/SvDrawer.svelte +254 -254
  19. package/dist/SvDropDownList.svelte +378 -378
  20. package/dist/SvDurationInput.svelte +126 -126
  21. package/dist/SvField.svelte +293 -293
  22. package/dist/SvForm.svelte +437 -437
  23. package/dist/SvGrid.controller.svelte.d.ts +17 -0
  24. package/dist/SvGrid.controller.svelte.js +128 -14
  25. package/dist/SvGrid.css +79 -10
  26. package/dist/SvGrid.svelte +191 -186
  27. package/dist/SvGrid.types.d.ts +42 -1
  28. package/dist/SvGridCellEditor.svelte +748 -744
  29. package/dist/SvGridChart.svelte +2246 -1716
  30. package/dist/SvGridChart.svelte.d.ts +63 -1
  31. package/dist/SvGridChartPanel.svelte +633 -485
  32. package/dist/SvGridChartView.svelte +79 -70
  33. package/dist/SvGridChartView.svelte.d.ts +7 -0
  34. package/dist/SvGridDropdown.svelte +728 -728
  35. package/dist/SvGridSelect.svelte +270 -270
  36. package/dist/SvGroupCell.svelte +141 -116
  37. package/dist/SvGroupCell.svelte.d.ts +8 -0
  38. package/dist/SvListBox.svelte +334 -334
  39. package/dist/SvMaskedInput.svelte +122 -122
  40. package/dist/SvMenu.svelte +124 -124
  41. package/dist/SvMenuList.svelte +146 -146
  42. package/dist/SvMultiSelect.svelte +293 -293
  43. package/dist/SvNumberInput.svelte +172 -172
  44. package/dist/SvOtpInput.svelte +158 -158
  45. package/dist/SvPasswordInput.svelte +151 -151
  46. package/dist/SvPhoneInput.svelte +133 -133
  47. package/dist/SvPopover.svelte +197 -197
  48. package/dist/SvProgress.svelte +116 -116
  49. package/dist/SvRadioGroup.svelte +107 -107
  50. package/dist/SvRating.svelte +112 -112
  51. package/dist/SvResult.svelte +73 -73
  52. package/dist/SvRichText.svelte +211 -211
  53. package/dist/SvRowGroupPanel.svelte +186 -170
  54. package/dist/SvRowGroupPanel.svelte.d.ts +8 -0
  55. package/dist/SvScrollArea.svelte +61 -61
  56. package/dist/SvSlider.svelte +203 -203
  57. package/dist/SvSwitchButton.svelte +108 -108
  58. package/dist/SvTagsInput.svelte +115 -115
  59. package/dist/SvTextInput.svelte +147 -147
  60. package/dist/SvTimePicker.svelte +245 -245
  61. package/dist/SvToaster.svelte +159 -159
  62. package/dist/SvToggleButton.svelte +85 -85
  63. package/dist/SvTooltip.svelte +161 -161
  64. package/dist/SvTour.svelte +208 -208
  65. package/dist/SvTree.svelte +444 -444
  66. package/dist/SvTreeSelect.svelte +239 -239
  67. package/dist/ai.d.ts +11 -2
  68. package/dist/ai.js +51 -7
  69. package/dist/cdn/GridMenus-DyFA-QxA.js +602 -0
  70. package/dist/cdn/GridMenus-M2XP9t0_.js +603 -0
  71. package/dist/cdn/{SvDateRangeInput-DflbiP7N.js → SvDateRangeInput-CaOuMs8O.js} +1 -1
  72. package/dist/cdn/{SvDateRangeInput-Bh0A0JkF.js → SvDateRangeInput-DMLKmGEc.js} +1 -1
  73. package/dist/cdn/{SvDateTimePicker-Bivn8dAP.js → SvDateTimePicker-CCbDZNZB.js} +1 -1
  74. package/dist/cdn/{SvDateTimePicker-BWwpfB_o.js → SvDateTimePicker-sonaH0oh.js} +1 -1
  75. package/dist/cdn/{SvGridCellEditor-Ba7rY3eu.js → SvGridCellEditor-BWnTi2N7.js} +2 -2
  76. package/dist/cdn/{SvGridCellEditor-AXL8cHGO.js → SvGridCellEditor-CjEJMJKc.js} +2 -2
  77. package/dist/cdn/SvGridChart-DAb9RbRs.js +1480 -0
  78. package/dist/cdn/SvGridChart-Yl-IXZFO.js +1481 -0
  79. package/dist/cdn/SvGridChartPanel-DayQpDsR.js +834 -0
  80. package/dist/cdn/SvGridChartPanel-aqf8n-vJ.js +810 -0
  81. package/dist/cdn/{SvGridChartView-eSPuJE6g.js → SvGridChartView-CxfakxR0.js} +5 -3
  82. package/dist/cdn/{SvGridChartView-SmPW10dI.js → SvGridChartView-Dm_YEx9L.js} +5 -3
  83. package/dist/cdn/{SvGridDropdown-B1ZcLpgs.js → SvGridDropdown-D0VdjeR8.js} +1 -1
  84. package/dist/cdn/{SvGridDropdown-CtdbHcIS.js → SvGridDropdown-D13MtJ2j.js} +1 -1
  85. package/dist/cdn/cell-formatting-C2Hf5gqd.js +86 -0
  86. package/dist/cdn/chart-CKJRCPOk.js +1652 -0
  87. package/dist/cdn/{date-format-DZT7T1wf.js → date-format-BNii4zeD.js} +2 -2
  88. package/dist/cdn/{date-format-CcP1tafP.js → date-format-BnnHlqGw.js} +2 -2
  89. package/dist/cdn/{export-format-Cv1Dll6k.js → export-format-CUDLy2yn.js} +84 -168
  90. package/dist/cdn/{src-B_YS5AOc.js → src-BJ2opd0j.js} +3642 -3450
  91. package/dist/cdn/{src-DYXXpuSk.js → src-DNbz94Ct.js} +8649 -8457
  92. package/dist/cdn/svgrid.js +16 -15
  93. package/dist/cdn/svgrid.svelte-external.js +16 -15
  94. package/dist/cell-formatting.d.ts +7 -0
  95. package/dist/cell-formatting.js +7 -1
  96. package/dist/chart-export.d.ts +23 -2
  97. package/dist/chart-export.js +88 -14
  98. package/dist/chart.d.ts +410 -18
  99. package/dist/chart.js +824 -24
  100. package/dist/editing.js +22 -13
  101. package/dist/grid-icons.d.ts +49 -0
  102. package/dist/grid-icons.js +86 -0
  103. package/dist/index.d.ts +3 -2
  104. package/dist/index.js +3 -2
  105. package/package.json +1 -1
  106. package/src/FlexRender.svelte +96 -96
  107. package/src/GridFooter.svelte +190 -181
  108. package/src/GridMenus.svelte +18 -10
  109. package/src/SvAutoComplete.svelte +169 -169
  110. package/src/SvAvatar.svelte +75 -75
  111. package/src/SvCalendar.svelte +503 -503
  112. package/src/SvCalendar.test.ts +226 -226
  113. package/src/SvCarousel.svelte +141 -141
  114. package/src/SvCheckBox.svelte +102 -102
  115. package/src/SvCircularProgress.svelte +109 -109
  116. package/src/SvColorInput.svelte +181 -181
  117. package/src/SvComboBox.svelte +279 -279
  118. package/src/SvContextMenu.svelte +116 -116
  119. package/src/SvCountryInput.svelte +163 -163
  120. package/src/SvDrawer.svelte +254 -254
  121. package/src/SvDropDownList.svelte +378 -378
  122. package/src/SvDurationInput.svelte +126 -126
  123. package/src/SvField.svelte +293 -293
  124. package/src/SvForm.svelte +437 -437
  125. package/src/SvForm.test.ts +411 -411
  126. package/src/SvGrid.controller.svelte.ts +146 -13
  127. package/src/SvGrid.css +79 -10
  128. package/src/SvGrid.svelte +191 -186
  129. package/src/SvGrid.types.ts +2133 -2092
  130. package/src/SvGridCellEditor.svelte +748 -744
  131. package/src/SvGridChart.svelte +2246 -1716
  132. package/src/SvGridChart.test.ts +243 -1
  133. package/src/SvGridChartPanel.svelte +633 -485
  134. package/src/SvGridChartView.svelte +79 -70
  135. package/src/SvGridDropdown.svelte +728 -728
  136. package/src/SvGridSelect.svelte +270 -270
  137. package/src/SvGroupCell.svelte +141 -116
  138. package/src/SvListBox.svelte +334 -334
  139. package/src/SvMaskedInput.svelte +122 -122
  140. package/src/SvMenu.svelte +124 -124
  141. package/src/SvMenu.test.ts +97 -97
  142. package/src/SvMenuList.svelte +146 -146
  143. package/src/SvMultiSelect.svelte +293 -293
  144. package/src/SvNumberInput.svelte +172 -172
  145. package/src/SvOtpInput.svelte +158 -158
  146. package/src/SvPasswordInput.svelte +151 -151
  147. package/src/SvPhoneInput.svelte +133 -133
  148. package/src/SvPopover.svelte +197 -197
  149. package/src/SvProgress.svelte +116 -116
  150. package/src/SvRadioGroup.svelte +107 -107
  151. package/src/SvRating.svelte +112 -112
  152. package/src/SvResult.svelte +73 -73
  153. package/src/SvRichText.svelte +211 -211
  154. package/src/SvRowGroupPanel.svelte +186 -170
  155. package/src/SvScrollArea.svelte +61 -61
  156. package/src/SvSlider.svelte +203 -203
  157. package/src/SvSwitchButton.svelte +108 -108
  158. package/src/SvTagsInput.svelte +115 -115
  159. package/src/SvTextInput.svelte +147 -147
  160. package/src/SvTimePicker.svelte +245 -245
  161. package/src/SvToaster.svelte +159 -159
  162. package/src/SvToaster.test.ts +95 -95
  163. package/src/SvToggleButton.svelte +85 -85
  164. package/src/SvTooltip.svelte +161 -161
  165. package/src/SvTour.svelte +208 -208
  166. package/src/SvTree.svelte +444 -444
  167. package/src/SvTreeSelect.svelte +239 -239
  168. package/src/a11y/dismissable.test.ts +119 -119
  169. package/src/a11y/dismissable.ts +114 -114
  170. package/src/a11y.contract.test.ts +49 -49
  171. package/src/a11y.test.ts +59 -59
  172. package/src/a11y.ts +61 -61
  173. package/src/ai.test.ts +561 -502
  174. package/src/ai.ts +1472 -1419
  175. package/src/build-api.coverage.test.ts +633 -633
  176. package/src/build-api.ts +846 -846
  177. package/src/builtin-editors.grid.test.ts +83 -83
  178. package/src/cell-formatting.ts +177 -171
  179. package/src/cell-render.test.ts +513 -513
  180. package/src/cell-render.ts +496 -496
  181. package/src/cell-values.ts +148 -148
  182. package/src/chart-export.test.ts +112 -0
  183. package/src/chart-export.ts +270 -202
  184. package/src/chart-view.svelte.ts +36 -36
  185. package/src/chart.test.ts +830 -1
  186. package/src/chart.ts +3342 -2321
  187. package/src/collaboration.test.ts +104 -104
  188. package/src/collaboration.ts +167 -167
  189. package/src/column-groups.ts +78 -78
  190. package/src/core.performance.test.ts +30 -30
  191. package/src/core.ts +1865 -1865
  192. package/src/createAutocomplete.svelte.ts +132 -132
  193. package/src/createCombobox.svelte.ts +191 -191
  194. package/src/createCountryInput.svelte.ts +157 -157
  195. package/src/createDropdownList.svelte.ts +168 -168
  196. package/src/createForm.svelte.ts +386 -386
  197. package/src/createGrid.svelte.ts +42 -42
  198. package/src/createGrid.test.ts +10 -10
  199. package/src/createGridState.svelte.ts +17 -17
  200. package/src/createListbox.svelte.ts +250 -250
  201. package/src/createMenu.svelte.ts +224 -224
  202. package/src/createPopoverSelect.svelte.ts +213 -213
  203. package/src/createSlider.svelte.ts +191 -191
  204. package/src/createTooltip.svelte.ts +144 -144
  205. package/src/createTree.svelte.ts +322 -322
  206. package/src/datetime/date-core.ts +206 -206
  207. package/src/datetime/date-restrict.ts +61 -61
  208. package/src/datetime/timezone.ts +135 -135
  209. package/src/dock-manager-model.ts +596 -596
  210. package/src/dock-model.ts +374 -374
  211. package/src/editing.test.ts +974 -974
  212. package/src/editing.ts +618 -609
  213. package/src/editor-contract.ts +171 -171
  214. package/src/editor-registry.grid.test.ts +144 -144
  215. package/src/editor-registry.ts +122 -122
  216. package/src/export-data-api.test.ts +126 -126
  217. package/src/export-format.test.ts +107 -107
  218. package/src/export-format.ts +601 -601
  219. package/src/filter-operators.ts +160 -160
  220. package/src/filtering/excel-filters.ts +325 -325
  221. package/src/flex-render.ts +3 -3
  222. package/src/form-field.ts +127 -127
  223. package/src/grid-icons.test.ts +46 -0
  224. package/src/grid-icons.ts +184 -0
  225. package/src/group-display.test.ts +167 -167
  226. package/src/group-display.ts +200 -200
  227. package/src/headless.ts +87 -87
  228. package/src/icon-overrides.grid.test.ts +188 -0
  229. package/src/icon-seam.test.ts +100 -0
  230. package/src/index.ts +19 -0
  231. package/src/js-scroller.svelte.ts +173 -173
  232. package/src/keyboard-handlers.ts +270 -270
  233. package/src/keyboard.test.ts +59 -59
  234. package/src/keyboard.ts +97 -97
  235. package/src/list-nav.test.ts +49 -49
  236. package/src/list-nav.ts +29 -29
  237. package/src/list-option.test.ts +56 -56
  238. package/src/list-option.ts +179 -179
  239. package/src/menus.ts +597 -597
  240. package/src/merge-objects.ts +48 -48
  241. package/src/overlays.test.ts +90 -90
  242. package/src/positioning.ts +268 -268
  243. package/src/render-component.ts +28 -28
  244. package/src/row-drag.test.ts +401 -401
  245. package/src/row-drag.ts +419 -419
  246. package/src/row-resize.test.ts +524 -524
  247. package/src/row-resize.ts +228 -228
  248. package/src/scheduler-ical.ts +181 -181
  249. package/src/scheduler-model.test.ts +562 -562
  250. package/src/scheduler-model.ts +873 -873
  251. package/src/selection.test.ts +885 -885
  252. package/src/server-data-source.test.ts +383 -383
  253. package/src/server-data-source.ts +469 -469
  254. package/src/sparkline.test.ts +68 -68
  255. package/src/sparkline.ts +169 -169
  256. package/src/spreadsheet.test.ts +488 -488
  257. package/src/spreadsheet.ts +312 -312
  258. package/src/static-functions.ts +11 -11
  259. package/src/subscribe.ts +38 -38
  260. package/src/summaries.ts +113 -113
  261. package/src/svgrid-wrapper.types.ts +563 -563
  262. package/src/svgrid.async-editor-options.test.ts +273 -273
  263. package/src/svgrid.auto-row-height.test.ts +204 -204
  264. package/src/svgrid.behavior.test.ts +910 -910
  265. package/src/svgrid.charting.test.ts +654 -534
  266. package/src/svgrid.comments-autocomplete.test.ts +127 -127
  267. package/src/svgrid.context-menu.test.ts +147 -147
  268. package/src/svgrid.features.test.ts +157 -157
  269. package/src/svgrid.filter-depth.test.ts +163 -163
  270. package/src/svgrid.filter-menu-listbox.svelte.test.ts +382 -377
  271. package/src/svgrid.filter-menu-scroll.test.ts +112 -112
  272. package/src/svgrid.grand-total.test.ts +188 -188
  273. package/src/svgrid.group-display-mode.test.ts +171 -171
  274. package/src/svgrid.group-footers.test.ts +121 -121
  275. package/src/svgrid.group-pagination.test.ts +153 -153
  276. package/src/svgrid.new-features.wrapper.test.ts +251 -251
  277. package/src/svgrid.tree-data.test.ts +186 -186
  278. package/src/svgrid.wrapper.test.ts +63 -63
  279. package/src/svgriddropdown.async-panel.svelte.test.ts +195 -195
  280. package/src/test-setup.ts +62 -62
  281. package/src/themes/index.ts +288 -288
  282. package/src/toast-store.svelte.ts +250 -250
  283. package/src/toast-store.test.ts +147 -147
  284. package/src/tree-row-model.test.ts +168 -168
  285. package/src/ui-buttons.test.ts +144 -144
  286. package/src/ui-inputs.test.ts +118 -118
  287. package/src/ui-localization.test.ts +113 -113
  288. package/src/ui-range.test.ts +70 -70
  289. package/src/ui-selection.test.ts +155 -155
  290. package/src/ui-tier1.test.ts +142 -142
  291. package/src/virtual.test.ts +88 -88
  292. package/src/virtualization/column-virtualizer.test.ts +27 -27
  293. package/src/virtualization/column-virtualizer.ts +30 -30
  294. package/src/virtualization/svelte-virtualizer.svelte.ts +26 -26
  295. package/src/virtualization/types.ts +30 -30
  296. package/src/virtualization/virtualizer.test.ts +47 -47
  297. package/src/virtualization/virtualizer.ts +322 -322
  298. package/dist/cdn/GridMenus-DMihUtma.js +0 -600
  299. package/dist/cdn/GridMenus-nmNDj1a3.js +0 -601
  300. package/dist/cdn/SvGridChart-Bs2GIR2Q.js +0 -1202
  301. package/dist/cdn/SvGridChart-CwhFz7GV.js +0 -1203
  302. package/dist/cdn/SvGridChartPanel-1WXuStzM.js +0 -561
  303. package/dist/cdn/SvGridChartPanel-e5_nqNP9.js +0 -585
  304. package/dist/cdn/chart-i4XcXyHJ.js +0 -1214
package/src/SvGrid.svelte CHANGED
@@ -23,6 +23,7 @@
23
23
  } from "./render-component";
24
24
  import { buildSparkline, toSparklineValues } from "./sparkline";
25
25
  import { localizeOperatorLabel } from "./filter-operators";
26
+ import { GRID_ICON_GLYPHS, type GridIconName } from "./grid-icons";
26
27
  // The whole editor UI - including the lazy SvGridDropdown / SvDateTimePicker
27
28
  // and the custom-editor registry - now lives in SvGridCellEditor.svelte, which
28
29
  // this component loads with import() once editing is enabled.
@@ -671,9 +672,19 @@
671
672
  for (const chip of chips.slice(fit)) chip.style.display = "none";
672
673
  const hidden = chips.length - fit;
673
674
  more.textContent = `+${hidden}`;
675
+ // Read the label element rather than stripping the remove button's glyph
676
+ // off the end of the chip's text. That regex assumed the button always
677
+ // renders one specific character, which stopped being true once `icons`
678
+ // let a consumer replace it - any other glyph, or an SVG, leaked into
679
+ // this tooltip.
674
680
  more.title = chips
675
681
  .slice(fit)
676
- .map((c) => c.textContent?.replace(/×$/, "").trim() ?? "")
682
+ .map(
683
+ (c) =>
684
+ (
685
+ c.querySelector(".sv-grid-filter-chip-label") ?? c
686
+ ).textContent?.trim() ?? "",
687
+ )
677
688
  .join(", ");
678
689
  };
679
690
  // Measure after layout settles.
@@ -734,6 +745,158 @@
734
745
  </p>
735
746
  {/snippet}
736
747
 
748
+ <!-- Every icon the grid draws for its own chrome comes through here, so the
749
+ `icons` prop has exactly one place to intercept. Three branches, in
750
+ order: a consumer override, a glyph icon whose default is a character,
751
+ and the built-in path set.
752
+
753
+ The override is wrapped in `.sv-grid-icon` rather than the consumer
754
+ being asked to add that class themselves. Sizing and the expander's
755
+ rotate-on-open both hang off it (SvGrid.css), and an override that
756
+ dropped the class would lose both silently - which is the kind of bug
757
+ that only shows up in someone else's app. -->
758
+ {#snippet icon(name: GridIconName)}
759
+ {@const override = opt.icons?.[name]}
760
+ {#if override}
761
+ <span class="sv-grid-icon sv-grid-icon-custom" aria-hidden="true"
762
+ >{@render override()}</span
763
+ >
764
+ {:else if GRID_ICON_GLYPHS[name]}
765
+ {GRID_ICON_GLYPHS[name]}
766
+ {:else}
767
+ <svg
768
+ class="sv-grid-icon"
769
+ viewBox="0 0 24 24"
770
+ fill="none"
771
+ stroke="currentColor"
772
+ stroke-width="2.2"
773
+ stroke-linecap="round"
774
+ stroke-linejoin="round"
775
+ aria-hidden="true"
776
+ >
777
+ {#if name === "sort"}
778
+ <path d="M8 10l4-4 4 4" />
779
+ <path d="M8 14l4 4 4-4" />
780
+ {:else if name === "sort-asc"}
781
+ <path d="M6 14l6-6 6 6" />
782
+ {:else if name === "sort-desc"}
783
+ <path d="M6 10l6 6 6-6" />
784
+ {:else if name === "filter"}
785
+ <path d="M3 5h18l-7 8v6l-4 2v-8z" />
786
+ {:else if name === "menu"}
787
+ <path d="M4 7h16" />
788
+ <path d="M4 12h16" />
789
+ <path d="M4 17h16" />
790
+ {:else if name === "group"}
791
+ <path d="M12 3l8 4.5-8 4.5-8-4.5z" />
792
+ <path d="M4 12l8 4.5 8-4.5" />
793
+ <path d="M4 16.5l8 4.5 8-4.5" />
794
+ {:else if name === "x" || name === "unpin"}
795
+ <path d="M18 6L6 18" />
796
+ <path d="M6 6l12 12" />
797
+ {:else if name === "chevron-down" || name === "column-group-caret"}
798
+ <path d="M6 9l6 6 6-6" />
799
+ {:else if name === "chevron-right"}
800
+ <!-- Same path SvTree's twisty uses, so every expander in the library
801
+ draws the same chevron. Rotated 90deg by CSS when expanded rather
802
+ than swapped for a second glyph. -->
803
+ <path d="m9 18 6-6-6-6" />
804
+ {:else if name === "op-contains" || name === "search"}
805
+ <!-- The magnifier the operator menu draws is also the one every search
806
+ box in the grid draws. Four hand-inlined copies used to diverge
807
+ here (different viewBox, different stroke width); they share this
808
+ arm now, so re-skinning `search` catches all of them. -->
809
+ <circle cx="11" cy="11" r="6" />
810
+ <path d="M20 20l-4.5-4.5" />
811
+ {:else if name === "op-equals"}
812
+ <path d="M5 9.5h14" />
813
+ <path d="M5 14.5h14" />
814
+ {:else if name === "op-startsWith" || name === "pin-left"}
815
+ <!-- `pin-left` / `pin-right` / `unpin` share the operator glyphs rather
816
+ than borrowing the operator NAMES, which is what the menu used to
817
+ do. Same default, but overriding a filter operator no longer
818
+ silently repaints the pin menu. -->
819
+ <path d="M5 5v14" />
820
+ <path d="M9 9h10" />
821
+ <path d="M9 15h7" />
822
+ {:else if name === "op-greaterThan" || name === "pin-right"}
823
+ <path d="M8 5l9 7-9 7" />
824
+ {:else if name === "op-lessThan"}
825
+ <path d="M16 5l-9 7 9 7" />
826
+ {:else if name === "op-between"}
827
+ <!-- Two bounds with the span between them. The catalogue has always
828
+ named this icon; the snippet had no case for it, so the Between
829
+ row in the operator menu drew an empty <svg>. -->
830
+ <path d="M5 5v14" />
831
+ <path d="M19 5v14" />
832
+ <path d="M9 12h6" />
833
+ {:else if name === "op-isBlank"}
834
+ <circle cx="12" cy="12" r="8" />
835
+ <path d="M6.5 6.5l11 11" />
836
+ {:else if name === "op-isNotBlank"}
837
+ <circle cx="12" cy="12" r="8" />
838
+ <circle cx="12" cy="12" r="3.2" fill="currentColor" stroke="none" />
839
+ {:else if name === "op-notContains"}
840
+ <circle cx="11" cy="11" r="6" />
841
+ <path d="M20 20l-4.5-4.5" />
842
+ <path d="M7 11h8" />
843
+ {:else if name === "op-notEquals"}
844
+ <path d="M5 9.5h14" />
845
+ <path d="M5 14.5h14" />
846
+ <path d="M16 5l-8 14" />
847
+ {:else if name === "op-endsWith"}
848
+ <path d="M19 5v14" />
849
+ <path d="M15 9H5" />
850
+ <path d="M15 15H8" />
851
+ {:else if name === "op-regex"}
852
+ <path d="M12 5v9" />
853
+ <path d="M8.1 7.4l7.8 4.5" />
854
+ <path d="M15.9 7.4l-7.8 4.5" />
855
+ <circle cx="6" cy="18" r="1.4" fill="currentColor" stroke="none" />
856
+ {:else if name === "op-in"}
857
+ <path d="M14 5a7 7 0 1 0 0 14" />
858
+ <path d="M6 12h9" />
859
+ <path d="M12 9l3 3-3 3" />
860
+ {:else if name === "op-notIn"}
861
+ <path d="M14 5a7 7 0 1 0 0 14" />
862
+ <path d="M15 12H6" />
863
+ <path d="M9 9l-3 3 3 3" />
864
+ {:else if name === "autosize"}
865
+ <path d="M3 12h18" />
866
+ <path d="M3 12l4-4" />
867
+ <path d="M3 12l4 4" />
868
+ <path d="M21 12l-4-4" />
869
+ <path d="M21 12l-4 4" />
870
+ {:else if name === "columns"}
871
+ <rect x="3" y="4" width="5" height="16" rx="1" />
872
+ <rect x="10" y="4" width="5" height="16" rx="1" />
873
+ <rect x="17" y="4" width="4" height="16" rx="1" />
874
+ {:else if name === "reset"}
875
+ <path d="M3 4v6h6" />
876
+ <path d="M3.5 10A9 9 0 1 0 6 5.3" />
877
+ {:else if name === "tool-panel"}
878
+ <!-- Deliberately NOT the same rects as `columns`: this one is 6/4/4 and
879
+ `columns` is 5/5/4. Two different marks for two different things,
880
+ and merging them would visibly change the toolbar button. -->
881
+ <rect x="3" y="4" width="6" height="16" rx="1" />
882
+ <rect x="11" y="4" width="4" height="16" rx="1" />
883
+ <rect x="17" y="4" width="4" height="16" rx="1" />
884
+ {:else if name === "chart"}
885
+ <line x1="12" y1="20" x2="12" y2="10" />
886
+ <line x1="18" y1="20" x2="18" y2="4" />
887
+ <line x1="6" y1="20" x2="6" y2="16" />
888
+ {:else if name === "advanced-filter"}
889
+ <!-- A filled-corner funnel, distinct from `filter`'s outline path. It
890
+ marks an ACTIVE advanced filter, so it has to read differently
891
+ from the plain funnel sitting in the header next to it. -->
892
+ <polygon
893
+ points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3"
894
+ />
895
+ {/if}
896
+ </svg>
897
+ {/if}
898
+ {/snippet}
899
+
737
900
  {#if opt.loading && !opt.loadingOverlay && !hasMeasured}
738
901
  <!-- Full-screen loading state only on the *initial* load, before the grid
739
902
  has ever rendered. Once measured, a `loading` flip (from a server-mode
@@ -759,10 +922,7 @@
759
922
  >
760
923
  {#if boardConfig.searchable !== false}
761
924
  <label class="sv-grid-board-search">
762
- <svg viewBox="0 0 16 16" aria-hidden="true" width="14" height="14">
763
- <circle cx="7" cy="7" r="4.5" fill="none" stroke="currentColor" stroke-width="1.5" />
764
- <line x1="10.2" y1="10.2" x2="14" y2="14" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" />
765
- </svg>
925
+ {@render icon("search")}
766
926
  <input
767
927
  type="search"
768
928
  placeholder={boardConfig.searchPlaceholder ?? "Search cards..."}
@@ -807,10 +967,7 @@
807
967
  >
808
968
  {#if schedulerConfig.searchable !== false}
809
969
  <label class="sv-grid-board-search">
810
- <svg viewBox="0 0 16 16" aria-hidden="true" width="14" height="14">
811
- <circle cx="7" cy="7" r="4.5" fill="none" stroke="currentColor" stroke-width="1.5" />
812
- <line x1="10.2" y1="10.2" x2="14" y2="14" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" />
813
- </svg>
970
+ {@render icon("search")}
814
971
  <input
815
972
  type="search"
816
973
  placeholder={schedulerConfig.searchPlaceholder ?? "Search events..."}
@@ -855,10 +1012,7 @@
855
1012
  >
856
1013
  {#if chartViewConfig.searchable !== false}
857
1014
  <label class="sv-grid-board-search">
858
- <svg viewBox="0 0 16 16" aria-hidden="true" width="14" height="14">
859
- <circle cx="7" cy="7" r="4.5" fill="none" stroke="currentColor" stroke-width="1.5" />
860
- <line x1="10.2" y1="10.2" x2="14" y2="14" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" />
861
- </svg>
1015
+ {@render icon("search")}
862
1016
  <input
863
1017
  type="search"
864
1018
  placeholder={chartViewConfig.searchPlaceholder ?? "Search data..."}
@@ -874,6 +1028,7 @@
874
1028
  data={boardData}
875
1029
  columns={opt.columns}
876
1030
  chart={chartViewConfig}
1031
+ localization={opt.localization}
877
1032
  getRowId={opt.getRowId}
878
1033
  />
879
1034
  {:else if ChartView}
@@ -881,6 +1036,7 @@
881
1036
  data={boardData}
882
1037
  columns={opt.columns}
883
1038
  chart={chartViewConfig}
1039
+ localization={opt.localization}
884
1040
  getRowId={opt.getRowId}
885
1041
  />
886
1042
  {:else}
@@ -927,112 +1083,6 @@
927
1083
  </div>
928
1084
  </div>
929
1085
  {:else}
930
- {#snippet icon(name: string)}
931
- <svg
932
- class="sv-grid-icon"
933
- viewBox="0 0 24 24"
934
- fill="none"
935
- stroke="currentColor"
936
- stroke-width="2.2"
937
- stroke-linecap="round"
938
- stroke-linejoin="round"
939
- aria-hidden="true"
940
- >
941
- {#if name === "sort"}
942
- <path d="M8 10l4-4 4 4" />
943
- <path d="M8 14l4 4 4-4" />
944
- {:else if name === "sort-asc"}
945
- <path d="M6 14l6-6 6 6" />
946
- {:else if name === "sort-desc"}
947
- <path d="M6 10l6 6 6-6" />
948
- {:else if name === "filter"}
949
- <path d="M3 5h18l-7 8v6l-4 2v-8z" />
950
- {:else if name === "menu"}
951
- <path d="M4 7h16" />
952
- <path d="M4 12h16" />
953
- <path d="M4 17h16" />
954
- {:else if name === "group"}
955
- <path d="M12 3l8 4.5-8 4.5-8-4.5z" />
956
- <path d="M4 12l8 4.5 8-4.5" />
957
- <path d="M4 16.5l8 4.5 8-4.5" />
958
- {:else if name === "x"}
959
- <path d="M18 6L6 18" />
960
- <path d="M6 6l12 12" />
961
- {:else if name === "chevron-down"}
962
- <path d="M6 9l6 6 6-6" />
963
- {:else if name === "chevron-right"}
964
- <!-- Same path SvTree's twisty uses, so every expander in the library
965
- draws the same chevron. Rotated 90deg by CSS when expanded rather
966
- than swapped for a second glyph. -->
967
- <path d="m9 18 6-6-6-6" />
968
- {:else if name === "op-contains"}
969
- <circle cx="11" cy="11" r="6" />
970
- <path d="M20 20l-4.5-4.5" />
971
- {:else if name === "op-equals"}
972
- <path d="M5 9.5h14" />
973
- <path d="M5 14.5h14" />
974
- {:else if name === "op-startsWith"}
975
- <path d="M5 5v14" />
976
- <path d="M9 9h10" />
977
- <path d="M9 15h7" />
978
- {:else if name === "op-greaterThan"}
979
- <path d="M8 5l9 7-9 7" />
980
- {:else if name === "op-lessThan"}
981
- <path d="M16 5l-9 7 9 7" />
982
- {:else if name === "op-between"}
983
- <!-- Two bounds with the span between them. The catalogue has always
984
- named this icon; the snippet had no case for it, so the Between
985
- row in the operator menu drew an empty <svg>. -->
986
- <path d="M5 5v14" />
987
- <path d="M19 5v14" />
988
- <path d="M9 12h6" />
989
- {:else if name === "op-isBlank"}
990
- <circle cx="12" cy="12" r="8" />
991
- <path d="M6.5 6.5l11 11" />
992
- {:else if name === "op-isNotBlank"}
993
- <circle cx="12" cy="12" r="8" />
994
- <circle cx="12" cy="12" r="3.2" fill="currentColor" stroke="none" />
995
- {:else if name === "op-notContains"}
996
- <circle cx="11" cy="11" r="6" />
997
- <path d="M20 20l-4.5-4.5" />
998
- <path d="M7 11h8" />
999
- {:else if name === "op-notEquals"}
1000
- <path d="M5 9.5h14" />
1001
- <path d="M5 14.5h14" />
1002
- <path d="M16 5l-8 14" />
1003
- {:else if name === "op-endsWith"}
1004
- <path d="M19 5v14" />
1005
- <path d="M15 9H5" />
1006
- <path d="M15 15H8" />
1007
- {:else if name === "op-regex"}
1008
- <path d="M12 5v9" />
1009
- <path d="M8.1 7.4l7.8 4.5" />
1010
- <path d="M15.9 7.4l-7.8 4.5" />
1011
- <circle cx="6" cy="18" r="1.4" fill="currentColor" stroke="none" />
1012
- {:else if name === "op-in"}
1013
- <path d="M14 5a7 7 0 1 0 0 14" />
1014
- <path d="M6 12h9" />
1015
- <path d="M12 9l3 3-3 3" />
1016
- {:else if name === "op-notIn"}
1017
- <path d="M14 5a7 7 0 1 0 0 14" />
1018
- <path d="M15 12H6" />
1019
- <path d="M9 9l-3 3 3 3" />
1020
- {:else if name === "autosize"}
1021
- <path d="M3 12h18" />
1022
- <path d="M3 12l4-4" />
1023
- <path d="M3 12l4 4" />
1024
- <path d="M21 12l-4-4" />
1025
- <path d="M21 12l-4 4" />
1026
- {:else if name === "columns"}
1027
- <rect x="3" y="4" width="5" height="16" rx="1" />
1028
- <rect x="10" y="4" width="5" height="16" rx="1" />
1029
- <rect x="17" y="4" width="4" height="16" rx="1" />
1030
- {:else if name === "reset"}
1031
- <path d="M3 4v6h6" />
1032
- <path d="M3.5 10A9 9 0 1 0 6 5.3" />
1033
- {/if}
1034
- </svg>
1035
- {/snippet}
1036
1086
 
1037
1087
  {#snippet cellBody(
1038
1088
  row: Row<TData>,
@@ -1370,7 +1420,7 @@
1370
1420
  <td
1371
1421
  class="sv-grid-cell sv-grid-row-number-cell"
1372
1422
  style={`width: ${rowNumberColumnWidth}px; min-width: ${rowNumberColumnWidth}px; max-width: ${rowNumberColumnWidth}px; left: 0;`}
1373
- >{where === "top" ? "" : ""}</td
1423
+ >{#if where === "top"}{@render icon("pinned-row-top")}{:else}{@render icon("pinned-row-bottom")}{/if}</td
1374
1424
  >
1375
1425
  {/if}
1376
1426
  {#if showRowSelectionEffective}
@@ -1458,9 +1508,7 @@
1458
1508
  to undo it. This is that something: state plus a way out.
1459
1509
  -->
1460
1510
  <span class="sv-grid-advf-chip">
1461
- <svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
1462
- <polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3" />
1463
- </svg>
1511
+ {@render icon("advanced-filter")}
1464
1512
  {messages.advancedFilterActive}
1465
1513
  <button
1466
1514
  type="button"
@@ -1468,7 +1516,7 @@
1468
1516
  aria-label={messages.advancedFilterClear}
1469
1517
  title={messages.advancedFilterClear}
1470
1518
  onclick={() => (ctrl.advancedFilter = null)}
1471
- >✕</button>
1519
+ >{@render icon("clear")}</button>
1472
1520
  </span>
1473
1521
  {/if}
1474
1522
  {#if toolPanelEnabled}
@@ -1482,21 +1530,7 @@
1482
1530
  aria-expanded={ctrl.toolPanelOpen}
1483
1531
  onclick={() => (ctrl.toolPanelOpen = !ctrl.toolPanelOpen)}
1484
1532
  >
1485
- <svg
1486
- viewBox="0 0 24 24"
1487
- width="15"
1488
- height="15"
1489
- fill="none"
1490
- stroke="currentColor"
1491
- stroke-width="2"
1492
- stroke-linecap="round"
1493
- stroke-linejoin="round"
1494
- aria-hidden="true"
1495
- >
1496
- <rect x="3" y="4" width="6" height="16" rx="1" />
1497
- <rect x="11" y="4" width="4" height="16" rx="1" />
1498
- <rect x="17" y="4" width="4" height="16" rx="1" />
1499
- </svg>
1533
+ {@render icon("tool-panel")}
1500
1534
  Columns &amp; Filters
1501
1535
  </button>
1502
1536
  {/if}
@@ -1509,9 +1543,7 @@
1509
1543
  aria-expanded={ctrl.chartPanelOpen}
1510
1544
  onclick={() => (ctrl.chartPanelOpen = !ctrl.chartPanelOpen)}
1511
1545
  >
1512
- <svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
1513
- <line x1="12" y1="20" x2="12" y2="10" /><line x1="18" y1="20" x2="18" y2="4" /><line x1="6" y1="20" x2="6" y2="16" />
1514
- </svg>
1546
+ {@render icon("chart")}
1515
1547
  Chart
1516
1548
  </button>
1517
1549
  {/if}
@@ -1519,7 +1551,7 @@
1519
1551
  {/if}
1520
1552
 
1521
1553
  {#if hasMeasured && (opt.paginationPosition === "top" || opt.paginationPosition === "both")}
1522
- <GridFooter {ctrl} showStatus={false} top pager pageSizeOptions={opt.pageSizeOptions} />
1554
+ <GridFooter {ctrl} {icon} showStatus={false} top pager pageSizeOptions={opt.pageSizeOptions} />
1523
1555
  {/if}
1524
1556
 
1525
1557
  <div
@@ -1613,20 +1645,9 @@
1613
1645
  <span class="sv-grid-group-header-label"
1614
1646
  >{cell.label}</span
1615
1647
  >
1616
- <svg
1617
- class="sv-grid-group-caret"
1618
- viewBox="0 0 16 16"
1619
- width="10"
1620
- height="10"
1621
- fill="none"
1622
- stroke="currentColor"
1623
- stroke-width="2.5"
1624
- stroke-linecap="round"
1625
- stroke-linejoin="round"
1626
- aria-hidden="true"
1648
+ <span class="sv-grid-group-caret" aria-hidden="true"
1649
+ >{@render icon("column-group-caret")}</span
1627
1650
  >
1628
- <polyline points="4 6 8 10 12 6"></polyline>
1629
- </svg>
1630
1651
  </button>
1631
1652
  {:else}
1632
1653
  <span class="sv-grid-group-header-label"
@@ -1659,7 +1680,9 @@
1659
1680
  style={`width: ${rowNumberColumnWidth}px; min-width: ${rowNumberColumnWidth}px; max-width: ${rowNumberColumnWidth}px; left: 0;`}
1660
1681
  aria-label="Row number"
1661
1682
  >
1662
- <span class="sv-grid-row-number-head">#</span>
1683
+ <span class="sv-grid-row-number-head"
1684
+ >{@render icon("row-number")}</span
1685
+ >
1663
1686
  </th>
1664
1687
  {/if}
1665
1688
  {#if showRowSelectionEffective}
@@ -1980,7 +2003,7 @@
1980
2003
  onmousedown={(event) => {
1981
2004
  event.preventDefault();
1982
2005
  removeFilterChip(rendered.column.id, token);
1983
- }}>×</button
2006
+ }}>{@render icon("remove")}</button
1984
2007
  >
1985
2008
  </span>
1986
2009
  {/each}
@@ -2819,32 +2842,14 @@
2819
2842
  {/if}
2820
2843
  </div>
2821
2844
 
2822
- <GridFooter {ctrl} pager={(opt.paginationPosition ?? "bottom") !== "top"} pageSizeOptions={opt.pageSizeOptions} />
2845
+ <GridFooter {ctrl} {icon} pager={(opt.paginationPosition ?? "bottom") !== "top"} pageSizeOptions={opt.pageSizeOptions} />
2823
2846
 
2824
2847
  {#if ctrl.findOpen}
2825
2848
  <!-- Find-in-grid overlay. Anchored to the TOP of the grid root so
2826
2849
  it tracks the grid even when the page scrolls. Ctrl+F opens;
2827
2850
  Enter cycles to the next hit; Esc closes. -->
2828
2851
  <div class="sv-grid-find" role="search" aria-label="Find in grid">
2829
- <svg class="sv-grid-find-icon" viewBox="0 0 16 16" aria-hidden="true">
2830
- <circle
2831
- cx="7"
2832
- cy="7"
2833
- r="4.5"
2834
- fill="none"
2835
- stroke="currentColor"
2836
- stroke-width="1.5"
2837
- />
2838
- <line
2839
- x1="10.2"
2840
- y1="10.2"
2841
- x2="14"
2842
- y2="14"
2843
- stroke="currentColor"
2844
- stroke-width="1.5"
2845
- stroke-linecap="round"
2846
- />
2847
- </svg>
2852
+ {@render icon("search")}
2848
2853
  <input
2849
2854
  class="sv-grid-find-input"
2850
2855
  type="search"
@@ -2897,7 +2902,7 @@
2897
2902
  setActiveCell(hit.rowIndex, hit.colIndex);
2898
2903
  scrollActiveCellIntoView(hit.rowIndex, hit.colIndex);
2899
2904
  }
2900
- }}>↑</button
2905
+ }}>{@render icon("find-prev")}</button
2901
2906
  >
2902
2907
  <button
2903
2908
  type="button"
@@ -2911,7 +2916,7 @@
2911
2916
  setActiveCell(hit.rowIndex, hit.colIndex);
2912
2917
  scrollActiveCellIntoView(hit.rowIndex, hit.colIndex);
2913
2918
  }
2914
- }}>↓</button
2919
+ }}>{@render icon("find-next")}</button
2915
2920
  >
2916
2921
  <button
2917
2922
  type="button"
@@ -2922,7 +2927,7 @@
2922
2927
  ctrl.findQuery = "";
2923
2928
  // Return focus to the grid instead of letting it fall to <body> (#80).
2924
2929
  ctrl.gridRootEl?.focus({ preventScroll: true });
2925
- }}>✕</button
2930
+ }}>{@render icon("close")}</button
2926
2931
  >
2927
2932
  </div>
2928
2933
  {/if}
@@ -2960,7 +2965,7 @@
2960
2965
  type="button"
2961
2966
  class="sv-grid-tool-panel-close"
2962
2967
  aria-label="Close"
2963
- onclick={() => (ctrl.toolPanelOpen = false)}>✕</button
2968
+ onclick={() => (ctrl.toolPanelOpen = false)}>{@render icon("close")}</button
2964
2969
  >
2965
2970
  </div>
2966
2971
  <div class="sv-grid-tool-panel-tabs" role="tablist">
@@ -3004,21 +3009,21 @@
3004
3009
  class:is-active={grouped}
3005
3010
  aria-label={grouped ? "Ungroup" : "Group by"}
3006
3011
  title={grouped ? "Ungroup" : "Group by this column"}
3007
- onclick={() => toggleGroupInPanel(column.id)}>⊞</button
3012
+ onclick={() => toggleGroupInPanel(column.id)}>{@render icon("group-add")}</button
3008
3013
  >
3009
3014
  <button
3010
3015
  type="button"
3011
3016
  class="sv-grid-tool-panel-btn"
3012
3017
  aria-label="Move up"
3013
3018
  disabled={i === 0}
3014
- onclick={() => moveColumnInPanel(column.id, -1)}>↑</button
3019
+ onclick={() => moveColumnInPanel(column.id, -1)}>{@render icon("move-up")}</button
3015
3020
  >
3016
3021
  <button
3017
3022
  type="button"
3018
3023
  class="sv-grid-tool-panel-btn"
3019
3024
  aria-label="Move down"
3020
3025
  disabled={i === toolPanelColumns.length - 1}
3021
- onclick={() => moveColumnInPanel(column.id, 1)}>↓</button
3026
+ onclick={() => moveColumnInPanel(column.id, 1)}>{@render icon("move-down")}</button
3022
3027
  >
3023
3028
  </span>
3024
3029
  </li>
@@ -3050,7 +3055,7 @@
3050
3055
  class="sv-grid-tp-filter-clear"
3051
3056
  aria-label={`Clear ${toolPanelHeaderLabel(column)} filter`}
3052
3057
  title={messages.clearFilter}
3053
- onclick={() => clearColumnFilter(column.id)}>✕</button
3058
+ onclick={() => clearColumnFilter(column.id)}>{@render icon("clear")}</button
3054
3059
  >
3055
3060
  {/if}
3056
3061
  </div>