@nova-design-system/nova-vue 3.23.0 → 3.24.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/README.md CHANGED
@@ -26,9 +26,15 @@ yarn add @nova-design-system/nova-webcomponents @nova-design-system/nova-base @n
26
26
  ```
27
27
 
28
28
  > In some case, you might experience SSL certificate issues when working on Developers' VM. As documented in the [Developers' setup guide](https://wiki.eliagroup.eu/spaces/EAing/pages/89296007/2.3.3.10+Developer+Setup#id-2.3.3.10DeveloperSetup-NPMconfig), you need to turn off the SSL certificate verification:
29
- >
29
+
30
+ ```bash
31
+ npm config set strict-ssl false
32
+ ```
33
+
34
+ > **Note for Yarn Users**
35
+ > Yarn **does not automatically** install peer dependencies. You must install the following peer dependency manually:
30
36
  > ```bash
31
- > npm config set strict-ssl false
37
+ > yarn add @stencil/vue-output-target
32
38
  > ```
33
39
 
34
40
  ---
@@ -18,6 +18,16 @@ export declare function createNvDatatable<T>(): import("vue").DefineComponent<im
18
18
  required: true;
19
19
  default: () => any[];
20
20
  };
21
+ /**
22
+ * Data mode - determines how sorting and pagination behave.
23
+ * - 'client': All data is loaded, sorting/pagination handled in browser
24
+ * - 'server': Data is fetched from server, sorting/pagination handled externally
25
+ * @default 'client'
26
+ */
27
+ mode: {
28
+ type: PropType<"server" | "client">;
29
+ default: string;
30
+ };
21
31
  pagination: {
22
32
  type: PropType<NvDatatablePaginationConfig>;
23
33
  default: any;
@@ -47,6 +57,16 @@ export declare function createNvDatatable<T>(): import("vue").DefineComponent<im
47
57
  required: true;
48
58
  default: () => any[];
49
59
  };
60
+ /**
61
+ * Data mode - determines how sorting and pagination behave.
62
+ * - 'client': All data is loaded, sorting/pagination handled in browser
63
+ * - 'server': Data is fetched from server, sorting/pagination handled externally
64
+ * @default 'client'
65
+ */
66
+ mode: {
67
+ type: PropType<"server" | "client">;
68
+ default: string;
69
+ };
50
70
  pagination: {
51
71
  type: PropType<NvDatatablePaginationConfig>;
52
72
  default: any;
@@ -64,6 +84,7 @@ export declare function createNvDatatable<T>(): import("vue").DefineComponent<im
64
84
  default: boolean;
65
85
  };
66
86
  }>> & Readonly<{}>, {
87
+ mode: "server" | "client";
67
88
  columns: NvDatatableColumn<T, keyof T, T[keyof T]>[];
68
89
  rows: T[];
69
90
  pagination: NvDatatablePaginationConfig;
@@ -162,6 +183,8 @@ export interface NvDatatableColumn<Row, K extends keyof Row = keyof Row, F = Row
162
183
  valueFormatter?: (params: NvTableValueFormatterParams<Row, Row[K], K>) => F;
163
184
  /** Custom cell renderer */
164
185
  renderCell?: (params: NvTableRenderCellParams<Row, F, K>) => VNode | string | number;
186
+ /** Custom header renderer */
187
+ renderHeader?: (params: NvTableRenderHeaderParams<K>) => VNode | string | number;
165
188
  /** Enable/disable sorting for this column */
166
189
  sortable?: boolean;
167
190
  /** Custom sorting function or built-in function name */
@@ -173,6 +196,15 @@ export interface NvDatatableColumn<Row, K extends keyof Row = keyof Row, F = Row
173
196
  /** Where to place undefined values in sort */
174
197
  sortUndefined?: 'first' | 'last' | false | -1 | 1;
175
198
  }
199
+ /**
200
+ * Parameters for custom header rendering function.
201
+ */
202
+ export interface NvTableRenderHeaderParams<Field> {
203
+ /** Display name for the column header */
204
+ headerName: string;
205
+ /** Field name */
206
+ field: Field;
207
+ }
176
208
  /**
177
209
  * Parameters for custom cell rendering function.
178
210
  */
@@ -199,11 +231,16 @@ export interface NvTableValueFormatterParams<Row, Value, Field> {
199
231
  }
200
232
  /**
201
233
  * Pagination configuration for NvDatatable.
202
- * Supports three modes: client-side, server-side with buttons, and infinite scroll.
234
+ * The pagination behavior (client vs server) is determined by the top-level `mode` prop.
235
+ * Use `infinite: true` for infinite scroll (requires top-level `mode="server"`).
203
236
  */
204
237
  export interface NvDatatablePaginationConfig {
205
- /** Pagination mode */
206
- mode: 'client' | 'server' | 'infinite';
238
+ /**
239
+ * Enable infinite scroll pagination.
240
+ * When true, data loads continuously as user scrolls.
241
+ * Requires top-level `mode="server"` on the datatable.
242
+ */
243
+ infinite?: boolean;
207
244
  /** Initial page size (default: 10) */
208
245
  initialPageSize?: number;
209
246
  /** Available page size options (default: [10, 20, 50, 100]) */
@@ -263,11 +300,9 @@ export interface NvDatatableRenderPaginationAPI {
263
300
  }
264
301
  /**
265
302
  * Sorting configuration for NvDatatable.
266
- * Supports both client-side and server-side sorting.
303
+ * The sorting behavior (client vs server) is determined by the top-level `mode` prop.
267
304
  */
268
305
  export interface NvDatatableSortingConfig {
269
- /** Sorting mode */
270
- mode: 'client' | 'server';
271
306
  /** Enable multi-column sorting with Shift+Click */
272
307
  enableMultiSort?: boolean;
273
308
  /** Allow cycling through to "no sort" state */
@@ -23,6 +23,16 @@ export function createNvDatatable() {
23
23
  required: true,
24
24
  default: () => [],
25
25
  },
26
+ /**
27
+ * Data mode - determines how sorting and pagination behave.
28
+ * - 'client': All data is loaded, sorting/pagination handled in browser
29
+ * - 'server': Data is fetched from server, sorting/pagination handled externally
30
+ * @default 'client'
31
+ */
32
+ mode: {
33
+ type: String,
34
+ default: 'client',
35
+ },
26
36
  pagination: {
27
37
  type: Object,
28
38
  default: undefined,
@@ -53,6 +63,7 @@ export function createNvDatatable() {
53
63
  const tableColumns = computed(() => props.columns
54
64
  .filter((col) => !col.hidden)
55
65
  .map((col) => {
66
+ const headerName = col.headerName || String(col.field);
56
67
  const columnDef = {
57
68
  accessorKey: col.field,
58
69
  accessorFn: col.valueFormatter
@@ -65,7 +76,12 @@ export function createNvDatatable() {
65
76
  });
66
77
  }
67
78
  : undefined,
68
- header: col.headerName || String(col.field),
79
+ header: col.renderHeader
80
+ ? () => col.renderHeader({
81
+ headerName,
82
+ field: col.field,
83
+ })
84
+ : headerName,
69
85
  size: col.width,
70
86
  enableResizing: col.resizable ?? true,
71
87
  // Sorting configuration
@@ -114,6 +130,8 @@ export function createNvDatatable() {
114
130
  }));
115
131
  // Determine base table configuration with sorting
116
132
  const getBaseTableConfig = () => {
133
+ // Sorting mode is derived from top-level mode prop
134
+ const isServerMode = props.mode === 'server';
117
135
  const baseConfig = {
118
136
  get data() {
119
137
  return props.rows;
@@ -126,13 +144,13 @@ export function createNvDatatable() {
126
144
  ...(props.sorting && {
127
145
  get state() {
128
146
  return {
129
- sorting: props.sorting.mode === 'server' && props.sorting.sortState
147
+ sorting: isServerMode && props.sorting.sortState
130
148
  ? props.sorting.sortState
131
149
  : sortingState.value,
132
150
  };
133
151
  },
134
152
  onSortingChange: (updaterOrValue) => {
135
- const currentSort = props.sorting.mode === 'server' && props.sorting.sortState
153
+ const currentSort = isServerMode && props.sorting.sortState
136
154
  ? props.sorting.sortState
137
155
  : sortingState.value;
138
156
  const newSort = typeof updaterOrValue === 'function'
@@ -141,12 +159,11 @@ export function createNvDatatable() {
141
159
  // Always update internal state for reactivity
142
160
  sortingState.value = newSort;
143
161
  // For server-side sorting, also call the callback
144
- if (props.sorting?.mode === 'server' &&
145
- props.sorting.onSortingChange) {
162
+ if (isServerMode && props.sorting?.onSortingChange) {
146
163
  props.sorting.onSortingChange(newSort);
147
164
  }
148
165
  },
149
- manualSorting: props.sorting.mode === 'server',
166
+ manualSorting: isServerMode,
150
167
  enableSorting: true,
151
168
  enableMultiSort: props.sorting.enableMultiSort ?? false,
152
169
  enableSortingRemoval: props.sorting.enableSortingRemoval ?? true,
@@ -156,19 +173,28 @@ export function createNvDatatable() {
156
173
  isMultiSortEvent: props.sorting.enableMultiSort
157
174
  ? () => true
158
175
  : undefined,
159
- getSortedRowModel: props.sorting.mode === 'client' ? getSortedRowModel() : undefined,
176
+ getSortedRowModel: !isServerMode ? getSortedRowModel() : undefined,
160
177
  }),
161
178
  };
162
179
  return baseConfig;
163
180
  };
181
+ // Validation: warn if infinite scroll is used without server mode
182
+ watchEffect(() => {
183
+ if (props.pagination?.infinite && props.mode !== 'server') {
184
+ console.warn('[NvDatatable] pagination.infinite requires mode="server". ' +
185
+ 'Set mode="server" on the datatable component.');
186
+ }
187
+ });
164
188
  // Create reactive table instance based on pagination mode
165
189
  const table = computed(() => {
166
190
  const baseConfig = getBaseTableConfig();
167
- if (!props.pagination || props.pagination.mode === 'infinite') {
191
+ const isServerMode = props.mode === 'server';
192
+ const isInfiniteScroll = props.pagination?.infinite === true;
193
+ if (!props.pagination || isInfiniteScroll) {
168
194
  // No pagination or infinite scroll - simple config
169
195
  return useVueTable(baseConfig);
170
196
  }
171
- else if (props.pagination.mode === 'client') {
197
+ else if (!isServerMode) {
172
198
  // Client-side pagination - table manages its own state
173
199
  return useVueTable({
174
200
  ...baseConfig,
@@ -187,7 +213,7 @@ export function createNvDatatable() {
187
213
  ...baseConfig,
188
214
  manualPagination: true,
189
215
  get pageCount() {
190
- if (!props.pagination || props.pagination.mode !== 'server') {
216
+ if (!props.pagination) {
191
217
  return -1;
192
218
  }
193
219
  const pageSize = paginationState.value.pageSize;
@@ -221,8 +247,11 @@ export function createNvDatatable() {
221
247
  });
222
248
  // Handle pagination changes for server mode
223
249
  watch(paginationState, (newState) => {
224
- if (props.pagination?.mode === 'server' &&
225
- props.pagination.onPaginationChange) {
250
+ const isServerMode = props.mode === 'server';
251
+ const isInfiniteScroll = props.pagination?.infinite === true;
252
+ if (isServerMode &&
253
+ !isInfiniteScroll &&
254
+ props.pagination?.onPaginationChange) {
226
255
  props.pagination.onPaginationChange({
227
256
  pageIndex: newState.pageIndex,
228
257
  pageSize: newState.pageSize,
@@ -238,14 +267,15 @@ export function createNvDatatable() {
238
267
  observer = null;
239
268
  }
240
269
  // Only set up observer for infinite scroll mode
241
- if (props.pagination?.mode !== 'infinite' || !lastRowRef.value) {
270
+ const isInfiniteScroll = props.pagination?.infinite === true;
271
+ if (!isInfiniteScroll || !lastRowRef.value) {
242
272
  return;
243
273
  }
244
274
  const threshold = props.pagination.loadMoreThreshold || 500;
245
275
  observer = new IntersectionObserver((entries) => {
246
276
  const entry = entries[0];
247
277
  if (entry.isIntersecting &&
248
- props.pagination?.mode === 'infinite' &&
278
+ props.pagination?.infinite &&
249
279
  props.pagination.hasMore &&
250
280
  !props.pagination.isLoading &&
251
281
  props.pagination.onLoadMore) {
@@ -274,9 +304,11 @@ export function createNvDatatable() {
274
304
  if (!props.pagination) {
275
305
  return null;
276
306
  }
307
+ const isServerMode = props.mode === 'server';
308
+ const isInfiniteScroll = props.pagination.infinite === true;
277
309
  const tablePaginationState = table.value.getState().pagination;
278
310
  const pageCount = table.value.getPageCount();
279
- const rowCount = props.pagination.mode === 'server'
311
+ const rowCount = isServerMode && !isInfiniteScroll
280
312
  ? props.pagination.totalRowCount || props.rows.length
281
313
  : props.rows.length;
282
314
  return {
@@ -292,17 +324,15 @@ export function createNvDatatable() {
292
324
  setPageSize: (size) => table.value.setPageSize(size),
293
325
  canPreviousPage: table.value.getCanPreviousPage(),
294
326
  canNextPage: table.value.getCanNextPage(),
295
- isLoading: props.pagination.mode === 'infinite'
327
+ isLoading: isInfiniteScroll
296
328
  ? props.pagination.isLoading
297
329
  : undefined,
298
- hasMore: props.pagination.mode === 'infinite'
299
- ? props.pagination.hasMore
300
- : undefined,
330
+ hasMore: isInfiniteScroll ? props.pagination.hasMore : undefined,
301
331
  };
302
332
  });
303
333
  return () => {
304
334
  const tableRows = table.value.getRowModel().rows;
305
- const isInfiniteScroll = props.pagination?.mode === 'infinite';
335
+ const isInfiniteScroll = props.pagination?.infinite === true;
306
336
  const tableElement = h(NvTable, attrs, {
307
337
  default: () => [
308
338
  h('table', {}, [
@@ -16,6 +16,9 @@ export declare const NvDatagridcolumn: StencilVueComponent<JSX.NvDatagridcolumn>
16
16
  export declare const NvDialog: StencilVueComponent<JSX.NvDialog, JSX.NvDialog["open"]>;
17
17
  export declare const NvDialogfooter: StencilVueComponent<JSX.NvDialogfooter>;
18
18
  export declare const NvDialogheader: StencilVueComponent<JSX.NvDialogheader>;
19
+ export declare const NvDrawer: StencilVueComponent<JSX.NvDrawer, JSX.NvDrawer["open"]>;
20
+ export declare const NvDrawerfooter: StencilVueComponent<JSX.NvDrawerfooter>;
21
+ export declare const NvDrawerheader: StencilVueComponent<JSX.NvDrawerheader>;
19
22
  export declare const NvFieldcheckbox: StencilVueComponent<JSX.NvFieldcheckbox, JSX.NvFieldcheckbox["checked"]>;
20
23
  export declare const NvFielddate: StencilVueComponent<JSX.NvFielddate, JSX.NvFielddate["value"]>;
21
24
  export declare const NvFielddaterange: StencilVueComponent<JSX.NvFielddaterange, JSX.NvFielddaterange["value"]>;
@@ -188,6 +188,40 @@ export const NvDialogheader = /*@__PURE__*/ defineContainer('nv-dialogheader', u
188
188
  'heading',
189
189
  'subheading'
190
190
  ]);
191
+ export const NvDrawer = /*@__PURE__*/ defineContainer('nv-drawer', undefined, [
192
+ 'open',
193
+ 'undismissable',
194
+ 'clickOutside',
195
+ 'controlled',
196
+ 'side',
197
+ 'size',
198
+ 'width',
199
+ 'autofocus',
200
+ 'swipeToOpen',
201
+ 'openChanged'
202
+ ], [
203
+ 'openChanged'
204
+ ], 'open', 'openChanged', undefined);
205
+ export const NvDrawerfooter = /*@__PURE__*/ defineContainer('nv-drawerfooter', undefined, [
206
+ 'disabled',
207
+ 'undismissable',
208
+ 'leadingIcon',
209
+ 'trailingIcon',
210
+ 'danger',
211
+ 'cancelLabel',
212
+ 'primaryLabel',
213
+ 'primaryButtonType',
214
+ 'form',
215
+ 'drawerCanceled',
216
+ 'drawerPrimaryClicked'
217
+ ], [
218
+ 'drawerCanceled',
219
+ 'drawerPrimaryClicked'
220
+ ]);
221
+ export const NvDrawerheader = /*@__PURE__*/ defineContainer('nv-drawerheader', undefined, [
222
+ 'heading',
223
+ 'subheading'
224
+ ]);
191
225
  export const NvFieldcheckbox = /*@__PURE__*/ defineContainer('nv-fieldcheckbox', undefined, [
192
226
  'message',
193
227
  'validation',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nova-design-system/nova-vue",
3
- "version": "3.23.0",
3
+ "version": "3.24.0",
4
4
  "description": "Nova is a design system created by Elia Group to empower creators to efficiently build solutions that people love to use.",
5
5
  "author": "Elia Group",
6
6
  "homepage": "https://nova.eliagroup.io",
@@ -47,5 +47,8 @@
47
47
  "vue": "3.5.25",
48
48
  "nova-utils": "*",
49
49
  "nova-storybook-utils": "*"
50
+ },
51
+ "peerDependencies": {
52
+ "@stencil/vue-output-target": "0.11.8"
50
53
  }
51
54
  }