@nova-design-system/nova-vue 3.14.0 → 3.16.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/dist/components/NvDatatable.d.ts +116 -0
- package/dist/components/NvDatatable.js +110 -0
- package/dist/generated/components.d.ts +2 -2
- package/dist/generated/components.js +7 -16
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -0
- package/dist/plugin.d.ts +14 -4
- package/dist/plugin.js +7 -3
- package/dist/providers/NotificationService.d.ts +84 -0
- package/dist/providers/NotificationService.js +215 -0
- package/dist/providers/index.d.ts +2 -0
- package/dist/providers/index.js +1 -0
- package/package.json +7 -4
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { type VNode, type PropType } from 'vue';
|
|
2
|
+
/**
|
|
3
|
+
* Creates a typed NvDatatable component for a specific row type. This is the
|
|
4
|
+
* standard approach for generic components in Vue.
|
|
5
|
+
*
|
|
6
|
+
* @returns {component} A Vue component definition typed for the specified row
|
|
7
|
+
* type.
|
|
8
|
+
*/
|
|
9
|
+
export declare function createNvDatatable<T extends NvDatatableRow>(): import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
10
|
+
columns: {
|
|
11
|
+
type: PropType<NvDatatableColumn<T>[]>;
|
|
12
|
+
required: true;
|
|
13
|
+
default: () => any[];
|
|
14
|
+
};
|
|
15
|
+
rows: {
|
|
16
|
+
type: PropType<T[]>;
|
|
17
|
+
required: true;
|
|
18
|
+
default: () => any[];
|
|
19
|
+
};
|
|
20
|
+
}>, () => VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
21
|
+
[key: string]: any;
|
|
22
|
+
}>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
23
|
+
columns: {
|
|
24
|
+
type: PropType<NvDatatableColumn<T>[]>;
|
|
25
|
+
required: true;
|
|
26
|
+
default: () => any[];
|
|
27
|
+
};
|
|
28
|
+
rows: {
|
|
29
|
+
type: PropType<T[]>;
|
|
30
|
+
required: true;
|
|
31
|
+
default: () => any[];
|
|
32
|
+
};
|
|
33
|
+
}>> & Readonly<{}>, {
|
|
34
|
+
columns: NvDatatableColumn<T>[];
|
|
35
|
+
rows: T[];
|
|
36
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
37
|
+
/**
|
|
38
|
+
* Default NvDatatable component with basic row type.
|
|
39
|
+
* For typed usage, use createNvDatatable<YourRowType>().
|
|
40
|
+
*/
|
|
41
|
+
export declare const NvDatatable: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
42
|
+
columns: {
|
|
43
|
+
type: PropType<NvDatatableColumn<NvDatatableRow>[]>;
|
|
44
|
+
required: true;
|
|
45
|
+
default: () => any[];
|
|
46
|
+
};
|
|
47
|
+
rows: {
|
|
48
|
+
type: PropType<NvDatatableRow[]>;
|
|
49
|
+
required: true;
|
|
50
|
+
default: () => any[];
|
|
51
|
+
};
|
|
52
|
+
}>, () => VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
53
|
+
[key: string]: any;
|
|
54
|
+
}>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
55
|
+
columns: {
|
|
56
|
+
type: PropType<NvDatatableColumn<NvDatatableRow>[]>;
|
|
57
|
+
required: true;
|
|
58
|
+
default: () => any[];
|
|
59
|
+
};
|
|
60
|
+
rows: {
|
|
61
|
+
type: PropType<NvDatatableRow[]>;
|
|
62
|
+
required: true;
|
|
63
|
+
default: () => any[];
|
|
64
|
+
};
|
|
65
|
+
}>> & Readonly<{}>, {
|
|
66
|
+
columns: NvDatatableColumn<NvDatatableRow>[];
|
|
67
|
+
rows: NvDatatableRow[];
|
|
68
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
69
|
+
/********************************* TYPES **************************************/
|
|
70
|
+
/**
|
|
71
|
+
* Type definition for a datatable row.
|
|
72
|
+
*/
|
|
73
|
+
export type NvDatatableRow = Record<string, string | number | boolean | null | undefined | typeof Date>;
|
|
74
|
+
/**
|
|
75
|
+
* Parameters for custom cell rendering function.
|
|
76
|
+
*/
|
|
77
|
+
export interface NvTableRenderCellParams<T extends NvDatatableRow, V> {
|
|
78
|
+
/** Cell value */
|
|
79
|
+
value: V;
|
|
80
|
+
/** Row data */
|
|
81
|
+
row: T;
|
|
82
|
+
/** Field name */
|
|
83
|
+
field: keyof T;
|
|
84
|
+
/** Row index */
|
|
85
|
+
rowIndex: number;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Column definition for NvDatatable.
|
|
89
|
+
*/
|
|
90
|
+
export interface NvDatatableColumn<T extends NvDatatableRow> {
|
|
91
|
+
/** Field name from row data */
|
|
92
|
+
field: keyof T;
|
|
93
|
+
/** Display name for column header */
|
|
94
|
+
headerName?: string;
|
|
95
|
+
/** Column width in pixels */
|
|
96
|
+
width?: number;
|
|
97
|
+
/** Whether column is resizable */
|
|
98
|
+
resizable?: boolean;
|
|
99
|
+
/** Whether column is hidden */
|
|
100
|
+
hidden?: boolean;
|
|
101
|
+
/** Custom cell renderer */
|
|
102
|
+
renderCell?: (params: NvTableRenderCellParams<T, T[keyof T]>) => VNode | string | number;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Props for NvDatatable component.
|
|
106
|
+
*/
|
|
107
|
+
export interface NvDatatableProps<T extends NvDatatableRow> {
|
|
108
|
+
/** Column definitions */
|
|
109
|
+
columns: Array<NvDatatableColumn<T>>;
|
|
110
|
+
/** Row data */
|
|
111
|
+
rows: Array<T>;
|
|
112
|
+
/** CSS class */
|
|
113
|
+
class?: string;
|
|
114
|
+
/** Inline styles */
|
|
115
|
+
style?: string | Record<string, string>;
|
|
116
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/* eslint-disable jsdoc/require-jsdoc */
|
|
2
|
+
import { defineComponent, computed, h } from 'vue';
|
|
3
|
+
import { useVueTable, getCoreRowModel, } from '@tanstack/vue-table';
|
|
4
|
+
import { NvTable } from '../generated/components';
|
|
5
|
+
/**
|
|
6
|
+
* Creates a typed NvDatatable component for a specific row type. This is the
|
|
7
|
+
* standard approach for generic components in Vue.
|
|
8
|
+
*
|
|
9
|
+
* @returns {component} A Vue component definition typed for the specified row
|
|
10
|
+
* type.
|
|
11
|
+
*/
|
|
12
|
+
export function createNvDatatable() {
|
|
13
|
+
return defineComponent({
|
|
14
|
+
name: 'NvDatatable',
|
|
15
|
+
props: {
|
|
16
|
+
columns: {
|
|
17
|
+
type: Array,
|
|
18
|
+
required: true,
|
|
19
|
+
default: () => [],
|
|
20
|
+
},
|
|
21
|
+
rows: {
|
|
22
|
+
type: Array,
|
|
23
|
+
required: true,
|
|
24
|
+
default: () => [],
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
setup(props, { attrs }) {
|
|
28
|
+
const tableColumns = computed(() => props.columns
|
|
29
|
+
.filter((col) => !col.hidden)
|
|
30
|
+
.map((col) => ({
|
|
31
|
+
accessorKey: col.field,
|
|
32
|
+
header: col.headerName || String(col.field),
|
|
33
|
+
size: col.width,
|
|
34
|
+
enableResizing: col.resizable ?? true,
|
|
35
|
+
cell: (context) => {
|
|
36
|
+
const value = context.getValue();
|
|
37
|
+
const row = context.row.original;
|
|
38
|
+
const rowIndex = context.row.index;
|
|
39
|
+
// Use custom renderCell if provided
|
|
40
|
+
if (col.renderCell) {
|
|
41
|
+
return col.renderCell({
|
|
42
|
+
value,
|
|
43
|
+
row,
|
|
44
|
+
field: col.field,
|
|
45
|
+
rowIndex,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
// Default rendering
|
|
49
|
+
return value;
|
|
50
|
+
},
|
|
51
|
+
})));
|
|
52
|
+
const table = useVueTable({
|
|
53
|
+
data: computed(() => props.rows),
|
|
54
|
+
columns: tableColumns.value,
|
|
55
|
+
getCoreRowModel: getCoreRowModel(),
|
|
56
|
+
});
|
|
57
|
+
return () => {
|
|
58
|
+
return h(NvTable, attrs, {
|
|
59
|
+
default: () => [
|
|
60
|
+
h('table', {}, [
|
|
61
|
+
h('thead', {}, [
|
|
62
|
+
...table.getHeaderGroups().map((headerGroup) => h('tr', { key: headerGroup.id }, [
|
|
63
|
+
...headerGroup.headers.map((header) => h('th', {
|
|
64
|
+
key: header.id,
|
|
65
|
+
'data-testid': `datatable-header-${header.id}`,
|
|
66
|
+
style: {
|
|
67
|
+
width: header.column.columnDef.size
|
|
68
|
+
? `${header.column.columnDef.size}px`
|
|
69
|
+
: undefined,
|
|
70
|
+
},
|
|
71
|
+
'data-no-resize': header.column.columnDef
|
|
72
|
+
.enableResizing
|
|
73
|
+
? null
|
|
74
|
+
: true,
|
|
75
|
+
}, header.isPlaceholder
|
|
76
|
+
? null
|
|
77
|
+
: typeof header.column.columnDef.header === 'function'
|
|
78
|
+
? header.column.columnDef.header(header.getContext())
|
|
79
|
+
: header.column.columnDef.header)),
|
|
80
|
+
])),
|
|
81
|
+
]),
|
|
82
|
+
h('tbody', {}, [
|
|
83
|
+
...table.getRowModel().rows.map((row) => h('tr', {
|
|
84
|
+
key: row.id,
|
|
85
|
+
'data-testid': `datatable-row-${row.id}`,
|
|
86
|
+
}, [
|
|
87
|
+
...row.getVisibleCells().map((cell) => h('td', {
|
|
88
|
+
key: cell.id,
|
|
89
|
+
'data-testid': `datatable-cell-${cell.id}`,
|
|
90
|
+
style: {
|
|
91
|
+
padding: '8px',
|
|
92
|
+
borderBottom: '1px solid #eee',
|
|
93
|
+
},
|
|
94
|
+
}, typeof cell.column.columnDef.cell === 'function'
|
|
95
|
+
? cell.column.columnDef.cell(cell.getContext())
|
|
96
|
+
: cell.getValue())),
|
|
97
|
+
])),
|
|
98
|
+
]),
|
|
99
|
+
]),
|
|
100
|
+
],
|
|
101
|
+
});
|
|
102
|
+
};
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Default NvDatatable component with basic row type.
|
|
108
|
+
* For typed usage, use createNvDatatable<YourRowType>().
|
|
109
|
+
*/
|
|
110
|
+
export const NvDatatable = createNvDatatable();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { JSX } from '@nova-design-system/nova-webcomponents';
|
|
2
|
-
export declare const NvAccordion: import("vue").DefineSetupFnComponent<JSX.NvAccordion & import("./vue-component-lib/utils").InputProps<
|
|
2
|
+
export declare const NvAccordion: import("vue").DefineSetupFnComponent<JSX.NvAccordion & import("./vue-component-lib/utils").InputProps<number[]>, {}, {}, JSX.NvAccordion & import("./vue-component-lib/utils").InputProps<number[]> & {}, import("vue").PublicProps>;
|
|
3
3
|
export declare const NvAccordionItem: import("vue").DefineSetupFnComponent<JSX.NvAccordionItem & import("./vue-component-lib/utils").InputProps<string | number | boolean>, {}, {}, JSX.NvAccordionItem & import("./vue-component-lib/utils").InputProps<string | number | boolean> & {}, import("vue").PublicProps>;
|
|
4
4
|
export declare const NvAlert: import("vue").DefineSetupFnComponent<JSX.NvAlert & import("./vue-component-lib/utils").InputProps<boolean>, {}, {}, JSX.NvAlert & import("./vue-component-lib/utils").InputProps<boolean> & {}, import("vue").PublicProps>;
|
|
5
5
|
export declare const NvAvatar: import("vue").DefineSetupFnComponent<JSX.NvAvatar & import("./vue-component-lib/utils").InputProps<string | number | boolean>, {}, {}, JSX.NvAvatar & import("./vue-component-lib/utils").InputProps<string | number | boolean> & {}, import("vue").PublicProps>;
|
|
@@ -56,11 +56,11 @@ export declare const NvLoader: import("vue").DefineSetupFnComponent<JSX.NvLoader
|
|
|
56
56
|
export declare const NvMenu: import("vue").DefineSetupFnComponent<JSX.NvMenu & import("./vue-component-lib/utils").InputProps<string | number | boolean>, {}, {}, JSX.NvMenu & import("./vue-component-lib/utils").InputProps<string | number | boolean> & {}, import("vue").PublicProps>;
|
|
57
57
|
export declare const NvMenuitem: import("vue").DefineSetupFnComponent<JSX.NvMenuitem & import("./vue-component-lib/utils").InputProps<string | number | boolean>, {}, {}, JSX.NvMenuitem & import("./vue-component-lib/utils").InputProps<string | number | boolean> & {}, import("vue").PublicProps>;
|
|
58
58
|
export declare const NvNotification: import("vue").DefineSetupFnComponent<JSX.NvNotification & import("./vue-component-lib/utils").InputProps<boolean>, {}, {}, JSX.NvNotification & import("./vue-component-lib/utils").InputProps<boolean> & {}, import("vue").PublicProps>;
|
|
59
|
+
export declare const NvNotificationcontainer: import("vue").DefineSetupFnComponent<JSX.NvNotificationcontainer & import("./vue-component-lib/utils").InputProps<string | number | boolean>, {}, {}, JSX.NvNotificationcontainer & import("./vue-component-lib/utils").InputProps<string | number | boolean> & {}, import("vue").PublicProps>;
|
|
59
60
|
export declare const NvPopover: import("vue").DefineSetupFnComponent<JSX.NvPopover & import("./vue-component-lib/utils").InputProps<boolean>, {}, {}, JSX.NvPopover & import("./vue-component-lib/utils").InputProps<boolean> & {}, import("vue").PublicProps>;
|
|
60
61
|
export declare const NvRow: import("vue").DefineSetupFnComponent<JSX.NvRow & import("./vue-component-lib/utils").InputProps<string | number | boolean>, {}, {}, JSX.NvRow & import("./vue-component-lib/utils").InputProps<string | number | boolean> & {}, import("vue").PublicProps>;
|
|
61
62
|
export declare const NvStack: import("vue").DefineSetupFnComponent<JSX.NvStack & import("./vue-component-lib/utils").InputProps<string | number | boolean>, {}, {}, JSX.NvStack & import("./vue-component-lib/utils").InputProps<string | number | boolean> & {}, import("vue").PublicProps>;
|
|
62
63
|
export declare const NvTable: import("vue").DefineSetupFnComponent<JSX.NvTable & import("./vue-component-lib/utils").InputProps<string | number | boolean>, {}, {}, JSX.NvTable & import("./vue-component-lib/utils").InputProps<string | number | boolean> & {}, import("vue").PublicProps>;
|
|
63
|
-
export declare const NvTablecolumn: import("vue").DefineSetupFnComponent<JSX.NvTablecolumn & import("./vue-component-lib/utils").InputProps<string | number | boolean>, {}, {}, JSX.NvTablecolumn & import("./vue-component-lib/utils").InputProps<string | number | boolean> & {}, import("vue").PublicProps>;
|
|
64
64
|
export declare const NvToggle: import("vue").DefineSetupFnComponent<JSX.NvToggle & import("./vue-component-lib/utils").InputProps<boolean>, {}, {}, JSX.NvToggle & import("./vue-component-lib/utils").InputProps<boolean> & {}, import("vue").PublicProps>;
|
|
65
65
|
export declare const NvTogglebutton: import("vue").DefineSetupFnComponent<JSX.NvTogglebutton & import("./vue-component-lib/utils").InputProps<string | number | boolean>, {}, {}, JSX.NvTogglebutton & import("./vue-component-lib/utils").InputProps<string | number | boolean> & {}, import("vue").PublicProps>;
|
|
66
66
|
export declare const NvTogglebuttongroup: import("vue").DefineSetupFnComponent<JSX.NvTogglebuttongroup & import("./vue-component-lib/utils").InputProps<string[]>, {}, {}, JSX.NvTogglebuttongroup & import("./vue-component-lib/utils").InputProps<string[]> & {}, import("vue").PublicProps>;
|
|
@@ -6,8 +6,8 @@ export const NvAccordion = /*@__PURE__*/ defineContainer('nv-accordion', undefin
|
|
|
6
6
|
'data',
|
|
7
7
|
'mode',
|
|
8
8
|
'openIndexes',
|
|
9
|
-
'
|
|
10
|
-
]);
|
|
9
|
+
'openIndexesChanged'
|
|
10
|
+
], 'openIndexes', 'open-indexes-changed');
|
|
11
11
|
export const NvAccordionItem = /*@__PURE__*/ defineContainer('nv-accordion-item', undefined, [
|
|
12
12
|
'itemTitle',
|
|
13
13
|
'subtitle',
|
|
@@ -543,8 +543,12 @@ export const NvNotification = /*@__PURE__*/ defineContainer('nv-notification', u
|
|
|
543
543
|
'icon',
|
|
544
544
|
'dismissible',
|
|
545
545
|
'hidden',
|
|
546
|
+
'initiallyHidden',
|
|
546
547
|
'hiddenChanged'
|
|
547
548
|
], 'hidden', 'hidden-changed');
|
|
549
|
+
export const NvNotificationcontainer = /*@__PURE__*/ defineContainer('nv-notificationcontainer', undefined, [
|
|
550
|
+
'position'
|
|
551
|
+
]);
|
|
548
552
|
export const NvPopover = /*@__PURE__*/ defineContainer('nv-popover', undefined, [
|
|
549
553
|
'triggerElement',
|
|
550
554
|
'open',
|
|
@@ -568,20 +572,7 @@ export const NvStack = /*@__PURE__*/ defineContainer('nv-stack', undefined, [
|
|
|
568
572
|
'full',
|
|
569
573
|
'vertical'
|
|
570
574
|
]);
|
|
571
|
-
export const NvTable = /*@__PURE__*/ defineContainer('nv-table', undefined
|
|
572
|
-
'data',
|
|
573
|
-
'columnsConfig',
|
|
574
|
-
'dataJson',
|
|
575
|
-
'columnsConfigJson',
|
|
576
|
-
'fallbackValue',
|
|
577
|
-
'noDataMessage',
|
|
578
|
-
'noColumnsNoDataMessage',
|
|
579
|
-
'action'
|
|
580
|
-
]);
|
|
581
|
-
export const NvTablecolumn = /*@__PURE__*/ defineContainer('nv-tablecolumn', undefined, [
|
|
582
|
-
'name',
|
|
583
|
-
'header'
|
|
584
|
-
]);
|
|
575
|
+
export const NvTable = /*@__PURE__*/ defineContainer('nv-table', undefined);
|
|
585
576
|
export const NvToggle = /*@__PURE__*/ defineContainer('nv-toggle', undefined, [
|
|
586
577
|
'inputId',
|
|
587
578
|
'name',
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/dist/plugin.d.ts
CHANGED
|
@@ -8,9 +8,19 @@
|
|
|
8
8
|
* By providing custom implementations, we ensure that event names are
|
|
9
9
|
* properly transformed, allowing Stencil components to work seamlessly in Vue.
|
|
10
10
|
*/
|
|
11
|
-
import {
|
|
11
|
+
import { App } from 'vue';
|
|
12
|
+
import { type NotificationServiceOptions } from './providers/NotificationService';
|
|
12
13
|
/**
|
|
13
|
-
*
|
|
14
|
-
* handlers.
|
|
14
|
+
* Configuration options for the NovaComponents plugin.
|
|
15
15
|
*/
|
|
16
|
-
export
|
|
16
|
+
export interface NovaComponentsOptions {
|
|
17
|
+
/** Notification service configuration options. */
|
|
18
|
+
notifications?: NotificationServiceOptions;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* This is the Vue plugin that is used to define the custom elements, event
|
|
22
|
+
* handlers, and includes the notification service.
|
|
23
|
+
*/
|
|
24
|
+
export declare const NovaComponents: {
|
|
25
|
+
install(app: App, options?: NovaComponentsOptions): Promise<void>;
|
|
26
|
+
};
|
package/dist/plugin.js
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* properly transformed, allowing Stencil components to work seamlessly in Vue.
|
|
10
10
|
*/
|
|
11
11
|
import { defineCustomElements } from '@nova-design-system/nova-webcomponents/loader';
|
|
12
|
+
import { NvNotificationService, } from './providers/NotificationService';
|
|
12
13
|
/**
|
|
13
14
|
* Transforms the event name to kebab-case.
|
|
14
15
|
* @param {string} eventName - The name of the event.
|
|
@@ -39,15 +40,18 @@ const ael = (el, eventName, cb, opts) => el.addEventListener(transformEventName(
|
|
|
39
40
|
*/
|
|
40
41
|
const rel = (el, eventName, cb, opts) => el.removeEventListener(transformEventName(eventName), cb, opts);
|
|
41
42
|
/**
|
|
42
|
-
* This is the Vue plugin that is used to define the custom elements
|
|
43
|
-
* handlers.
|
|
43
|
+
* This is the Vue plugin that is used to define the custom elements, event
|
|
44
|
+
* handlers, and includes the notification service.
|
|
44
45
|
*/
|
|
45
46
|
export const NovaComponents = {
|
|
46
|
-
async install() {
|
|
47
|
+
async install(app, options = {}) {
|
|
48
|
+
// Define custom elements with event handling
|
|
47
49
|
defineCustomElements(window, {
|
|
48
50
|
ce: (eventName, opts) => new CustomEvent(transformEventName(eventName), opts),
|
|
49
51
|
ael,
|
|
50
52
|
rel,
|
|
51
53
|
});
|
|
54
|
+
// Install notification service
|
|
55
|
+
NvNotificationService.install(app, options.notifications);
|
|
52
56
|
},
|
|
53
57
|
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { App, type Ref, type Component } from 'vue';
|
|
2
|
+
import { NotificationEmphasis, FeedbackColors, NotificationPosition } from '../index';
|
|
3
|
+
/**
|
|
4
|
+
* Action callbacks for notifications. Will render buttons automatically.
|
|
5
|
+
*/
|
|
6
|
+
export interface NotificationAction {
|
|
7
|
+
/** The label of the action. */
|
|
8
|
+
label: string;
|
|
9
|
+
/** The callback to execute when the action is clicked. */
|
|
10
|
+
onClick: () => void;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Options for creating a notification.
|
|
14
|
+
*/
|
|
15
|
+
export interface NotificationOptions {
|
|
16
|
+
/** Unique identifier for the notification. If not provided, one will be generated. */
|
|
17
|
+
id?: string;
|
|
18
|
+
/** Short and concise text for the notification heading. */
|
|
19
|
+
heading?: string;
|
|
20
|
+
/** Main content of the notification. */
|
|
21
|
+
message?: string;
|
|
22
|
+
/** Whether the notification can be manually dismissed via close button. */
|
|
23
|
+
dismissible?: boolean;
|
|
24
|
+
/** Adjusts the emphasis to make the notification more or less visually
|
|
25
|
+
* prominent to users. Use this to draw attention to important actions or
|
|
26
|
+
* reduce focus on less critical ones */
|
|
27
|
+
emphasis?: `${NotificationEmphasis}`;
|
|
28
|
+
/** Type of the notification, used to determine the color and default icon. */
|
|
29
|
+
feedback?: `${FeedbackColors}`;
|
|
30
|
+
/** Custom icon name to override the default icon. */
|
|
31
|
+
icon?: string;
|
|
32
|
+
/** Notification actions */
|
|
33
|
+
actions?: NotificationAction[];
|
|
34
|
+
/** Custom components for the notification actions. */
|
|
35
|
+
actionSlot?: Component;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* A notification with all required fields populated.
|
|
39
|
+
*/
|
|
40
|
+
export interface Notification extends NotificationOptions {
|
|
41
|
+
/** Timestamp when the notification was created. */
|
|
42
|
+
createdAt: number;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Context value provided by the NotificationService.
|
|
46
|
+
*/
|
|
47
|
+
export interface NotificationContextValue {
|
|
48
|
+
/** Reactive array of active notifications. */
|
|
49
|
+
notifications: Ref<Notification[]>;
|
|
50
|
+
/** Function to show a new notification. Returns the notification ID. */
|
|
51
|
+
show: (options: NotificationOptions) => string;
|
|
52
|
+
/** Function to dismiss a specific notification by ID. This will remove the
|
|
53
|
+
* notification after the animation completes */
|
|
54
|
+
dismiss: (id: string) => void;
|
|
55
|
+
/** Function to immediately remove a specific notification by ID. */
|
|
56
|
+
remove: (id: string) => void;
|
|
57
|
+
/** Function to remove all active notifications immediately. */
|
|
58
|
+
removeAll: () => void;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Configuration options for the NotificationService plugin.
|
|
62
|
+
*/
|
|
63
|
+
export interface NotificationServiceOptions {
|
|
64
|
+
/** Position of the notification container on the screen. */
|
|
65
|
+
position?: `${NotificationPosition}`;
|
|
66
|
+
/** Maximum number of notifications to display at once. */
|
|
67
|
+
maxNotifications?: number;
|
|
68
|
+
/** Additional CSS class name for the notification container. */
|
|
69
|
+
className?: string;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Vue plugin for Nova notifications.
|
|
73
|
+
*/
|
|
74
|
+
export declare const NvNotificationService: {
|
|
75
|
+
install(app: App, options?: NotificationServiceOptions): void;
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* Composable to use notifications in any component.
|
|
79
|
+
*
|
|
80
|
+
* @returns {NotificationContextValue} The notification context
|
|
81
|
+
* @throws {Error} If used outside of an app with NvNotificationService installed
|
|
82
|
+
*/
|
|
83
|
+
export declare const useNotifications: () => NotificationContextValue;
|
|
84
|
+
export default NvNotificationService;
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/* eslint-disable jsdoc/require-jsdoc */
|
|
2
|
+
import { ref, createApp, h, } from 'vue';
|
|
3
|
+
import { NvButton, NvNotification, NvNotificationcontainer, } from '../generated/components';
|
|
4
|
+
/**
|
|
5
|
+
* Utility function to generate unique IDs.
|
|
6
|
+
*
|
|
7
|
+
* @returns {string} A unique identifier string
|
|
8
|
+
*/
|
|
9
|
+
const generateId = () => {
|
|
10
|
+
return `notification-${Date.now()}-${Math.random()
|
|
11
|
+
.toString(36)
|
|
12
|
+
.substr(2, 9)}`;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Utility function to unwrap a notification element from a ref.
|
|
16
|
+
* @param {NvNotificationRef} el The notification element ref
|
|
17
|
+
* @returns {HTMLNvNotificationElement | null} The notification element
|
|
18
|
+
*/
|
|
19
|
+
const unwrapNotificationEl = (el) => {
|
|
20
|
+
if (!el)
|
|
21
|
+
return null;
|
|
22
|
+
return '$el' in el ? el.$el : el;
|
|
23
|
+
};
|
|
24
|
+
class NotificationManager {
|
|
25
|
+
notifications = ref([]);
|
|
26
|
+
options;
|
|
27
|
+
containerApp = null;
|
|
28
|
+
constructor(options = {}) {
|
|
29
|
+
this.options = {
|
|
30
|
+
position: options.position || 'top-right',
|
|
31
|
+
maxNotifications: options.maxNotifications || 50,
|
|
32
|
+
className: options.className || '',
|
|
33
|
+
};
|
|
34
|
+
this.createContainer();
|
|
35
|
+
}
|
|
36
|
+
// keep track of all notification refs by id
|
|
37
|
+
elRefs = new Map();
|
|
38
|
+
// small helper to bind/unbind refs per id
|
|
39
|
+
setElRef = (id) => (el) => {
|
|
40
|
+
if (el)
|
|
41
|
+
this.elRefs.set(id, el);
|
|
42
|
+
else
|
|
43
|
+
this.elRefs.delete(id);
|
|
44
|
+
};
|
|
45
|
+
createContainer() {
|
|
46
|
+
// Create container element
|
|
47
|
+
const containerEl = document.createElement('div');
|
|
48
|
+
containerEl.id = 'nova-notification-container';
|
|
49
|
+
document.body.appendChild(containerEl);
|
|
50
|
+
// Create Vue app for the container
|
|
51
|
+
this.containerApp = createApp({
|
|
52
|
+
setup: () => {
|
|
53
|
+
return () => {
|
|
54
|
+
const items = this.notifications.value.map((notification) => {
|
|
55
|
+
const hasCustomActions = (notification.actions && notification.actions.length > 0) ||
|
|
56
|
+
!!notification.actionSlot;
|
|
57
|
+
const actionChildren = [];
|
|
58
|
+
notification.actions?.forEach((action) => {
|
|
59
|
+
actionChildren.push(h(NvButton, { onClick: action.onClick, emphasis: 'low', size: 'sm' }, { default: () => action.label }));
|
|
60
|
+
});
|
|
61
|
+
if (notification.actionSlot) {
|
|
62
|
+
actionChildren.push(h(notification.actionSlot));
|
|
63
|
+
}
|
|
64
|
+
const actionContainer = hasCustomActions
|
|
65
|
+
? h('div', { slot: 'actions' }, actionChildren)
|
|
66
|
+
: null;
|
|
67
|
+
return h(NvNotification, {
|
|
68
|
+
key: notification.id,
|
|
69
|
+
ref: this.setElRef(notification.id),
|
|
70
|
+
heading: notification.heading,
|
|
71
|
+
message: notification.message,
|
|
72
|
+
dismissible: notification.dismissible,
|
|
73
|
+
emphasis: notification.emphasis,
|
|
74
|
+
feedback: notification.feedback,
|
|
75
|
+
icon: notification.icon,
|
|
76
|
+
initiallyHidden: true,
|
|
77
|
+
onHiddenChanged: (event) => {
|
|
78
|
+
if (event.detail)
|
|
79
|
+
this.handleNotificationClose(notification.id);
|
|
80
|
+
},
|
|
81
|
+
}, {
|
|
82
|
+
default: () => (actionContainer ? [actionContainer] : null),
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
return h(NvNotificationcontainer, {
|
|
86
|
+
position: this.options.position,
|
|
87
|
+
class: this.options.className,
|
|
88
|
+
'data-testid': 'notification-container',
|
|
89
|
+
}, {
|
|
90
|
+
// ✅ function slot avoids the warning
|
|
91
|
+
default: () => items,
|
|
92
|
+
});
|
|
93
|
+
};
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
this.containerApp.mount(containerEl);
|
|
97
|
+
}
|
|
98
|
+
handleNotificationClose(id) {
|
|
99
|
+
this.remove(id);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Show a new notification.
|
|
103
|
+
*
|
|
104
|
+
* @param {NotificationOptions} options - The notification options
|
|
105
|
+
* @returns {string} The notification ID
|
|
106
|
+
*/
|
|
107
|
+
show = (options) => {
|
|
108
|
+
const id = options.id || generateId();
|
|
109
|
+
const notification = {
|
|
110
|
+
id,
|
|
111
|
+
heading: options.heading,
|
|
112
|
+
message: options.message,
|
|
113
|
+
dismissible: options.dismissible ?? true,
|
|
114
|
+
emphasis: options.emphasis ?? 'medium',
|
|
115
|
+
feedback: options.feedback ?? 'information',
|
|
116
|
+
actions: options.actions ?? [],
|
|
117
|
+
actionSlot: options.actionSlot,
|
|
118
|
+
icon: options.icon,
|
|
119
|
+
createdAt: Date.now(),
|
|
120
|
+
};
|
|
121
|
+
// Remove oldest notifications if we exceed max
|
|
122
|
+
const newNotifications = [notification, ...this.notifications.value];
|
|
123
|
+
if (newNotifications.length > this.options.maxNotifications) {
|
|
124
|
+
this.notifications.value = newNotifications.slice(0, this.options.maxNotifications);
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
this.notifications.value = newNotifications;
|
|
128
|
+
}
|
|
129
|
+
setTimeout(() => {
|
|
130
|
+
const ref = this.elRefs.get(id);
|
|
131
|
+
const el = unwrapNotificationEl(ref);
|
|
132
|
+
el?.show();
|
|
133
|
+
}, 0);
|
|
134
|
+
return id;
|
|
135
|
+
};
|
|
136
|
+
/**
|
|
137
|
+
* Dismiss a specific notification by ID. This will remove the notification
|
|
138
|
+
* after the animation completes.
|
|
139
|
+
*
|
|
140
|
+
* @param {string} id - The notification ID to dismiss
|
|
141
|
+
*/
|
|
142
|
+
dismiss = (id) => {
|
|
143
|
+
const ref = this.elRefs.get(id);
|
|
144
|
+
const el = unwrapNotificationEl(ref);
|
|
145
|
+
el?.dismiss();
|
|
146
|
+
};
|
|
147
|
+
/**
|
|
148
|
+
* Immediately remove a specific notification by ID.
|
|
149
|
+
*
|
|
150
|
+
* @param {string} id - The notification ID to dismiss
|
|
151
|
+
*/
|
|
152
|
+
remove = (id) => {
|
|
153
|
+
this.notifications.value = this.notifications.value.filter((notification) => notification.id !== id);
|
|
154
|
+
this.elRefs.delete(id);
|
|
155
|
+
};
|
|
156
|
+
/**
|
|
157
|
+
* Clear all active notifications.
|
|
158
|
+
*/
|
|
159
|
+
removeAll = () => {
|
|
160
|
+
this.notifications.value = [];
|
|
161
|
+
};
|
|
162
|
+
/**
|
|
163
|
+
* Get the current context value.
|
|
164
|
+
*
|
|
165
|
+
* @returns {NotificationContextValue} The context value
|
|
166
|
+
*/
|
|
167
|
+
getContextValue = () => ({
|
|
168
|
+
notifications: this.notifications,
|
|
169
|
+
show: this.show,
|
|
170
|
+
remove: this.remove,
|
|
171
|
+
dismiss: this.dismiss,
|
|
172
|
+
removeAll: this.removeAll,
|
|
173
|
+
});
|
|
174
|
+
/**
|
|
175
|
+
* Destroy the notification manager and clean up resources.
|
|
176
|
+
*/
|
|
177
|
+
destroy() {
|
|
178
|
+
if (this.containerApp) {
|
|
179
|
+
this.containerApp.unmount();
|
|
180
|
+
this.containerApp = null;
|
|
181
|
+
}
|
|
182
|
+
const containerEl = document.getElementById('nova-notification-container');
|
|
183
|
+
if (containerEl) {
|
|
184
|
+
document.body.removeChild(containerEl);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
// Global notification manager instance
|
|
189
|
+
let notificationManager = null;
|
|
190
|
+
/**
|
|
191
|
+
* Vue plugin for Nova notifications.
|
|
192
|
+
*/
|
|
193
|
+
export const NvNotificationService = {
|
|
194
|
+
install(app, options = {}) {
|
|
195
|
+
notificationManager = new NotificationManager(options);
|
|
196
|
+
// Provide global property
|
|
197
|
+
app.config.globalProperties.$notifications =
|
|
198
|
+
notificationManager.getContextValue();
|
|
199
|
+
// Provide for composition API
|
|
200
|
+
app.provide('notifications', notificationManager.getContextValue());
|
|
201
|
+
},
|
|
202
|
+
};
|
|
203
|
+
/**
|
|
204
|
+
* Composable to use notifications in any component.
|
|
205
|
+
*
|
|
206
|
+
* @returns {NotificationContextValue} The notification context
|
|
207
|
+
* @throws {Error} If used outside of an app with NvNotificationService installed
|
|
208
|
+
*/
|
|
209
|
+
export const useNotifications = () => {
|
|
210
|
+
if (!notificationManager) {
|
|
211
|
+
throw new Error('useNotifications must be used in an app with NovaComponents installed. Use app.use(NovaComponents) in your main.ts');
|
|
212
|
+
}
|
|
213
|
+
return notificationManager.getContextValue();
|
|
214
|
+
};
|
|
215
|
+
export default NvNotificationService;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { NvNotificationService, useNotifications, default as NotificationService, } from './NotificationService';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nova-design-system/nova-vue",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.16.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",
|
|
@@ -31,17 +31,20 @@
|
|
|
31
31
|
},
|
|
32
32
|
"scripts": {
|
|
33
33
|
"build": "npm run tsc",
|
|
34
|
+
"build:watch": "npm run tsc:watch",
|
|
34
35
|
"tsc": "tsc -p . --outDir ./dist",
|
|
36
|
+
"tsc:watch": "tsc -p . --outDir ./dist --watch",
|
|
35
37
|
"storybook": "storybook dev -p 6008",
|
|
36
38
|
"storybook.build": "storybook build -o ../../storybook-static/vue",
|
|
37
|
-
"clean": "rimraf dist lib/generated",
|
|
39
|
+
"clean": "rimraf dist lib/generated lib/stories/generated",
|
|
38
40
|
"typecheck": "tsc --emitDeclarationOnly false --noEmit"
|
|
39
41
|
},
|
|
40
42
|
"dependencies": {
|
|
41
|
-
"@nova-design-system/nova-webcomponents": "*"
|
|
43
|
+
"@nova-design-system/nova-webcomponents": "*",
|
|
44
|
+
"@tanstack/vue-table": "8.21.3"
|
|
42
45
|
},
|
|
43
46
|
"devDependencies": {
|
|
44
|
-
"vue": "3.
|
|
47
|
+
"vue": "3.5.17",
|
|
45
48
|
"nova-utils": "*",
|
|
46
49
|
"nova-storybook-utils": "*"
|
|
47
50
|
}
|