wx-svelte-grid 2.0.1 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wx-svelte-grid",
3
- "version": "2.0.1",
3
+ "version": "2.1.1",
4
4
  "description": "A powerful and flexible DataGrid component written in Svelte",
5
5
  "productTag": "grid",
6
6
  "productTrial": false,
@@ -30,16 +30,21 @@
30
30
  "bugs": {
31
31
  "url": "https://forum.svar.dev"
32
32
  },
33
- "homepage": "https://svar.dev/svelte/grid/",
33
+ "homepage": "https://svar.dev/svelte/datagrid/",
34
34
  "dependencies": {
35
- "wx-lib-dom": "0.7.1",
35
+ "wx-lib-dom": "0.8.0",
36
36
  "wx-lib-state": "1.9.0",
37
37
  "wx-lib-svelte": "0.5.1",
38
- "wx-svelte-menu": "2.0.1",
39
- "wx-svelte-core": "2.0.1",
40
- "wx-grid-data-provider": "2.0.1",
41
- "wx-grid-locales": "2.0.1",
42
- "wx-grid-store": "2.0.1"
38
+ "wx-svelte-menu": "2.1.0",
39
+ "wx-svelte-core": "2.1.0",
40
+ "wx-grid-data-provider": "2.1.1",
41
+ "wx-grid-locales": "2.1.1",
42
+ "wx-grid-store": "2.1.1"
43
+ },
44
+ "devDependencies": {
45
+ "wx-svelte-editor": "2.1.0",
46
+ "wx-svelte-comments": "2.1.0",
47
+ "wx-svelte-tasklist": "2.1.0"
43
48
  },
44
49
  "files": [
45
50
  "src",
package/readme.md CHANGED
@@ -19,31 +19,29 @@
19
19
 
20
20
  </div>
21
21
 
22
-
23
22
  [SVAR DataGrid](https://svar.dev/svelte/datagrid/) is an advanced Svelte component that enhances standard data tables, enabling you to create high-performance, feature-rich data grids that efficiently handle large data sets. Fully customizable, it supports inline editing with a variety of cell editors to meet diverse project requirements.
24
23
 
25
24
  <div align="center">
26
25
  <img src="https://cdn.svar.dev/public/react-grid.png" alt="SVAR Svelte DataGrid - Screenshot" width="700">
27
26
  </div>
28
27
 
29
-
30
28
  # :sparkles: Key Features
31
29
 
32
- - High performance (virtual scrolling and dynamic loading)
33
- - In-cell editing with different cell editors (datepicker, combo, select, rich select, etc.)
34
- - Sorting by multiple columns
35
- - Responsive design to adapt to different screen/container sizes
36
- - Multiple row selection
37
- - Fixed columns
38
- - Expandable/collapsible columns
39
- - Customizable tooltips for grid cells
40
- - Context menu
41
- - Tree-like structure
42
- - Paging
43
- - Export to CSV
44
- - Keyboard navigation
45
- - RestDataProvider for easy backend data binding
46
- - Dark and light skins
30
+ - High performance (virtual scrolling and dynamic loading)
31
+ - In-cell editing with different cell editors (datepicker, combo, select, rich select, etc.)
32
+ - Sorting by multiple columns
33
+ - Responsive design to adapt to different screen/container sizes
34
+ - Multiple row selection
35
+ - Fixed columns
36
+ - Expandable/collapsible columns
37
+ - Customizable tooltips for grid cells
38
+ - Context menu
39
+ - Tree-like structure
40
+ - Paging
41
+ - Export to CSV
42
+ - Keyboard navigation
43
+ - RestDataProvider for easy backend data binding
44
+ - Dark and light skins
47
45
 
48
46
  # :hammer_and_wrench: How to Use
49
47
 
@@ -80,7 +78,8 @@ To use SVAR DataGrid, simply import the package and include the component in you
80
78
 
81
79
  <Grid {data} {columns} />
82
80
  ```
83
- For further instructions, see the detailed [how-to-start guide](https://docs.svar.dev/svelte/grid/getting_started).
81
+
82
+ For further instructions, see the detailed [how-to-start guide](https://docs.svar.dev/svelte/grid/getting_started).
84
83
 
85
84
  ### :computer: How to Modify
86
85
 
@@ -104,5 +103,4 @@ To run the test:
104
103
 
105
104
  ### :speech_balloon: Need Help?
106
105
 
107
- Join our [community forum](https://forum.svar.dev) to get help or post feature requests.
108
-
106
+ Join our [community forum](https://forum.svar.dev) to get help or post feature requests.
@@ -1,63 +1,126 @@
1
1
  <script>
2
+ import { onDestroy, getContext } from "svelte";
2
3
  import { getStyle } from "../helpers/columnWidth";
3
4
  import { getRenderValue } from "wx-grid-store";
4
5
 
5
- /**
6
- * @typedef {Object} Props
7
- * @property {any} row
8
- * @property {any} col
9
- * @property {any} [cellStyle]
10
- * @property {any} [columnStyle]
11
- * @property {import('svelte').Snippet} [children]
12
- */
13
-
14
- /** @type {Props} */
15
- let { row, col, cellStyle = null, columnStyle = null, children } = $props();
6
+ let {
7
+ row,
8
+ column,
9
+ cellStyle = null,
10
+ columnStyle = null,
11
+ children,
12
+ reorder,
13
+ focusable,
14
+ } = $props();
16
15
 
17
16
  let style = $derived(
18
- getStyle(col.width, col.flexgrow, col.fixed, col.left)
17
+ getStyle(
18
+ column.width,
19
+ column.flexgrow,
20
+ column.fixed,
21
+ column.left,
22
+ column.right
23
+ )
19
24
  ),
20
25
  css = $derived(buildCellCss(columnStyle, cellStyle));
21
26
 
27
+ const api = getContext("grid-store");
28
+ const { focusCell } = api.getReactiveState();
29
+
30
+ const isDraggable = $derived(
31
+ typeof column.draggable === "function"
32
+ ? column.draggable(row, column) !== false
33
+ : column.draggable
34
+ );
35
+
36
+ let cellEl;
37
+ $effect(() => {
38
+ if (cellEl) {
39
+ if (focusable && $focusCell) cellEl.focus();
40
+ else if (!focusable && document.activeElement === cellEl)
41
+ cellEl.blur();
42
+ }
43
+ });
44
+
22
45
  function buildCellCss(columnStyle, cellStyle) {
23
46
  let css = "wx-cell";
24
- css += columnStyle ? " " + columnStyle(col) : "";
25
- css += cellStyle ? " " + cellStyle(row, col) : "";
47
+ css += column.fixed
48
+ ? " " + (column.fixed === -1 ? "wx-shadow" : "wx-fixed")
49
+ : "";
50
+ css += columnStyle ? " " + columnStyle(column) : "";
51
+ css += cellStyle ? " " + cellStyle(row, column) : "";
52
+ css += column.treetoggle ? " wx-tree-cell" : "";
26
53
  return css;
27
54
  }
55
+
56
+ function toggleFocusAction() {
57
+ if (focusable && !$focusCell) {
58
+ api.exec("focus-cell", {
59
+ row: row.id,
60
+ column: column.id,
61
+ eventSource: "focus",
62
+ });
63
+ }
64
+ }
65
+
66
+ onDestroy(() => {
67
+ if (focusable && $focusCell) {
68
+ api.exec("focus-cell", { eventSource: "destroy" });
69
+ focusable = false;
70
+ }
71
+ });
28
72
  </script>
29
73
 
74
+ <!-- svelte-ignore a11y_no_noninteractive_tabindex -->
30
75
  <div
31
76
  class={css}
32
- class:wx-shadow={col.fixed === -1}
77
+ class:wx-shadow={(column.fixed && column.fixed.left === -1) ||
78
+ column.fixed.right === -1}
79
+ bind:this={cellEl}
80
+ onfocus={toggleFocusAction}
81
+ class:wx-fixed-right={column.fixed && column.fixed.right}
33
82
  {style}
34
83
  data-row-id={row.id}
35
- data-col-id={col.id}
84
+ data-col-id={column.id}
85
+ tabindex={focusable ? "0" : "-1"}
86
+ role={"gridcell"}
87
+ aria-colindex={column._colindex}
88
+ aria-readonly={!column.editor ? true : undefined}
36
89
  >
37
- {#if col.treetoggle}
38
- <div class="wx-tree-cell">
39
- <span style="margin-left:{row.$level * 28}px;"></span>
40
- {#if row.$count}
41
- <i
42
- data-action="toggle-row"
43
- class="wx-table-tree-toggle wxi-menu-{row.open !== false
44
- ? 'down'
45
- : 'right'}"
46
- ></i>
47
- {/if}
48
- {#if children}{@render children()}{:else}{getRenderValue(
49
- row,
50
- col
51
- )}{/if}
52
- </div>
90
+ {#if reorder && column.draggable}
91
+ {#if isDraggable}
92
+ <i draggable-data="true" class="wx-draggable wxi-drag"></i>
93
+ {:else}
94
+ <i class="wx-draggable-stub"></i>
95
+ {/if}
96
+ {/if}
97
+ {#if column.treetoggle}
98
+ <span style="margin-left:{row.$level * 28}px;"></span>
99
+ {#if row.$count}
100
+ <i
101
+ data-action="toggle-row"
102
+ class="wx-table-tree-toggle wxi-menu-{row.open !== false
103
+ ? 'down'
104
+ : 'right'}"
105
+ ></i>
106
+ {/if}
107
+ {/if}
108
+ {#if column.cell}
109
+ <column.cell
110
+ {api}
111
+ {row}
112
+ {column}
113
+ onaction={({ action, data }) => api.exec(action, data)}
114
+ />
53
115
  {:else if children}{@render children()}{:else}{getRenderValue(
54
116
  row,
55
- col
117
+ column
56
118
  )}{/if}
57
119
  </div>
58
120
 
59
121
  <style>
60
122
  :global(.wx-measure-cell-body),
123
+ :global(.wx-print-cell),
61
124
  .wx-cell {
62
125
  background: inherit;
63
126
  box-sizing: border-box;
@@ -66,6 +129,7 @@
66
129
  text-overflow: ellipsis;
67
130
  white-space: nowrap;
68
131
  }
132
+ :global(.wx-print-tree-cell),
69
133
  .wx-tree-cell {
70
134
  display: flex;
71
135
  }
@@ -75,16 +139,45 @@
75
139
  border-right: var(--wx-table-cell-border);
76
140
  }
77
141
 
142
+ :global(.wx-print-draggable),
143
+ .wx-draggable,
144
+ .wx-draggable-stub {
145
+ display: inline-block;
146
+ vertical-align: middle;
147
+ margin-right: 3px;
148
+ font-size: 20px;
149
+ height: 20px;
150
+ width: 20px;
151
+ }
152
+
153
+ .wx-draggable {
154
+ cursor: move;
155
+ }
156
+
78
157
  .wx-shadow.wx-cell {
79
- border-right: var(--wx-table-fixed-column-right-border);
158
+ border-right: var(--wx-table-fixed-column-border);
80
159
  clip-path: inset(0px -15px 0px 0px);
81
160
  z-index: 1;
82
161
  }
83
162
 
163
+ .wx-fixed-right.wx-shadow.wx-cell {
164
+ border-right: var(--wx-table-cell-border);
165
+ border-left: var(--wx-table-fixed-column-border);
166
+ }
167
+ .wx-fixed-right.wx-shadow.wx-cell:last-child {
168
+ border-right: none;
169
+ }
170
+
171
+ :global(.wx-print-grid-tree-toggle),
84
172
  .wx-table-tree-toggle {
85
173
  font-size: 20px;
86
174
  cursor: pointer;
87
175
  margin: 0 8px 0 0;
88
176
  display: inline-block;
89
177
  }
178
+
179
+ .wx-cell[tabindex="0"]:focus {
180
+ outline: 1px solid var(--wx-color-primary);
181
+ outline-offset: -1px;
182
+ }
90
183
  </style>
@@ -1,7 +1,10 @@
1
1
  <script>
2
+ import { getContext } from "svelte";
2
3
  import { getStyle, getCssName } from "../helpers/columnWidth";
3
4
 
4
- let { cell, column, columnStyle } = $props();
5
+ const api = getContext("grid-store");
6
+
7
+ let { cell, column, row, columnStyle } = $props();
5
8
 
6
9
  let style = $derived(
7
10
  getStyle(
@@ -9,21 +12,43 @@
9
12
  cell.flexgrow,
10
13
  column.fixed,
11
14
  column.left,
15
+ cell.right ?? column.right,
12
16
  cell.height
13
17
  )
14
18
  );
15
19
 
16
20
  let css = $derived(getCssName(column, cell, columnStyle));
21
+
22
+ function getCell() {
23
+ return Object.fromEntries(
24
+ Object.entries(cell).filter(([key]) => key !== "cell")
25
+ );
26
+ }
17
27
  </script>
18
28
 
19
- <div class="wx-cell {css} {cell.css || ''}" {style}>
29
+ <div
30
+ class="wx-cell {css} {cell.css || ''}"
31
+ class:wx-fixed-right={column.fixed && column.fixed.right}
32
+ {style}
33
+ >
20
34
  {#if !column.collapsed && !cell.collapsed}
21
- <div class="wx-text">{cell.text || ""}</div>
35
+ {#if cell.cell}
36
+ <cell.cell
37
+ {api}
38
+ cell={getCell()}
39
+ {column}
40
+ {row}
41
+ onaction={({ action, data }) => api.exec(action, data)}
42
+ />
43
+ {:else}
44
+ <div class="wx-text">{cell.text || ""}</div>
45
+ {/if}
22
46
  {/if}
23
47
  </div>
24
48
 
25
49
  <style>
26
50
  :global(.wx-measure-cell-footer),
51
+ :global(.wx-print-cell-footer),
27
52
  .wx-cell {
28
53
  padding: 8px;
29
54
  display: flex;
@@ -33,6 +58,10 @@
33
58
  overflow: hidden;
34
59
  }
35
60
 
61
+ :global(.wx-print-cell-footer) {
62
+ display: table-cell;
63
+ }
64
+
36
65
  .wx-cell:not(:last-child) {
37
66
  border-right: var(--wx-table-footer-cell-border);
38
67
  }
@@ -41,16 +70,14 @@
41
70
  align-items: flex-end;
42
71
  }
43
72
 
44
- :global(.wx-measure-cell-footer.wx-measure-vertical) {
45
- padding: 8px;
46
- }
47
-
73
+ :global(.wx-print-cell-footer .wx-text),
48
74
  .wx-text {
49
75
  text-overflow: ellipsis;
50
76
  white-space: nowrap;
51
77
  overflow: hidden;
52
78
  }
53
79
 
80
+ :global(.wx-print-cell-footer.wx-vertical .wx-text),
54
81
  .wx-vertical .wx-text {
55
82
  transform: rotate(-90deg) translateY(100%);
56
83
  transform-origin: left bottom;
@@ -58,14 +85,27 @@
58
85
  overflow: unset;
59
86
  }
60
87
 
88
+ :global(.wx-print-cell-footer.wx-vertical .wx-text) {
89
+ display: block;
90
+ }
91
+
61
92
  .wx-cell.wx-shadow {
62
93
  clip-path: inset(0px -15px 0px 0px);
63
- border-right: var(--wx-table-fixed-column-right-border);
94
+ border-right: var(--wx-table-fixed-column-border);
95
+ }
96
+
97
+ .wx-cell.wx-fixed-right.wx-shadow {
98
+ border-right: var(--wx-table-cell-border);
99
+ border-left: var(--wx-table-fixed-column-border);
100
+ }
101
+
102
+ .wx-cell.wx-fixed-right.wx-cell:last-child {
103
+ border-right: none;
64
104
  }
65
105
 
66
106
  .wx-shadow,
67
107
  .wx-fixed {
68
- z-index: 1;
108
+ z-index: 3;
69
109
  }
70
110
 
71
111
  .wx-rowspan {
@@ -73,7 +113,13 @@
73
113
  }
74
114
 
75
115
  .wx-rowspan.wx-shadow,
76
- .wx-colspan.wx-shadow {
77
- z-index: 3;
116
+ .wx-rowspan.wx-fixed,
117
+ .wx-colspan.wx-shadow,
118
+ .wx-colspan.wx-fixed {
119
+ z-index: 4;
120
+ }
121
+
122
+ :global(.wx-f-row:not(:last-child)) .wx-cell:not(.wx-rowspan) {
123
+ border-bottom: var(--wx-table-header-cell-border);
78
124
  }
79
125
  </style>
@@ -9,7 +9,7 @@
9
9
 
10
10
  // stores
11
11
  import { EventBusRouter } from "wx-lib-state";
12
- import { DataStore } from "wx-grid-store";
12
+ import { DataStore, isCommunity } from "wx-grid-store";
13
13
 
14
14
  // ui
15
15
  import Layout from "./Layout.svelte";
@@ -29,6 +29,8 @@
29
29
  editor = null,
30
30
  filter = null,
31
31
  overlay = null,
32
+ reorder = false,
33
+ onreorder = null,
32
34
  autoRowHeight = false,
33
35
  sizes = {},
34
36
  split = { left: 0 },
@@ -87,6 +89,7 @@
87
89
  getReactiveState: dataStore.getReactive.bind(dataStore),
88
90
  exec: firstInRoute.exec.bind(firstInRoute),
89
91
  getRow: dataStore.getRow.bind(dataStore),
92
+ getRowIndex: dataStore.getRowIndex.bind(dataStore),
90
93
  });
91
94
  // auto config columns
92
95
  const finalColumns = $derived.by(() => {
@@ -111,6 +114,13 @@
111
114
  return columns;
112
115
  });
113
116
 
117
+ const isReorderAvailable = $derived.by(() => {
118
+ let available = !tree;
119
+ if (!isCommunity()) available = true;
120
+
121
+ return available ? reorder : false;
122
+ });
123
+
114
124
  let _skin = $derived(getContext("wx-theme"));
115
125
 
116
126
  let init_once = true;
@@ -126,6 +136,7 @@
126
136
  filter,
127
137
  tree,
128
138
  _skin,
139
+ _select: select,
129
140
  });
130
141
 
131
142
  if (init_once && init) {
@@ -146,7 +157,8 @@
146
157
  {rowStyle}
147
158
  {columnStyle}
148
159
  {cellStyle}
149
- {select}
160
+ reorder={isReorderAvailable}
161
+ {onreorder}
150
162
  {multiselect}
151
163
  {autoRowHeight}
152
164
  />