@svgrid/grid 2.1.22 → 2.2.0

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 (295) hide show
  1. package/README.md +9 -2
  2. package/dist/DockNodeView.svelte +306 -0
  3. package/dist/DockNodeView.svelte.d.ts +7 -0
  4. package/dist/DockPopoutHost.svelte +17 -0
  5. package/dist/DockPopoutHost.svelte.d.ts +14 -0
  6. package/dist/FlexRender.svelte +96 -96
  7. package/dist/GridFooter.svelte +178 -178
  8. package/dist/GridMenus.svelte +83 -3
  9. package/dist/SvAutoComplete.svelte +5 -3
  10. package/dist/SvCarousel.svelte +141 -163
  11. package/dist/SvColorInput.svelte +187 -186
  12. package/dist/SvColorInput.svelte.d.ts +1 -1
  13. package/dist/SvComboBox.svelte +7 -3
  14. package/dist/SvCommand.svelte +28 -85
  15. package/dist/SvContextMenu.svelte +116 -116
  16. package/dist/SvCountryInput.svelte +1 -1
  17. package/dist/SvDateRangeInput.svelte +1 -1
  18. package/dist/SvDateTimePicker.svelte +9 -3
  19. package/dist/SvDateTimePicker.svelte.d.ts +3 -0
  20. package/dist/SvDockLayout.svelte +244 -0
  21. package/dist/SvDockLayout.svelte.d.ts +77 -0
  22. package/dist/SvDockManager.svelte +922 -0
  23. package/dist/SvDockManager.svelte.d.ts +106 -0
  24. package/dist/SvDrawer.svelte +250 -228
  25. package/dist/SvDrawer.svelte.d.ts +4 -0
  26. package/dist/SvDropDownList.svelte +85 -13
  27. package/dist/SvDropDownList.svelte.d.ts +3 -0
  28. package/dist/SvField.svelte +21 -4
  29. package/dist/SvField.svelte.d.ts +1 -0
  30. package/dist/SvForm.svelte +201 -91
  31. package/dist/SvForm.svelte.d.ts +15 -22
  32. package/dist/SvGrid.controller.svelte.d.ts +32 -1
  33. package/dist/SvGrid.controller.svelte.js +156 -27
  34. package/dist/SvGrid.css +193 -5
  35. package/dist/SvGrid.svelte +3131 -2786
  36. package/dist/SvGrid.types.d.ts +452 -1
  37. package/dist/SvGridBoard.svelte +2339 -2339
  38. package/dist/SvGridChart.svelte +1724 -1724
  39. package/dist/SvGridChartPanel.svelte +485 -485
  40. package/dist/SvGridDropdown.svelte +689 -682
  41. package/dist/SvGridSelect.svelte +1 -0
  42. package/dist/SvGroupCell.svelte +109 -109
  43. package/dist/SvListBox.svelte +36 -14
  44. package/dist/SvMaskedInput.svelte +4 -3
  45. package/dist/SvMaskedInput.svelte.d.ts +1 -1
  46. package/dist/SvMenu.svelte +124 -124
  47. package/dist/SvMenuList.svelte +117 -165
  48. package/dist/SvMenuList.svelte.d.ts +2 -13
  49. package/dist/SvModal.svelte +12 -29
  50. package/dist/SvMultiSelect.svelte +1 -0
  51. package/dist/SvNumberInput.svelte +131 -130
  52. package/dist/SvNumberInput.svelte.d.ts +1 -1
  53. package/dist/SvOtpInput.svelte +158 -158
  54. package/dist/SvPagination.svelte +18 -18
  55. package/dist/SvPasswordInput.svelte +3 -2
  56. package/dist/SvPasswordInput.svelte.d.ts +1 -1
  57. package/dist/SvPhoneInput.svelte +3 -2
  58. package/dist/SvPhoneInput.svelte.d.ts +1 -1
  59. package/dist/SvPopover.svelte +139 -139
  60. package/dist/SvRowGroupPanel.svelte +170 -170
  61. package/dist/SvScrollArea.svelte +61 -61
  62. package/dist/SvStepper.svelte +6 -9
  63. package/dist/SvTagsInput.svelte +3 -2
  64. package/dist/SvTagsInput.svelte.d.ts +1 -1
  65. package/dist/SvTooltip.svelte +127 -138
  66. package/dist/SvTour.svelte +204 -176
  67. package/dist/SvTree.svelte +377 -377
  68. package/dist/SvTreeSelect.svelte +230 -229
  69. package/dist/build-api.js +76 -54
  70. package/dist/cdn/svgrid.js +10913 -6450
  71. package/dist/cdn/svgrid.svelte-external.js +9628 -5481
  72. package/dist/chart-export.js +8 -8
  73. package/dist/columns.js +6 -0
  74. package/dist/conditional-formatting.d.ts +67 -3
  75. package/dist/conditional-formatting.js +124 -17
  76. package/dist/createCarousel.svelte.d.ts +72 -0
  77. package/dist/createCarousel.svelte.js +80 -0
  78. package/dist/createCommand.svelte.d.ts +62 -0
  79. package/dist/createCommand.svelte.js +109 -0
  80. package/dist/createForm.svelte.d.ts +62 -0
  81. package/dist/createForm.svelte.js +374 -0
  82. package/dist/createMenu.svelte.d.ts +88 -0
  83. package/dist/createMenu.svelte.js +153 -0
  84. package/dist/createOverlay.svelte.d.ts +38 -0
  85. package/dist/createOverlay.svelte.js +68 -0
  86. package/dist/createPagination.d.ts +74 -0
  87. package/dist/createPagination.js +71 -0
  88. package/dist/createPopoverSelect.svelte.js +6 -12
  89. package/dist/createStepper.d.ts +44 -0
  90. package/dist/createStepper.js +26 -0
  91. package/dist/createTooltip.svelte.d.ts +32 -0
  92. package/dist/createTooltip.svelte.js +61 -0
  93. package/dist/datetime/timezone.d.ts +36 -0
  94. package/dist/datetime/timezone.js +110 -0
  95. package/dist/dock-context.d.ts +52 -0
  96. package/dist/dock-context.js +1 -0
  97. package/dist/dock-manager-model.d.ts +136 -0
  98. package/dist/dock-manager-model.js +514 -0
  99. package/dist/dock-model.d.ts +105 -0
  100. package/dist/dock-model.js +288 -0
  101. package/dist/dock-popout.d.ts +30 -0
  102. package/dist/dock-popout.js +81 -0
  103. package/dist/editor-contract.d.ts +2 -0
  104. package/dist/filter-operators.d.ts +6 -0
  105. package/dist/filter-operators.js +35 -2
  106. package/dist/filtering/excel-filters.d.ts +18 -1
  107. package/dist/filtering/excel-filters.js +56 -0
  108. package/dist/form-field.d.ts +73 -0
  109. package/dist/form-field.js +15 -0
  110. package/dist/index.d.ts +25 -5
  111. package/dist/index.js +40 -4
  112. package/dist/list-nav.d.ts +18 -0
  113. package/dist/list-nav.js +30 -0
  114. package/dist/list-option.d.ts +2 -0
  115. package/dist/menu-item.d.ts +20 -0
  116. package/dist/menu-item.js +1 -0
  117. package/dist/menus.d.ts +5 -0
  118. package/dist/menus.js +68 -16
  119. package/dist/panel-resize.d.ts +25 -0
  120. package/dist/panel-resize.js +40 -0
  121. package/dist/popover.d.ts +29 -3
  122. package/dist/popover.js +22 -6
  123. package/dist/recurrence.d.ts +33 -7
  124. package/dist/recurrence.js +151 -13
  125. package/dist/row-drag.d.ts +8 -0
  126. package/dist/row-drag.js +11 -0
  127. package/dist/scheduler-ical.d.ts +30 -0
  128. package/dist/scheduler-ical.js +180 -0
  129. package/dist/scheduler-model.d.ts +269 -0
  130. package/dist/scheduler-model.js +602 -0
  131. package/dist/scheduler-view.svelte.d.ts +22 -0
  132. package/dist/scheduler-view.svelte.js +13 -0
  133. package/dist/spreadsheet.js +20 -12
  134. package/dist/ui-app.types.d.ts +3 -0
  135. package/package.json +14 -10
  136. package/src/DockNodeView.svelte +306 -0
  137. package/src/DockPopoutHost.svelte +17 -0
  138. package/src/FlexRender.svelte +96 -96
  139. package/src/GridFooter.svelte +178 -178
  140. package/src/GridMenus.svelte +83 -3
  141. package/src/SvAutoComplete.svelte +5 -3
  142. package/src/SvCarousel.svelte +141 -163
  143. package/src/SvCarousel.test.ts +68 -0
  144. package/src/SvColorInput.svelte +187 -186
  145. package/src/SvComboBox.svelte +7 -3
  146. package/src/SvCommand.svelte +28 -85
  147. package/src/SvCommand.test.ts +78 -0
  148. package/src/SvContextMenu.svelte +116 -116
  149. package/src/SvCountryInput.svelte +1 -1
  150. package/src/SvDateRangeInput.svelte +1 -1
  151. package/src/SvDateTimePicker.svelte +9 -3
  152. package/src/SvDockLayout.svelte +244 -0
  153. package/src/SvDockManager.svelte +922 -0
  154. package/src/SvDrawer.svelte +250 -228
  155. package/src/SvDropDownList.svelte +85 -13
  156. package/src/SvField.svelte +21 -4
  157. package/src/SvForm.svelte +201 -91
  158. package/src/SvForm.test.ts +299 -0
  159. package/src/SvGrid.controller.svelte.ts +3158 -3034
  160. package/src/SvGrid.css +193 -5
  161. package/src/SvGrid.svelte +3131 -2786
  162. package/src/SvGrid.types.ts +1489 -1027
  163. package/src/SvGridBoard.svelte +2339 -2339
  164. package/src/SvGridChart.svelte +1724 -1724
  165. package/src/SvGridChartPanel.svelte +485 -485
  166. package/src/SvGridDropdown.svelte +689 -682
  167. package/src/SvGridSelect.svelte +1 -0
  168. package/src/SvGroupCell.svelte +109 -109
  169. package/src/SvListBox.svelte +36 -14
  170. package/src/SvMaskedInput.svelte +4 -3
  171. package/src/SvMenu.svelte +124 -124
  172. package/src/SvMenu.test.ts +97 -73
  173. package/src/SvMenuList.svelte +117 -165
  174. package/src/SvModal.svelte +12 -29
  175. package/src/SvModal.test.ts +82 -0
  176. package/src/SvMultiSelect.svelte +1 -0
  177. package/src/SvNumberInput.svelte +131 -130
  178. package/src/SvOtpInput.svelte +158 -158
  179. package/src/SvPagination.svelte +18 -18
  180. package/src/SvPasswordInput.svelte +3 -2
  181. package/src/SvPhoneInput.svelte +3 -2
  182. package/src/SvPopover.svelte +139 -139
  183. package/src/SvRowGroupPanel.svelte +170 -170
  184. package/src/SvScrollArea.svelte +61 -61
  185. package/src/SvStepper.svelte +6 -9
  186. package/src/SvTagsInput.svelte +3 -2
  187. package/src/SvTooltip.svelte +127 -138
  188. package/src/SvTooltip.test.ts +73 -0
  189. package/src/SvTour.svelte +204 -176
  190. package/src/SvTree.svelte +377 -377
  191. package/src/SvTreeSelect.svelte +230 -229
  192. package/src/a11y.contract.test.ts +49 -49
  193. package/src/a11y.test.ts +59 -59
  194. package/src/a11y.ts +61 -61
  195. package/src/build-api.ts +870 -847
  196. package/src/cell-formatting.ts +169 -169
  197. package/src/cell-render.ts +469 -469
  198. package/src/chart-export.ts +201 -201
  199. package/src/chart.ts +2296 -2296
  200. package/src/collaboration.test.ts +104 -104
  201. package/src/collaboration.ts +167 -167
  202. package/src/columns.ts +5 -0
  203. package/src/conditional-formatting.test.ts +104 -0
  204. package/src/conditional-formatting.ts +176 -19
  205. package/src/core.performance.test.ts +30 -30
  206. package/src/core.ts +1111 -1111
  207. package/src/createAutocomplete.svelte.ts +132 -132
  208. package/src/createCarousel.svelte.ts +104 -0
  209. package/src/createCombobox.svelte.ts +179 -179
  210. package/src/createCommand.svelte.ts +125 -0
  211. package/src/createCountryInput.svelte.ts +157 -157
  212. package/src/createDropdownList.svelte.ts +162 -162
  213. package/src/createForm.svelte.ts +333 -0
  214. package/src/createGrid.svelte.ts +42 -42
  215. package/src/createGrid.test.ts +10 -10
  216. package/src/createGridState.svelte.ts +17 -17
  217. package/src/createMenu.svelte.ts +202 -0
  218. package/src/createOverlay.svelte.ts +101 -0
  219. package/src/createPagination.test.ts +65 -0
  220. package/src/createPagination.ts +84 -0
  221. package/src/createPopoverSelect.svelte.ts +206 -210
  222. package/src/createStepper.test.ts +62 -0
  223. package/src/createStepper.ts +61 -0
  224. package/src/createTooltip.svelte.ts +86 -0
  225. package/src/createTree.svelte.ts +319 -319
  226. package/src/datetime/timezone.test.ts +69 -0
  227. package/src/datetime/timezone.ts +134 -0
  228. package/src/dock-context.ts +47 -0
  229. package/src/dock-manager-model.test.ts +275 -0
  230. package/src/dock-manager-model.ts +593 -0
  231. package/src/dock-model.test.ts +163 -0
  232. package/src/dock-model.ts +368 -0
  233. package/src/dock-popout.ts +94 -0
  234. package/src/editing.test.ts +859 -859
  235. package/src/editing.ts +675 -675
  236. package/src/editor-contract.ts +2 -0
  237. package/src/export-data-api.test.ts +126 -126
  238. package/src/export-format.test.ts +107 -107
  239. package/src/export-format.ts +598 -598
  240. package/src/filter-operators.test.ts +59 -0
  241. package/src/filter-operators.ts +35 -2
  242. package/src/filtering/excel-filters.test.ts +86 -1
  243. package/src/filtering/excel-filters.ts +65 -0
  244. package/src/flex-render.ts +3 -3
  245. package/src/form-field.ts +87 -0
  246. package/src/index.ts +623 -469
  247. package/src/keyboard.test.ts +59 -59
  248. package/src/keyboard.ts +97 -97
  249. package/src/list-nav.test.ts +49 -0
  250. package/src/list-nav.ts +29 -0
  251. package/src/list-option.ts +2 -0
  252. package/src/menu-item.ts +21 -0
  253. package/src/menus.test.ts +48 -0
  254. package/src/menus.ts +639 -582
  255. package/src/merge-objects.ts +48 -48
  256. package/src/overlays.test.ts +90 -90
  257. package/src/panel-resize.ts +52 -0
  258. package/src/popover.bounds.test.ts +93 -0
  259. package/src/popover.ts +51 -7
  260. package/src/recurrence.test.ts +88 -1
  261. package/src/recurrence.ts +166 -15
  262. package/src/render-component.ts +28 -28
  263. package/src/row-drag.ts +10 -0
  264. package/src/scheduler-ical.test.ts +68 -0
  265. package/src/scheduler-ical.ts +180 -0
  266. package/src/scheduler-model.test.ts +546 -0
  267. package/src/scheduler-model.ts +853 -0
  268. package/src/scheduler-view.svelte.ts +33 -0
  269. package/src/selection.test.ts +754 -754
  270. package/src/selection.ts +600 -600
  271. package/src/server-data-source.test.ts +289 -289
  272. package/src/server-data-source.ts +413 -413
  273. package/src/sparkline.test.ts +68 -68
  274. package/src/sparkline.ts +169 -169
  275. package/src/spreadsheet.test.ts +489 -489
  276. package/src/spreadsheet.ts +312 -304
  277. package/src/static-functions.ts +11 -11
  278. package/src/subscribe.ts +38 -38
  279. package/src/svgrid-wrapper.types.ts +501 -501
  280. package/src/svgrid.behavior.test.ts +706 -706
  281. package/src/svgrid.charting.test.ts +527 -527
  282. package/src/svgrid.effect-driven-filter.svelte.test.ts +116 -0
  283. package/src/svgrid.features.test.ts +157 -157
  284. package/src/svgrid.new-features.wrapper.test.ts +251 -251
  285. package/src/svgrid.wrapper.test.ts +40 -40
  286. package/src/test-setup.ts +62 -62
  287. package/src/themes/index.ts +159 -159
  288. package/src/ui-app.types.ts +3 -0
  289. package/src/virtual.test.ts +6 -4
  290. package/src/virtualization/column-virtualizer.test.ts +27 -27
  291. package/src/virtualization/column-virtualizer.ts +30 -30
  292. package/src/virtualization/svelte-virtualizer.svelte.ts +26 -26
  293. package/src/virtualization/types.ts +30 -30
  294. package/src/virtualization/virtualizer.test.ts +47 -47
  295. package/src/virtualization/virtualizer.ts +296 -296
@@ -1,170 +1,170 @@
1
- <!--
2
- A row-group panel (like the "drag columns to group" bar in enterprise grids).
3
- Shows the current group-by columns as chips you can remove or drag to reorder,
4
- plus a "+ Group by" menu to add one. It is also a drop target: a column drag
5
- that carries `text/sv-column` (its column id) adds that column. Wire `onChange`
6
- to a server group model's `setGroupBy`, or to client grouping.
7
-
8
- <SvRowGroupPanel
9
- columns={[{ id: 'region', label: 'Region' }, { id: 'country', label: 'Country' }]}
10
- groupBy={view.groupBy}
11
- onChange={(g) => ctl.setGroupBy(g)}
12
- />
13
- -->
14
- <script lang="ts">
15
- type Col = { id: string; label: string }
16
- type Props = {
17
- /** Columns that can be grouped on. */
18
- columns: Col[]
19
- /** Current group-by column ids, outer to inner. */
20
- groupBy: string[]
21
- /** Called with the new group-by order. */
22
- onChange: (groupBy: string[]) => void
23
- /** Text shown when nothing is grouped. */
24
- placeholder?: string
25
- }
26
- let { columns, groupBy, onChange, placeholder = 'Drag a column here to group by it' }: Props = $props()
27
-
28
- const labelOf = (id: string) => columns.find((c) => c.id === id)?.label ?? id
29
- const available = $derived(columns.filter((c) => !groupBy.includes(c.id)))
30
-
31
- let dragIndex = $state<number | null>(null)
32
-
33
- function remove(id: string) {
34
- onChange(groupBy.filter((g) => g !== id))
35
- }
36
- function add(id: string) {
37
- if (id && !groupBy.includes(id)) onChange([...groupBy, id])
38
- }
39
- function reorder(to: number) {
40
- if (dragIndex === null || dragIndex === to) return
41
- const next = [...groupBy]
42
- const [moved] = next.splice(dragIndex, 1)
43
- next.splice(to, 0, moved!)
44
- dragIndex = null
45
- onChange(next)
46
- }
47
- function onPanelDrop(e: DragEvent) {
48
- const id = e.dataTransfer?.getData('text/sv-column')
49
- if (id) add(id)
50
- }
51
- /** Keyboard equivalent of dragging a chip: moves the chip at `i` one slot earlier/later,
52
- * reusing `reorder()` (via `dragIndex`) so there is a single source of truth for the move. */
53
- function moveByKeyboard(i: number, delta: number) {
54
- const to = i + delta
55
- if (to < 0 || to >= groupBy.length) return
56
- dragIndex = i
57
- reorder(to)
58
- }
59
- function onChipKeydown(e: KeyboardEvent, i: number) {
60
- if (!e.altKey) return
61
- if (e.key === 'ArrowLeft') {
62
- e.preventDefault()
63
- moveByKeyboard(i, -1)
64
- } else if (e.key === 'ArrowRight') {
65
- e.preventDefault()
66
- moveByKeyboard(i, 1)
67
- }
68
- }
69
- </script>
70
-
71
- <div
72
- class="sv-rowgroup-panel"
73
- role="group"
74
- aria-label="Row groups"
75
- ondragover={(e) => e.preventDefault()}
76
- ondrop={onPanelDrop}
77
- >
78
- <span class="sv-rgp-label" aria-hidden="true">Group by:</span>
79
- {#if groupBy.length === 0}
80
- <span class="sv-rgp-empty">{placeholder}</span>
81
- {:else}
82
- {#each groupBy as id, i (id)}
83
- {#if i > 0}<span class="sv-rgp-sep" aria-hidden="true">›</span>{/if}
84
- <!-- svelte-ignore a11y_no_noninteractive_tabindex, a11y_no_noninteractive_element_interactions -->
85
- <span
86
- class="sv-rgp-chip"
87
- class:sv-rgp-chip-drag={dragIndex === i}
88
- role="group"
89
- tabindex="0"
90
- aria-label={`Grouped by ${labelOf(id)}, position ${i + 1} of ${groupBy.length}. Press Alt+Arrow keys to reorder.`}
91
- draggable="true"
92
- ondragstart={() => (dragIndex = i)}
93
- ondragend={() => (dragIndex = null)}
94
- ondragover={(e) => e.preventDefault()}
95
- ondrop={() => reorder(i)}
96
- onkeydown={(e) => onChipKeydown(e, i)}
97
- >
98
- <span class="sv-rgp-grip" aria-hidden="true">⠿</span>
99
- {labelOf(id)}
100
- <button type="button" class="sv-rgp-x" onclick={() => remove(id)} aria-label={`Stop grouping by ${labelOf(id)}`}>×</button>
101
- </span>
102
- {/each}
103
- {/if}
104
- {#if available.length}
105
- <select
106
- class="sv-rgp-add"
107
- aria-label="Add a group column"
108
- onchange={(e) => { add(e.currentTarget.value); e.currentTarget.value = '' }}
109
- >
110
- <option value="">+ Group by</option>
111
- {#each available as c (c.id)}<option value={c.id}>{c.label}</option>{/each}
112
- </select>
113
- {/if}
114
- </div>
115
-
116
- <style>
117
- .sv-rowgroup-panel {
118
- display: flex;
119
- align-items: center;
120
- flex-wrap: wrap;
121
- gap: 6px;
122
- padding: 8px 10px;
123
- border: 1px dashed var(--sg-border, #cbd5e1);
124
- border-radius: 10px;
125
- background: var(--sg-header-bg, #f8fafc);
126
- font-size: 13px;
127
- }
128
- .sv-rgp-label { color: var(--sg-muted, #64748b); font-weight: 600; }
129
- .sv-rgp-empty { color: var(--sg-muted, #94a3b8); font-style: italic; }
130
- .sv-rgp-sep { color: var(--sg-muted, #94a3b8); }
131
- .sv-rgp-chip {
132
- display: inline-flex;
133
- align-items: center;
134
- gap: 6px;
135
- padding: 3px 6px 3px 8px;
136
- border-radius: 999px;
137
- background: var(--sg-bg, #fff);
138
- border: 1px solid var(--sg-border, #e2e8f0);
139
- cursor: grab;
140
- user-select: none;
141
- font-weight: 600;
142
- }
143
- .sv-rgp-chip-drag { opacity: 0.5; }
144
- .sv-rgp-grip { color: var(--sg-muted, #94a3b8); cursor: grab; }
145
- .sv-rgp-x {
146
- display: inline-flex;
147
- align-items: center;
148
- justify-content: center;
149
- width: 16px;
150
- height: 16px;
151
- border: 0;
152
- border-radius: 50%;
153
- background: none;
154
- color: var(--sg-muted, #64748b);
155
- cursor: pointer;
156
- font-size: 14px;
157
- line-height: 1;
158
- }
159
- .sv-rgp-x:hover { background: var(--sg-header-bg, #f1f5f9); color: var(--sg-fg, #0f172a); }
160
- .sv-rgp-add {
161
- font: inherit;
162
- font-size: 13px;
163
- padding: 4px 8px;
164
- border-radius: 8px;
165
- border: 1px solid var(--sg-border, #e2e8f0);
166
- background: var(--sg-bg, #fff);
167
- color: var(--sg-accent, #2563eb);
168
- cursor: pointer;
169
- }
170
- </style>
1
+ <!--
2
+ A row-group panel (like the "drag columns to group" bar in enterprise grids).
3
+ Shows the current group-by columns as chips you can remove or drag to reorder,
4
+ plus a "+ Group by" menu to add one. It is also a drop target: a column drag
5
+ that carries `text/sv-column` (its column id) adds that column. Wire `onChange`
6
+ to a server group model's `setGroupBy`, or to client grouping.
7
+
8
+ <SvRowGroupPanel
9
+ columns={[{ id: 'region', label: 'Region' }, { id: 'country', label: 'Country' }]}
10
+ groupBy={view.groupBy}
11
+ onChange={(g) => ctl.setGroupBy(g)}
12
+ />
13
+ -->
14
+ <script lang="ts">
15
+ type Col = { id: string; label: string }
16
+ type Props = {
17
+ /** Columns that can be grouped on. */
18
+ columns: Col[]
19
+ /** Current group-by column ids, outer to inner. */
20
+ groupBy: string[]
21
+ /** Called with the new group-by order. */
22
+ onChange: (groupBy: string[]) => void
23
+ /** Text shown when nothing is grouped. */
24
+ placeholder?: string
25
+ }
26
+ let { columns, groupBy, onChange, placeholder = 'Drag a column here to group by it' }: Props = $props()
27
+
28
+ const labelOf = (id: string) => columns.find((c) => c.id === id)?.label ?? id
29
+ const available = $derived(columns.filter((c) => !groupBy.includes(c.id)))
30
+
31
+ let dragIndex = $state<number | null>(null)
32
+
33
+ function remove(id: string) {
34
+ onChange(groupBy.filter((g) => g !== id))
35
+ }
36
+ function add(id: string) {
37
+ if (id && !groupBy.includes(id)) onChange([...groupBy, id])
38
+ }
39
+ function reorder(to: number) {
40
+ if (dragIndex === null || dragIndex === to) return
41
+ const next = [...groupBy]
42
+ const [moved] = next.splice(dragIndex, 1)
43
+ next.splice(to, 0, moved!)
44
+ dragIndex = null
45
+ onChange(next)
46
+ }
47
+ function onPanelDrop(e: DragEvent) {
48
+ const id = e.dataTransfer?.getData('text/sv-column')
49
+ if (id) add(id)
50
+ }
51
+ /** Keyboard equivalent of dragging a chip: moves the chip at `i` one slot earlier/later,
52
+ * reusing `reorder()` (via `dragIndex`) so there is a single source of truth for the move. */
53
+ function moveByKeyboard(i: number, delta: number) {
54
+ const to = i + delta
55
+ if (to < 0 || to >= groupBy.length) return
56
+ dragIndex = i
57
+ reorder(to)
58
+ }
59
+ function onChipKeydown(e: KeyboardEvent, i: number) {
60
+ if (!e.altKey) return
61
+ if (e.key === 'ArrowLeft') {
62
+ e.preventDefault()
63
+ moveByKeyboard(i, -1)
64
+ } else if (e.key === 'ArrowRight') {
65
+ e.preventDefault()
66
+ moveByKeyboard(i, 1)
67
+ }
68
+ }
69
+ </script>
70
+
71
+ <div
72
+ class="sv-rowgroup-panel"
73
+ role="group"
74
+ aria-label="Row groups"
75
+ ondragover={(e) => e.preventDefault()}
76
+ ondrop={onPanelDrop}
77
+ >
78
+ <span class="sv-rgp-label" aria-hidden="true">Group by:</span>
79
+ {#if groupBy.length === 0}
80
+ <span class="sv-rgp-empty">{placeholder}</span>
81
+ {:else}
82
+ {#each groupBy as id, i (id)}
83
+ {#if i > 0}<span class="sv-rgp-sep" aria-hidden="true">›</span>{/if}
84
+ <!-- svelte-ignore a11y_no_noninteractive_tabindex, a11y_no_noninteractive_element_interactions -->
85
+ <span
86
+ class="sv-rgp-chip"
87
+ class:sv-rgp-chip-drag={dragIndex === i}
88
+ role="group"
89
+ tabindex="0"
90
+ aria-label={`Grouped by ${labelOf(id)}, position ${i + 1} of ${groupBy.length}. Press Alt+Arrow keys to reorder.`}
91
+ draggable="true"
92
+ ondragstart={() => (dragIndex = i)}
93
+ ondragend={() => (dragIndex = null)}
94
+ ondragover={(e) => e.preventDefault()}
95
+ ondrop={() => reorder(i)}
96
+ onkeydown={(e) => onChipKeydown(e, i)}
97
+ >
98
+ <span class="sv-rgp-grip" aria-hidden="true">⠿</span>
99
+ {labelOf(id)}
100
+ <button type="button" class="sv-rgp-x" onclick={() => remove(id)} aria-label={`Stop grouping by ${labelOf(id)}`}>×</button>
101
+ </span>
102
+ {/each}
103
+ {/if}
104
+ {#if available.length}
105
+ <select
106
+ class="sv-rgp-add"
107
+ aria-label="Add a group column"
108
+ onchange={(e) => { add(e.currentTarget.value); e.currentTarget.value = '' }}
109
+ >
110
+ <option value="">+ Group by</option>
111
+ {#each available as c (c.id)}<option value={c.id}>{c.label}</option>{/each}
112
+ </select>
113
+ {/if}
114
+ </div>
115
+
116
+ <style>
117
+ .sv-rowgroup-panel {
118
+ display: flex;
119
+ align-items: center;
120
+ flex-wrap: wrap;
121
+ gap: 6px;
122
+ padding: 8px 10px;
123
+ border: 1px dashed var(--sg-border, #cbd5e1);
124
+ border-radius: 10px;
125
+ background: var(--sg-header-bg, #f8fafc);
126
+ font-size: 13px;
127
+ }
128
+ .sv-rgp-label { color: var(--sg-muted, #64748b); font-weight: 600; }
129
+ .sv-rgp-empty { color: var(--sg-muted, #94a3b8); font-style: italic; }
130
+ .sv-rgp-sep { color: var(--sg-muted, #94a3b8); }
131
+ .sv-rgp-chip {
132
+ display: inline-flex;
133
+ align-items: center;
134
+ gap: 6px;
135
+ padding: 3px 6px 3px 8px;
136
+ border-radius: 999px;
137
+ background: var(--sg-bg, #fff);
138
+ border: 1px solid var(--sg-border, #e2e8f0);
139
+ cursor: grab;
140
+ user-select: none;
141
+ font-weight: 600;
142
+ }
143
+ .sv-rgp-chip-drag { opacity: 0.5; }
144
+ .sv-rgp-grip { color: var(--sg-muted, #94a3b8); cursor: grab; }
145
+ .sv-rgp-x {
146
+ display: inline-flex;
147
+ align-items: center;
148
+ justify-content: center;
149
+ width: 16px;
150
+ height: 16px;
151
+ border: 0;
152
+ border-radius: 50%;
153
+ background: none;
154
+ color: var(--sg-muted, #64748b);
155
+ cursor: pointer;
156
+ font-size: 14px;
157
+ line-height: 1;
158
+ }
159
+ .sv-rgp-x:hover { background: var(--sg-header-bg, #f1f5f9); color: var(--sg-fg, #0f172a); }
160
+ .sv-rgp-add {
161
+ font: inherit;
162
+ font-size: 13px;
163
+ padding: 4px 8px;
164
+ border-radius: 8px;
165
+ border: 1px solid var(--sg-border, #e2e8f0);
166
+ background: var(--sg-bg, #fff);
167
+ color: var(--sg-accent, #2563eb);
168
+ cursor: pointer;
169
+ }
170
+ </style>
@@ -1,61 +1,61 @@
1
- <script lang="ts">
2
- /**
3
- * SvScrollArea - a scroll container with the kit's themed custom scrollbars
4
- * (Firefox `scrollbar-color` + Chromium `::-webkit-scrollbar`) consuming the
5
- * `--sg-scrollbar-*` tokens, so any panel matches the grid/demos without
6
- * hand-rolling scrollbar CSS. The fallbacks derive from `--sg-fg` so it also
7
- * adapts to light/dark when no preset defines the tokens.
8
- *
9
- * ```svelte
10
- * <SvScrollArea maxHeight="240px">…long content…</SvScrollArea>
11
- * ```
12
- */
13
- import type { Snippet } from 'svelte'
14
-
15
- type Props = {
16
- maxHeight?: string
17
- height?: string
18
- /** Scroll horizontally instead of vertically. */
19
- horizontal?: boolean
20
- /** Accessible name for the scrollable region, announced by screen readers. */
21
- ariaLabel?: string
22
- children?: Snippet
23
- }
24
-
25
- let { maxHeight, height, horizontal = false, ariaLabel = 'Scrollable content', children }: Props = $props()
26
- </script>
27
-
28
- <!-- svelte-ignore a11y_no_noninteractive_tabindex -->
29
- <div
30
- class="sv-scroll"
31
- class:is-x={horizontal}
32
- style:max-height={maxHeight}
33
- style:height={height}
34
- tabindex="0"
35
- role="region"
36
- aria-label={ariaLabel}
37
- >
38
- {@render children?.()}
39
- </div>
40
-
41
- <style>
42
- .sv-scroll {
43
- overflow: auto; overscroll-behavior: contain; min-height: 0;
44
- scrollbar-width: thin;
45
- scrollbar-color: var(--sg-scrollbar-thumb, color-mix(in srgb, var(--sg-fg, #0f172a) 26%, transparent)) var(--sg-scrollbar-bg, transparent);
46
- }
47
- .sv-scroll.is-x { overflow: auto hidden; }
48
- .sv-scroll::-webkit-scrollbar { width: 12px; height: 12px; }
49
- .sv-scroll::-webkit-scrollbar-track {
50
- background: var(--sg-scrollbar-bg, transparent);
51
- box-shadow: inset 1px 0 0 0 var(--sg-scrollbar-border, transparent);
52
- }
53
- .sv-scroll::-webkit-scrollbar-thumb {
54
- background: var(--sg-scrollbar-thumb, color-mix(in srgb, var(--sg-fg, #0f172a) 26%, transparent));
55
- border-radius: var(--sg-scrollbar-thumb-radius, 6px);
56
- border: 3px solid transparent; background-clip: padding-box;
57
- }
58
- .sv-scroll::-webkit-scrollbar-thumb:hover { background: var(--sg-scrollbar-thumb-hover, color-mix(in srgb, var(--sg-fg, #0f172a) 38%, transparent)); }
59
- .sv-scroll::-webkit-scrollbar-thumb:active { background: var(--sg-scrollbar-thumb-active, color-mix(in srgb, var(--sg-fg, #0f172a) 50%, transparent)); }
60
- .sv-scroll::-webkit-scrollbar-corner { background: var(--sg-scrollbar-bg, transparent); }
61
- </style>
1
+ <script lang="ts">
2
+ /**
3
+ * SvScrollArea - a scroll container with the kit's themed custom scrollbars
4
+ * (Firefox `scrollbar-color` + Chromium `::-webkit-scrollbar`) consuming the
5
+ * `--sg-scrollbar-*` tokens, so any panel matches the grid/demos without
6
+ * hand-rolling scrollbar CSS. The fallbacks derive from `--sg-fg` so it also
7
+ * adapts to light/dark when no preset defines the tokens.
8
+ *
9
+ * ```svelte
10
+ * <SvScrollArea maxHeight="240px">…long content…</SvScrollArea>
11
+ * ```
12
+ */
13
+ import type { Snippet } from 'svelte'
14
+
15
+ type Props = {
16
+ maxHeight?: string
17
+ height?: string
18
+ /** Scroll horizontally instead of vertically. */
19
+ horizontal?: boolean
20
+ /** Accessible name for the scrollable region, announced by screen readers. */
21
+ ariaLabel?: string
22
+ children?: Snippet
23
+ }
24
+
25
+ let { maxHeight, height, horizontal = false, ariaLabel = 'Scrollable content', children }: Props = $props()
26
+ </script>
27
+
28
+ <!-- svelte-ignore a11y_no_noninteractive_tabindex -->
29
+ <div
30
+ class="sv-scroll"
31
+ class:is-x={horizontal}
32
+ style:max-height={maxHeight}
33
+ style:height={height}
34
+ tabindex="0"
35
+ role="region"
36
+ aria-label={ariaLabel}
37
+ >
38
+ {@render children?.()}
39
+ </div>
40
+
41
+ <style>
42
+ .sv-scroll {
43
+ overflow: auto; overscroll-behavior: contain; min-height: 0;
44
+ scrollbar-width: thin;
45
+ scrollbar-color: var(--sg-scrollbar-thumb, color-mix(in srgb, var(--sg-fg, #0f172a) 26%, transparent)) var(--sg-scrollbar-bg, transparent);
46
+ }
47
+ .sv-scroll.is-x { overflow: auto hidden; }
48
+ .sv-scroll::-webkit-scrollbar { width: 12px; height: 12px; }
49
+ .sv-scroll::-webkit-scrollbar-track {
50
+ background: var(--sg-scrollbar-bg, transparent);
51
+ box-shadow: inset 1px 0 0 0 var(--sg-scrollbar-border, transparent);
52
+ }
53
+ .sv-scroll::-webkit-scrollbar-thumb {
54
+ background: var(--sg-scrollbar-thumb, color-mix(in srgb, var(--sg-fg, #0f172a) 26%, transparent));
55
+ border-radius: var(--sg-scrollbar-thumb-radius, 6px);
56
+ border: 3px solid transparent; background-clip: padding-box;
57
+ }
58
+ .sv-scroll::-webkit-scrollbar-thumb:hover { background: var(--sg-scrollbar-thumb-hover, color-mix(in srgb, var(--sg-fg, #0f172a) 38%, transparent)); }
59
+ .sv-scroll::-webkit-scrollbar-thumb:active { background: var(--sg-scrollbar-thumb-active, color-mix(in srgb, var(--sg-fg, #0f172a) 50%, transparent)); }
60
+ .sv-scroll::-webkit-scrollbar-corner { background: var(--sg-scrollbar-bg, transparent); }
61
+ </style>
@@ -14,6 +14,7 @@
14
14
  * ```
15
15
  */
16
16
  import type { StepItem } from './ui-app.types'
17
+ import { createStepper } from './createStepper'
17
18
 
18
19
  type Props = {
19
20
  steps: ReadonlyArray<StepItem>
@@ -27,22 +28,18 @@
27
28
 
28
29
  let { steps, current, onChange, linear = true, orientation = 'horizontal' }: Props = $props()
29
30
 
30
- const statusOf = (i: number): 'complete' | 'active' | 'upcoming' =>
31
- i < current ? 'complete' : i === current ? 'active' : 'upcoming'
32
- const clickable = (i: number) => (linear ? i <= current : true)
33
- const go = (i: number) => { if (clickable(i) && i !== current) onChange?.(i) }
31
+ // Status, clickability and navigation live in the shared headless core.
32
+ const st = createStepper({ count: () => steps.length, current: () => current, onChange, linear: () => linear })
34
33
  </script>
35
34
 
36
35
  <ol class="sv-step sv-step--{orientation}">
37
36
  {#each steps as step, i (i)}
38
- {@const status = statusOf(i)}
39
- <li class="sv-step__item is-{status}" class:is-clickable={clickable(i)}>
37
+ {@const status = st.statusOf(i)}
38
+ <li class="sv-step__item is-{status}" class:is-clickable={st.clickable(i)}>
40
39
  <button
41
40
  type="button"
42
41
  class="sv-step__btn"
43
- aria-current={status === 'active' ? 'step' : undefined}
44
- disabled={!clickable(i)}
45
- onclick={() => go(i)}
42
+ {...st.stepButtonProps(i)}
46
43
  >
47
44
  <span class="sv-step__marker" aria-hidden="true">
48
45
  {#if status === 'complete'}✓{:else}{i + 1}{/if}
@@ -27,7 +27,7 @@
27
27
  }
28
28
 
29
29
  let {
30
- value = [],
30
+ value = $bindable<string[]>([]),
31
31
  onChange,
32
32
  placeholder = 'Add tag…',
33
33
  disabled = false,
@@ -51,7 +51,8 @@
51
51
 
52
52
  const ti = createTagsInput({
53
53
  value: () => value,
54
- onChange: (t) => onChange?.(t),
54
+ // Write `value` (so `bind:value` works) AND fire `onChange` (callback users).
55
+ onChange: (t) => { value = t; onChange?.(t) },
55
56
  disabled: () => disabled,
56
57
  unique: () => unique,
57
58
  max: () => max,
@@ -14,6 +14,6 @@ type Props = SvEditorProps & {
14
14
  /** Override the built-in strings (draft + remove aria-labels). */
15
15
  messages?: Partial<TagsMessages>;
16
16
  };
17
- declare const SvTagsInput: import("svelte").Component<Props, {}, "">;
17
+ declare const SvTagsInput: import("svelte").Component<Props, {}, "value">;
18
18
  type SvTagsInput = ReturnType<typeof SvTagsInput>;
19
19
  export default SvTagsInput;