wx-svelte-grid 2.5.0 → 2.6.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wx-svelte-grid",
3
- "version": "2.5.0",
3
+ "version": "2.6.0",
4
4
  "description": "A fast, feature-rich Svelte DataGrid component",
5
5
  "productTag": "grid",
6
6
  "productTrial": false,
@@ -33,19 +33,19 @@
33
33
  },
34
34
  "homepage": "https://svar.dev/svelte/datagrid/",
35
35
  "dependencies": {
36
- "@svar-ui/lib-dom": "0.11.1",
36
+ "@svar-ui/lib-dom": "0.12.1",
37
37
  "@svar-ui/lib-state": "1.9.6",
38
38
  "@svar-ui/lib-svelte": "0.5.2",
39
- "@svar-ui/svelte-menu": "2.4.0",
40
- "@svar-ui/svelte-core": "2.4.0",
41
- "@svar-ui/svelte-toolbar": "2.4.0",
42
- "@svar-ui/grid-data-provider": "2.5.0",
43
- "@svar-ui/grid-locales": "2.5.0",
44
- "@svar-ui/grid-store": "2.5.0"
39
+ "@svar-ui/svelte-menu": "2.5.0",
40
+ "@svar-ui/svelte-core": "2.5.0",
41
+ "@svar-ui/svelte-toolbar": "2.5.0",
42
+ "@svar-ui/grid-data-provider": "2.6.0",
43
+ "@svar-ui/grid-locales": "2.6.0",
44
+ "@svar-ui/grid-store": "2.6.0"
45
45
  },
46
46
  "devDependencies": {
47
- "@svar-ui/svelte-editor": "2.4.0",
48
- "@svar-ui/svelte-filter": "2.4.0"
47
+ "@svar-ui/svelte-editor": "2.5.0",
48
+ "@svar-ui/svelte-filter": "2.5.0"
49
49
  },
50
50
  "files": [
51
51
  "src",
package/readme.md CHANGED
@@ -19,7 +19,7 @@
19
19
 
20
20
  </div>
21
21
 
22
- [SVAR Svelte DataGrid](https://svar.dev/svelte/datagrid/) is a high-performance Svelte component for building feature-rich, accessible data tables with sorting, filtering, paging, in-cell editing, and virtual scrolling. Easily customizable with CSS and a developer-friendly API.
22
+ [SVAR Svelte DataGrid](https://svar.dev/svelte/datagrid/) is a high-performance Svelte component for building feature-rich, accessible data tables. It supports sorting, advanced filtering, paging, in-cell editing, and virtual scrolling out of the box. Comes with full TypeScript support and a flexible, developer-friendly API. Suitable for dashboards, admin panels, and data-heavy SaaS applications.
23
23
 
24
24
  <div align="center">
25
25
  <img src="https://cdn.svar.dev/public/react-grid.png" alt="SVAR Svelte DataGrid - Screenshot" width="700">
@@ -29,26 +29,30 @@
29
29
 
30
30
  Here is a quick overview of what SVAR Svelte DataGrid offers:
31
31
 
32
- - High performance (virtual scrolling for rows and columns)
32
+ - High performance (virtual scrolling and dynamic loading)
33
33
  - In-cell editing with different cell editors (datepicker, combo, select, rich select, etc.)
34
+ - External editor for grid data
34
35
  - Custom HTML for cells
35
36
  - Sorting by multiple columns
36
- - Filtering
37
+ - Advanced filtering (including natural language)
37
38
  - Paging
38
- - Fixed columns
39
+ - Frozen columns
39
40
  - Expandable/collapsible columns
41
+ - Row reordering with drag-and-drop
40
42
  - Customizable tooltips for grid cells
41
43
  - Context menu
42
- - External editor for grid data
44
+ - Built-in toolbar
43
45
  - Tree-like structure
44
- - Print support
45
- - Responsive design to adapt to different screen/container sizes
46
- - Accessibility: compatible with [WAI-ARIA](https://www.w3.org/WAI/standards-guidelines/aria/) standard
46
+ - Print support, export to CSV
47
+ - Undo/redo
47
48
  - Keyboard navigation
49
+ - Accessibility: compatibility with [WAI-ARIA](https://www.w3.org/WAI/standards-guidelines/aria/) standard
48
50
  - RestDataProvider for easy backend data binding
49
- - Dark and light skins
51
+ - Dark and light skins, customizable with CSS (no Tailwind dependency)
50
52
  - Full TypeScript support
51
53
 
54
+ [Check the demos](https://docs.svar.dev/svelte/grid/samples/#/base/willow) to see how these features work.
55
+
52
56
  ### :hammer_and_wrench: How to Use
53
57
 
54
58
  To use SVAR Svelte DataGrid, simply import the package and include the component in your Svelte file:
@@ -87,14 +91,14 @@ To use SVAR Svelte DataGrid, simply import the package and include the component
87
91
 
88
92
  For further instructions, see the detailed [how-to-start guide](https://docs.svar.dev/svelte/grid/getting_started).
89
93
 
90
- ### :computer: How to Modify
94
+ ### How to Modify
91
95
 
92
96
  Typically, you don't need to modify the code. However, if you wish to do so, follow these steps:
93
97
 
94
98
  1. Run `yarn` to install dependencies. Note that this project is a monorepo using `yarn` workspaces, so npm will not work
95
99
  2. Start the project in development mode with `yarn start`
96
100
 
97
- ### :white_check_mark: Run Tests
101
+ ### Run Tests
98
102
 
99
103
  To run the test:
100
104
 
@@ -107,6 +111,10 @@ To run the test:
107
111
  yarn test:cypress
108
112
  ```
109
113
 
110
- ### :speech_balloon: Need Help?
114
+ ### Need Help?
111
115
 
112
116
  Join our [community forum](https://forum.svar.dev) to get help or post feature requests.
117
+
118
+ ### ⭐ Show Your Support
119
+
120
+ If SVAR Svelte DataGrid helps your project, [give us a star on GitHub](https://github.com/svar-widgets/grid)! It helps more developers discover this component and keeps our team motivated to ship new features.
@@ -2,6 +2,7 @@
2
2
  import { onDestroy, getContext, untrack } from "svelte";
3
3
  import { getStyle } from "../helpers/columnWidth";
4
4
  import { getRenderValue } from "@svar-ui/grid-store";
5
+ import { setID } from "@svar-ui/lib-dom";
5
6
 
6
7
  let {
7
8
  row,
@@ -95,8 +96,8 @@
95
96
  onfocus={toggleFocusAction}
96
97
  class:wx-fixed-right={column.fixed && column.fixed.right}
97
98
  {style}
98
- data-row-id={row.id}
99
- data-col-id={column.id}
99
+ data-row-id={setID(row.id)}
100
+ data-col-id={setID(column.id)}
100
101
  tabindex={focusable ? "0" : "-1"}
101
102
  role={"gridcell"}
102
103
  aria-colindex={column._colindex}
@@ -39,6 +39,7 @@
39
39
  sortMarks = {},
40
40
  undo = false,
41
41
  hotkeys = null,
42
+ filterValues = {},
42
43
  ...restProps
43
44
  } = $props();
44
45
 
@@ -147,7 +148,7 @@
147
148
  let _skin = $derived(getContext("wx-theme"));
148
149
  let init_once = true;
149
150
 
150
- $effect.pre(() => {
151
+ const reinitStore = () => {
151
152
  dataStore.init({
152
153
  data,
153
154
  columns: finalColumns,
@@ -157,6 +158,7 @@
157
158
  dynamic,
158
159
  tree,
159
160
  sortMarks,
161
+ filterValues,
160
162
  select,
161
163
  undo,
162
164
  reorder,
@@ -167,7 +169,10 @@
167
169
  init(api);
168
170
  init_once = false;
169
171
  }
170
- });
172
+ };
173
+
174
+ reinitStore();
175
+ $effect(reinitStore);
171
176
  </script>
172
177
 
173
178
  <Locale words={en} optional={true}>
@@ -3,6 +3,7 @@
3
3
  import { resize } from "../helpers/actions/resize";
4
4
  import { getCssName, getStyle } from "../helpers/columnWidth";
5
5
  import Filter from "./inlineFilters/Filter.svelte";
6
+ import { setID } from "@svar-ui/lib-dom";
6
7
 
7
8
  let {
8
9
  cell,
@@ -49,7 +50,7 @@
49
50
  }
50
51
  api.exec("sort-rows", {
51
52
  key: cell.id,
52
- add: ev.ctrlKey,
53
+ add: ev.ctrlKey || ev.metaKey,
53
54
  order: sortMark?.order,
54
55
  });
55
56
  }
@@ -106,7 +107,7 @@
106
107
  tabindex="0"
107
108
  onkeydown={toggleCollapseColumn}
108
109
  onclick={collapse}
109
- data-header-id={column.id}
110
+ data-header-id={setID(column.id)}
110
111
  >
111
112
  <div class="wx-text" style={collapsedTextStyle}>
112
113
  {cell.text || ""}
@@ -121,7 +122,7 @@
121
122
  class:wx-fixed-right={column.fixed && column.fixed.right}
122
123
  {style}
123
124
  onclick={sort}
124
- data-header-id={column.id}
125
+ data-header-id={setID(column.id)}
125
126
  tabindex={!cell._hidden && column.sort && !cell.filter
126
127
  ? "0"
127
128
  : undefined}
@@ -9,9 +9,10 @@
9
9
  import {
10
10
  clickOutside,
11
11
  delegateClick,
12
- locateAttr,
13
12
  locate,
14
- id,
13
+ setID,
14
+ locateID,
15
+ getID,
15
16
  } from "@svar-ui/lib-dom";
16
17
 
17
18
  import { hotkeys, defaultHotkeys } from "@svar-ui/grid-store";
@@ -410,12 +411,12 @@
410
411
 
411
412
  const bodyClickHandlers = {
412
413
  dblclick: (id, ev) => {
413
- const data = { id, column: locateAttr(ev, "data-col-id") };
414
+ const data = { id, column: locateID(ev, "data-col-id") };
414
415
  api.exec("open-editor", data);
415
416
  },
416
417
  click: (id, ev) => {
417
418
  if (postDrag) return;
418
- const column = locateAttr(ev, "data-col-id");
419
+ const column = locateID(ev, "data-col-id");
419
420
  if ($focusCell?.id !== id)
420
421
  api.exec("focus-cell", {
421
422
  row: id,
@@ -425,7 +426,7 @@
425
426
 
426
427
  if ($select === false) return;
427
428
 
428
- const toggle = multiselect && ev.ctrlKey;
429
+ const toggle = multiselect && (ev.ctrlKey || ev.metaKey);
429
430
  const range = multiselect && ev.shiftKey;
430
431
 
431
432
  if (
@@ -467,11 +468,11 @@
467
468
 
468
469
  dragItem = from;
469
470
 
470
- if (api.getRow(dragItem).open)
471
+ if ($tree && api.getRow(dragItem).open)
471
472
  api.exec("close-row", { id: dragItem, nested: true });
472
473
 
473
474
  // default to drag source (target may be shifted by this moment)
474
- const itemNode = locate(sourceNode, "data-id");
475
+ const itemNode = locate(sourceNode);
475
476
  dragNode = itemNode.cloneNode(true);
476
477
  dragNode.classList.remove("wx-selected");
477
478
  dragNode
@@ -521,8 +522,8 @@
521
522
  }
522
523
 
523
524
  if (tableNode.contains(context.targetNode)) {
524
- const targetRow = locate(context.targetNode, "data-id");
525
- const to = id(targetRow?.getAttribute("data-id"));
525
+ const targetRow = locate(context.targetNode);
526
+ const to = targetRow && getID(targetRow);
526
527
 
527
528
  if (to && to !== from) {
528
529
  context.to = to;
@@ -675,9 +676,9 @@
675
676
  !focus ||
676
677
  (visibleSelection.length &&
677
678
  !visibleSelection.includes(focus.row)) ||
678
- dataRows.findIndex(r => r.id == focus.row) === -1 ||
679
+ dataRows.findIndex(r => r.id === focus.row) === -1 ||
679
680
  renderColumns.data.findIndex(
680
- c => c.id == focus.column && !c.collapsed
681
+ c => c.id === focus.column && !c.collapsed
681
682
  ) === -1
682
683
  ) {
683
684
  const row = visibleSelection[0] || dataRows[0].id;
@@ -753,6 +754,7 @@
753
754
  style="width:{contentWidth}px;height:{fullHeight}px;"
754
755
  onmousedown={ev => lockSelection(ev)}
755
756
  use:clickOutside={() =>
757
+ $focusCell &&
756
758
  api.exec("focus-cell", { eventSource: "click" })}
757
759
  use:delegateClick={bodyClickHandlers}
758
760
  >
@@ -771,8 +773,8 @@
771
773
  class:wx-autoheight={autoRowHeight}
772
774
  class={"wx-row" +
773
775
  (rowStyle ? " " + rowStyle(row) : "")}
774
- data-id={row.id}
775
- data-context-id={row.id}
776
+ data-id={setID(row.id)}
777
+ data-context-id={setID(row.id)}
776
778
  class:wx-selected={isSelected}
777
779
  class:wx-inactive={dragItem === row.id}
778
780
  style={`${autoRowHeight ? "min-height" : "height"}:${row.rowHeight || defaultRowHeight}px;`}
@@ -786,7 +788,7 @@
786
788
  {#each renderColumns.data as column (column.id)}
787
789
  {#if column.collapsed}
788
790
  <div class="wx-cell wx-collapsed"></div>
789
- {:else if $editor?.id === row.id && $editor.column == column.id}
791
+ {:else if $editor?.id === row.id && $editor.column === column.id}
790
792
  <Editor {row} {column} />
791
793
  {:else}
792
794
  <Cell
@@ -796,7 +798,7 @@
796
798
  {cellStyle}
797
799
  {reorder}
798
800
  focusable={focus?.row === row.id &&
799
- focus?.column == column.id}
801
+ focus?.column === column.id}
800
802
  />
801
803
  {/if}
802
804
  {/each}
@@ -1,5 +1,6 @@
1
1
  <script>
2
2
  import { getRenderValue } from "@svar-ui/grid-store";
3
+ import { getID } from "@svar-ui/lib-dom";
3
4
 
4
5
  let { content: Content = null, api, children } = $props();
5
6
 
@@ -12,8 +13,8 @@
12
13
  function findAttribute(node) {
13
14
  while (node) {
14
15
  if (node.getAttribute) {
15
- const id = node.getAttribute("data-row-id");
16
- const colId = node.getAttribute("data-col-id");
16
+ const id = getID(node, "data-row-id");
17
+ const colId = getID(node, "data-col-id");
17
18
  if (id && api && colId) {
18
19
  const col = api.getColumn(colId);
19
20
  return { id, col, target: node };
@@ -1,8 +1,9 @@
1
1
  <script>
2
2
  import { onMount } from "svelte";
3
3
  import { SuggestDropdown } from "@svar-ui/svelte-core";
4
+ import { clickOutside } from "@svar-ui/lib-dom";
4
5
 
5
- let { actions, editor, onaction } = $props();
6
+ let { editor, onaction, onsave, onapply } = $props();
6
7
 
7
8
  let { value, renderedValue: text, options: filterOptions } = $state(editor);
8
9
  let { template, cell } = $state(editor?.config || {});
@@ -10,8 +11,8 @@
10
11
  let index = $derived(filterOptions.findIndex(a => a.id === value));
11
12
 
12
13
  function updateValue({ id }) {
13
- actions.updateValue(id);
14
- actions.save();
14
+ onapply(id);
15
+ onsave();
15
16
  }
16
17
 
17
18
  let navigate;
@@ -46,6 +47,7 @@
46
47
  bind:value={text}
47
48
  oninput={input}
48
49
  onkeydown={e => keydown(e, index)}
50
+ use:clickOutside={() => onsave(true)}
49
51
  />
50
52
  <SuggestDropdown items={filterOptions} onready={ready} onselect={updateValue}>
51
53
  {#snippet children({ option })}
@@ -1,9 +1,10 @@
1
1
  <script>
2
2
  import { onMount } from "svelte";
3
+ import { clickOutside } from "@svar-ui/lib-dom";
3
4
 
4
5
  import { Calendar, Dropdown } from "@svar-ui/svelte-core";
5
6
 
6
- let { actions, editor, onaction } = $props();
7
+ let { editor, onaction, onsave, onapply, oncancel } = $props();
7
8
 
8
9
  let value = $state(editor.value || new Date());
9
10
 
@@ -11,8 +12,8 @@
11
12
  let cell = $state(editor.config?.cell);
12
13
 
13
14
  function updateValue({ value }) {
14
- actions.updateValue(value);
15
- actions.save();
15
+ onapply(value);
16
+ onsave();
16
17
  }
17
18
 
18
19
  let node;
@@ -31,7 +32,7 @@
31
32
  class="wx-value"
32
33
  bind:this={node}
33
34
  tabindex="0"
34
- onclick={() => actions.cancel()}
35
+ onclick={oncancel}
35
36
  onkeydown={ev => ev.preventDefault()}
36
37
  >
37
38
  {#if template}
@@ -42,7 +43,13 @@
42
43
  {:else}<span class="wx-text">{editor.renderedValue}</span>{/if}
43
44
  </div>
44
45
  <Dropdown width={"auto"}>
45
- <Calendar {value} onchange={updateValue} buttons={editor.config?.buttons} />
46
+ <div use:clickOutside={() => onsave(true)}>
47
+ <Calendar
48
+ {value}
49
+ onchange={updateValue}
50
+ buttons={editor.config?.buttons}
51
+ />
52
+ </div>
46
53
  </Dropdown>
47
54
 
48
55
  <style>
@@ -1,7 +1,6 @@
1
1
  <script>
2
2
  import { getContext } from "svelte";
3
3
  import { getStyle } from "../../helpers/columnWidth";
4
- import { clickOutside } from "@svar-ui/lib-dom";
5
4
  import { editors } from "./editors";
6
5
 
7
6
  let { column, row } = $props();
@@ -35,7 +34,13 @@
35
34
  }
36
35
 
37
36
  function keyHandler(ev) {
38
- if (ev.key === "Enter" && $editor) cancel();
37
+ if (ev.key === "Enter" && $editor) {
38
+ if (column.editor.type === "multiselect") {
39
+ updateValue($editor.value);
40
+ } else {
41
+ cancel();
42
+ }
43
+ }
39
44
  }
40
45
 
41
46
  let style = $derived(
@@ -71,11 +76,12 @@
71
76
  onclick={ev => ev.stopPropagation()}
72
77
  ondblclick={ev => ev.stopPropagation()}
73
78
  onkeydown={keyHandler}
74
- use:clickOutside={() => save(true)}
75
79
  >
76
80
  <SvelteComponent
77
81
  editor={$editor}
78
- actions={{ save, cancel, updateValue }}
82
+ onsave={save}
83
+ onapply={updateValue}
84
+ oncancel={cancel}
79
85
  onaction={({ action, data }) => api.exec(action, data)}
80
86
  />
81
87
  </div>
@@ -0,0 +1,113 @@
1
+ <script>
2
+ import { SuggestDropdown } from "@svar-ui/svelte-core";
3
+ import { clickOutside } from "@svar-ui/lib-dom";
4
+ import { onMount } from "svelte";
5
+
6
+ let { editor, onaction, onsave, onapply, oncancel } = $props();
7
+ let { config } = $state(editor);
8
+
9
+ const options = $derived(editor?.options ?? []);
10
+ let value = $derived(editor?.value || []);
11
+ let renderedValue = $derived(editor?.renderedValue);
12
+ let index = $derived.by(() => {
13
+ const firstSelected = options.find(opt => value.includes(opt.id));
14
+ return firstSelected ? options.indexOf(firstSelected) : -1;
15
+ });
16
+
17
+ function updateValue({ id }) {
18
+ onapply(id);
19
+ node.focus();
20
+ }
21
+
22
+ let navigate;
23
+ let keydown = $state();
24
+
25
+ function ready(ev) {
26
+ navigate = ev.navigate;
27
+ keydown = ev.keydown;
28
+ navigate(index);
29
+ }
30
+
31
+ let node = $state();
32
+ onMount(() => {
33
+ node.focus();
34
+ if (window && window.getSelection) {
35
+ window.getSelection().removeAllRanges();
36
+ }
37
+ });
38
+ </script>
39
+
40
+ <!-- svelte-ignore a11y_click_events_have_key_events -->
41
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
42
+ <!-- svelte-ignore a11y_no_noninteractive_tabindex -->
43
+ <div
44
+ bind:this={node}
45
+ class="wx-value"
46
+ tabindex="0"
47
+ onclick={oncancel}
48
+ onkeydown={ev => {
49
+ keydown(ev, index);
50
+ ev.preventDefault();
51
+ }}
52
+ use:clickOutside={() => onsave(true)}
53
+ >
54
+ {#if config?.template}
55
+ {config.template(value?.map(id => options.find(opt => opt.id === id)))}
56
+ {:else if config?.cell}
57
+ {@const SvelteComponent = config.cell}
58
+ <SvelteComponent
59
+ data={value.map(id => options.find(opt => opt.id === id))}
60
+ />
61
+ {:else}
62
+ <span class="wx-text">{renderedValue}</span>
63
+ {/if}
64
+ </div>
65
+
66
+ <SuggestDropdown
67
+ items={options}
68
+ onready={ready}
69
+ onselect={updateValue}
70
+ checkboxes={true}
71
+ multiselect={true}
72
+ {value}
73
+ >
74
+ {#snippet children({ option })}
75
+ <div class="wx-option">
76
+ {#if config?.template}
77
+ {config.template(option)}
78
+ {:else if config?.cell}
79
+ {@const SvelteComponent = config.cell}
80
+ <SvelteComponent data={option} {onaction} />
81
+ {:else}
82
+ {option.label}
83
+ {/if}
84
+ </div>
85
+ {/snippet}
86
+ </SuggestDropdown>
87
+
88
+ <style>
89
+ .wx-option {
90
+ display: flex;
91
+ direction: row;
92
+ align-items: center;
93
+ justify-content: flex-start;
94
+ gap: 8px;
95
+ }
96
+ .wx-text {
97
+ width: 100%;
98
+ white-space: nowrap;
99
+ overflow: hidden;
100
+ text-overflow: ellipsis;
101
+ }
102
+
103
+ .wx-value {
104
+ width: 100%;
105
+ height: 100%;
106
+ padding: 8px;
107
+ overflow: hidden;
108
+ outline: none;
109
+ border: 1px solid var(--wx-color-primary);
110
+ text-overflow: ellipsis;
111
+ white-space: nowrap;
112
+ }
113
+ </style>
@@ -1,8 +1,9 @@
1
1
  <script>
2
2
  import { onMount } from "svelte";
3
3
  import { SuggestDropdown } from "@svar-ui/svelte-core";
4
+ import { clickOutside } from "@svar-ui/lib-dom";
4
5
 
5
- let { actions, editor, onaction } = $props();
6
+ let { editor, onaction, onsave, onapply, oncancel } = $props();
6
7
 
7
8
  let data = $state(editor.options.find(opt => opt.id === editor.value));
8
9
  let { value, options } = $state(editor);
@@ -11,8 +12,8 @@
11
12
  let index = $derived(options.findIndex(a => a.id === value));
12
13
 
13
14
  function updateValue({ id }) {
14
- actions.updateValue(id);
15
- actions.save();
15
+ onapply(id);
16
+ onsave();
16
17
  }
17
18
 
18
19
  let navigate;
@@ -40,11 +41,12 @@
40
41
  bind:this={node}
41
42
  class="wx-value"
42
43
  tabindex="0"
43
- onclick={() => actions.cancel()}
44
+ onclick={oncancel}
44
45
  onkeydown={ev => {
45
46
  keydown(ev, index);
46
47
  ev.preventDefault();
47
48
  }}
49
+ use:clickOutside={() => onsave(true)}
48
50
  >
49
51
  {#if template}
50
52
  {template(data)}
@@ -1,7 +1,8 @@
1
1
  <script>
2
2
  import { onMount } from "svelte";
3
+ import { clickOutside } from "@svar-ui/lib-dom";
3
4
 
4
- let { actions, editor } = $props();
5
+ let { editor, onsave, onapply } = $props();
5
6
 
6
7
  let value = $state(editor.value || "");
7
8
 
@@ -10,15 +11,16 @@
10
11
 
11
12
  function updateValue() {
12
13
  value = node.value;
13
- actions.updateValue(node.value);
14
+ onapply(node.value);
14
15
  }
15
16
 
16
17
  function closeAndSave({ key }) {
17
- if (key === "Enter") actions.save();
18
+ if (key === "Enter") onsave();
18
19
  }
19
20
  </script>
20
21
 
21
22
  <input
23
+ use:clickOutside={() => onsave(true)}
22
24
  class="wx-text"
23
25
  oninput={updateValue}
24
26
  onkeydown={closeAndSave}
@@ -2,10 +2,16 @@ import Text from "./Text.svelte";
2
2
  import Combo from "./Combo.svelte";
3
3
  import Datepicker from "./Datepicker.svelte";
4
4
  import Richselect from "./Richselect.svelte";
5
+ import Multiselect from "./MultiSelect.svelte";
5
6
 
6
7
  export const editors = {
7
8
  text: Text,
8
9
  combo: Combo,
9
10
  datepicker: Datepicker,
10
11
  richselect: Richselect,
12
+ multiselect: Multiselect,
11
13
  };
14
+
15
+ export function registerInlineEditor(type, component) {
16
+ editors[type] = component;
17
+ }
@@ -0,0 +1,27 @@
1
+ <script>
2
+ import { DatePicker } from "@svar-ui/svelte-core";
3
+
4
+ let { filter, column, action, filterValue } = $props();
5
+
6
+ function filterRows({ value }) {
7
+ action({ value, key: column.id });
8
+ }
9
+ </script>
10
+
11
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
12
+ <div style="width:100%;">
13
+ <DatePicker
14
+ placeholder={""}
15
+ clear={true}
16
+ {...filter.config ?? {}}
17
+ value={filterValue}
18
+ onchange={filterRows}
19
+ />
20
+ </div>
21
+
22
+ <style>
23
+ :global(.wx-cell.wx-filter div.wx-datepicker input) {
24
+ height: 28px;
25
+ padding: 4px 8px;
26
+ }
27
+ </style>
@@ -1,7 +1,9 @@
1
1
  import Text from "./Text.svelte";
2
2
  import Richselect from "./Richselect.svelte";
3
+ import DatePicker from "./DatePicker.svelte";
3
4
 
4
5
  export const filters = {
5
6
  text: Text,
6
7
  richselect: Richselect,
8
+ datepicker: DatePicker,
7
9
  };
@@ -15,7 +15,7 @@
15
15
  {#each columns as row, i}
16
16
  <tr>
17
17
  {#each row as cell (cell.id)}
18
- {@const column = _columns.find(c => c.id == cell.id)}
18
+ {@const column = _columns.find(c => c.id === cell.id)}
19
19
  <th
20
20
  style={getPrintCellStyle(cell, sizes.columnWidth)}
21
21
  class="wx-print-cell-{type} {getColumnCss(column)}"
@@ -1,12 +1,8 @@
1
- import { locate, id } from "@svar-ui/lib-dom";
1
+ import { locate, getID } from "@svar-ui/lib-dom";
2
2
 
3
3
  const SHIFT = 5;
4
4
  const LONG_TOUCH_DELAY = 700;
5
5
 
6
- function getID(node) {
7
- return id(node.getAttribute("data-id"));
8
- }
9
-
10
6
  export function getOffset(node) {
11
7
  const box = node.getBoundingClientRect();
12
8
  const body = document.body;
package/src/index.js CHANGED
@@ -18,6 +18,8 @@ import { setEnv } from "@svar-ui/lib-dom";
18
18
  import { env } from "@svar-ui/lib-svelte";
19
19
  setEnv(env);
20
20
 
21
+ export { registerInlineEditor } from "./components/inlineEditors/editors";
22
+
21
23
  export {
22
24
  Grid,
23
25
  HeaderMenu,
package/types/index.d.ts CHANGED
@@ -10,6 +10,7 @@ import type {
10
10
  TMethodsConfig,
11
11
  IConfig,
12
12
  TEditorType,
13
+ TEditorConfig,
13
14
  IColumnEditor,
14
15
  IHeaderCell,
15
16
  } from "@svar-ui/grid-store";
@@ -131,6 +132,20 @@ export declare const WillowDark: Component<{
131
132
  children?: () => any;
132
133
  }>;
133
134
 
135
+ export declare function registerInlineEditor(
136
+ type: string,
137
+ component: Component<{
138
+ editor: TEditorConfig;
139
+ onsave?: (ignoreFocus: boolean) => void;
140
+ oncancel?: () => void;
141
+ onapply?: (value: any) => void;
142
+ onaction?: (ev: {
143
+ action: string;
144
+ data?: { [key: string]: any };
145
+ }) => void;
146
+ }>
147
+ ): void;
148
+
134
149
  /* get component events from store actions*/
135
150
  type RemoveHyphen<S extends string> = S extends `${infer Head}-${infer Tail}`
136
151
  ? `${Head}${RemoveHyphen<Tail>}`
package/whatsnew.md CHANGED
@@ -1,3 +1,26 @@
1
+ ## 2.6.0
2
+
3
+ ### New features
4
+
5
+ - Multiselect inline editor
6
+ - Ability to register custom inline editors
7
+
8
+ ### Updates
9
+
10
+ - Integration with FilterQuery
11
+
12
+ ### Fixes
13
+
14
+ - Dropdown editors are cut off in small tables
15
+ - DataGrid fails to initialize in SvelteKit with serverside rendering
16
+
17
+ ## 2.5.1
18
+
19
+ ### Fixes
20
+
21
+ - Items with string ids fail in some operations
22
+ - Multiple sorting and selection does not work on MacOs
23
+
1
24
  ## 2.5.0
2
25
 
3
26
  ### New features
@@ -1,56 +0,0 @@
1
- <script>
2
- import {
3
- Field,
4
- Text,
5
- RichSelect,
6
- MultiCombo,
7
- DatePicker,
8
- Area,
9
- Checkbox,
10
- Switch,
11
- } from "@svar-ui/svelte-core";
12
-
13
- let { editors, data = null } = $props();
14
- </script>
15
-
16
- {#if data}
17
- {#each editors as editor}
18
- {#if editor.type === "combo"}
19
- <Field label={editor.label}>
20
- <RichSelect
21
- options={editor.options || []}
22
- bind:value={$data[editor.id]}
23
- />
24
- </Field>
25
- {:else if editor.type === "multicombo"}
26
- <Field label={editor.label}>
27
- <MultiCombo
28
- textField="name"
29
- checkboxes={false}
30
- options={editor.options || []}
31
- bind:value={$data[editor.id]}
32
- />
33
- </Field>
34
- {:else if editor.type === "datepicker"}
35
- <Field label={editor.label}>
36
- <DatePicker bind:value={$data[editor.id]} />
37
- </Field>
38
- {:else if editor.type === "textarea"}
39
- <Field label={editor.label}>
40
- <Area bind:value={$data[editor.id]} />
41
- </Field>
42
- {:else if editor.type === "switch"}
43
- <Field label={editor.label}>
44
- <Switch bind:value={$data[editor.id]} />
45
- </Field>
46
- {:else if editor.type === "checkbox"}
47
- <Field label={editor.label}>
48
- <Checkbox bind:value={$data[editor.id]} />
49
- </Field>
50
- {:else}
51
- <Field label={editor.label}>
52
- <Text bind:value={$data[editor.id]} />
53
- </Field>
54
- {/if}
55
- {/each}
56
- {/if}