@v-c/notification 0.0.2
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/LICENSE +21 -0
- package/bump.config.ts +6 -0
- package/dist/Notice.cjs +230 -0
- package/dist/Notice.d.ts +15 -0
- package/dist/Notice.js +225 -0
- package/dist/NoticeList.cjs +157 -0
- package/dist/NoticeList.d.ts +13 -0
- package/dist/NoticeList.js +154 -0
- package/dist/NotificationProvider.cjs +13 -0
- package/dist/NotificationProvider.d.ts +10 -0
- package/dist/NotificationProvider.js +10 -0
- package/dist/Notifications.cjs +146 -0
- package/dist/Notifications.d.ts +24 -0
- package/dist/Notifications.js +143 -0
- package/dist/_virtual/rolldown_runtime.cjs +21 -0
- package/dist/hooks/useNotification.cjs +80 -0
- package/dist/hooks/useNotification.d.ts +36 -0
- package/dist/hooks/useNotification.js +78 -0
- package/dist/hooks/useStack.cjs +24 -0
- package/dist/hooks/useStack.d.ts +6 -0
- package/dist/hooks/useStack.js +22 -0
- package/dist/index.cjs +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +4 -0
- package/dist/interface.cjs +0 -0
- package/dist/interface.d.ts +55 -0
- package/dist/interface.js +0 -0
- package/docs/context.vue +34 -0
- package/docs/hooks.vue +89 -0
- package/docs/index.less +265 -0
- package/docs/maxCount.vue +24 -0
- package/docs/motion.ts +33 -0
- package/docs/notification.stories.vue +31 -0
- package/docs/showProgress.vue +34 -0
- package/docs/stack.vue +39 -0
- package/package.json +30 -0
- package/src/Notice.tsx +212 -0
- package/src/NoticeList.tsx +203 -0
- package/src/NotificationProvider.tsx +19 -0
- package/src/Notifications.tsx +164 -0
- package/src/hooks/useNotification.tsx +163 -0
- package/src/hooks/useStack.ts +32 -0
- package/src/index.ts +9 -0
- package/src/interface.ts +61 -0
- package/tsconfig.json +7 -0
- package/vite.config.ts +18 -0
- package/vitest.config.ts +9 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import Notice_default from "./Notice.js";
|
|
2
|
+
import useStack_default from "./hooks/useStack.js";
|
|
3
|
+
import { useNotificationContext } from "./NotificationProvider.js";
|
|
4
|
+
import { TransitionGroup, computed, createVNode, defineComponent, isVNode, mergeProps, reactive, ref, shallowRef, toRef, watch, watchEffect } from "vue";
|
|
5
|
+
import { classNames } from "@v-c/util";
|
|
6
|
+
import { getTransitionGroupProps } from "@v-c/util/dist/utils/transition";
|
|
7
|
+
import { unrefElement } from "@v-c/util/dist/vueuse/unref-element";
|
|
8
|
+
function _isSlot(s) {
|
|
9
|
+
return typeof s === "function" || Object.prototype.toString.call(s) === "[object Object]" && !isVNode(s);
|
|
10
|
+
}
|
|
11
|
+
var NoticeList_default = /* @__PURE__ */ defineComponent((props, { attrs }) => {
|
|
12
|
+
const ctx = useNotificationContext();
|
|
13
|
+
const dictRef = reactive({});
|
|
14
|
+
const keys = computed(() => (props.configList ?? []).map((config) => ({
|
|
15
|
+
config,
|
|
16
|
+
key: String(config.key)
|
|
17
|
+
})));
|
|
18
|
+
const latestNotice = shallowRef(null);
|
|
19
|
+
const hoverKeys = ref([]);
|
|
20
|
+
const [stackEnabled, stackOptions] = useStack_default(toRef(props, "stack"));
|
|
21
|
+
const expanded = computed(() => stackEnabled.value && (hoverKeys.value.length > 0 || keys.value.length <= stackOptions.threshold.value));
|
|
22
|
+
const placementMotion = computed(() => {
|
|
23
|
+
if (typeof props.motion === "function") return props.placement ? props.motion(props.placement) : void 0;
|
|
24
|
+
return props.motion;
|
|
25
|
+
});
|
|
26
|
+
watch([
|
|
27
|
+
hoverKeys,
|
|
28
|
+
keys,
|
|
29
|
+
stackEnabled
|
|
30
|
+
], () => {
|
|
31
|
+
if (stackEnabled.value && hoverKeys.value.length > 1) hoverKeys.value = hoverKeys.value.filter((key) => keys.value.some(({ key: dataKey }) => key === dataKey));
|
|
32
|
+
});
|
|
33
|
+
watchEffect(() => {
|
|
34
|
+
if (!stackEnabled.value) {
|
|
35
|
+
latestNotice.value = null;
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const lastKey = keys.value[keys.value.length - 1]?.key;
|
|
39
|
+
latestNotice.value = lastKey ? dictRef[lastKey] ?? null : null;
|
|
40
|
+
}, { flush: "post" });
|
|
41
|
+
const checkAllClosed = () => {
|
|
42
|
+
if (!props.placement) return;
|
|
43
|
+
if (keys.value.length === 0) props.onAllNoticeRemoved?.(props.placement);
|
|
44
|
+
};
|
|
45
|
+
return () => {
|
|
46
|
+
let _slot;
|
|
47
|
+
const { prefixCls = "", placement = "topRight", onNoticeClose } = props;
|
|
48
|
+
const renderNotify = () => keys.value.map(({ config }, motionIndex) => {
|
|
49
|
+
const { key, times } = config;
|
|
50
|
+
const strKey = String(key);
|
|
51
|
+
const { className: configClassName, style: configStyle, classNames: configClassNames, styles: configStyles,...restConfig } = config;
|
|
52
|
+
const dataIndex = keys.value.findIndex((item) => item.key === strKey);
|
|
53
|
+
const stackStyle = {};
|
|
54
|
+
if (stackEnabled.value) {
|
|
55
|
+
const index = keys.value.length - 1 - (dataIndex > -1 ? dataIndex : motionIndex - 1);
|
|
56
|
+
const transformX = placement === "top" || placement === "bottom" ? "-50%" : "0";
|
|
57
|
+
if (index > 0) {
|
|
58
|
+
stackStyle.height = expanded.value ? dictRef[strKey]?.offsetHeight : latestNotice.value?.offsetHeight;
|
|
59
|
+
if (stackStyle.height && typeof stackStyle.height === "number") stackStyle.height = `${stackStyle.height}px`;
|
|
60
|
+
let verticalOffset = 0;
|
|
61
|
+
for (let i = 0; i < index; i += 1) {
|
|
62
|
+
const targetKey = keys.value[keys.value.length - 1 - i]?.key;
|
|
63
|
+
const node = targetKey ? dictRef[targetKey] : null;
|
|
64
|
+
verticalOffset += (node?.offsetHeight ?? 0) + stackOptions.gap.value;
|
|
65
|
+
}
|
|
66
|
+
const transformY = (expanded.value ? verticalOffset : index * stackOptions.offset.value) * (placement.startsWith("top") ? 1 : -1);
|
|
67
|
+
const currentWidth = dictRef[strKey]?.offsetWidth;
|
|
68
|
+
const latestWidth = latestNotice.value?.offsetWidth;
|
|
69
|
+
stackStyle.transform = `translate3d(${transformX}, ${transformY}px, 0) scaleX(${!expanded.value && latestWidth && currentWidth ? (latestWidth - stackOptions.offset.value * 2 * (index < 3 ? index : 3)) / currentWidth : 1})`;
|
|
70
|
+
} else stackStyle.transform = `translate3d(${transformX}, 0, 0)`;
|
|
71
|
+
}
|
|
72
|
+
return createVNode("div", {
|
|
73
|
+
"key": strKey,
|
|
74
|
+
"class": classNames(`${prefixCls}-notice-wrapper`, configClassNames?.wrapper),
|
|
75
|
+
"style": {
|
|
76
|
+
...stackStyle,
|
|
77
|
+
...configStyles?.wrapper
|
|
78
|
+
},
|
|
79
|
+
"onMouseenter": () => {
|
|
80
|
+
hoverKeys.value = hoverKeys.value.includes(strKey) ? hoverKeys.value : [...hoverKeys.value, strKey];
|
|
81
|
+
},
|
|
82
|
+
"onMouseleave": () => {
|
|
83
|
+
hoverKeys.value = hoverKeys.value.filter((k) => k !== strKey);
|
|
84
|
+
}
|
|
85
|
+
}, [createVNode(Notice_default, mergeProps(restConfig, {
|
|
86
|
+
"ref": (el) => {
|
|
87
|
+
const element = unrefElement(el) ?? void 0;
|
|
88
|
+
if (dataIndex > -1) dictRef[strKey] = element;
|
|
89
|
+
else delete dictRef[strKey];
|
|
90
|
+
},
|
|
91
|
+
"prefixCls": prefixCls,
|
|
92
|
+
"classNames": configClassNames,
|
|
93
|
+
"styles": configStyles,
|
|
94
|
+
"class": classNames(configClassName, ctx.value?.classNames?.notice),
|
|
95
|
+
"style": configStyle,
|
|
96
|
+
"times": times,
|
|
97
|
+
"eventKey": key,
|
|
98
|
+
"onNoticeClose": onNoticeClose,
|
|
99
|
+
"hovering": stackEnabled.value && hoverKeys.value.length > 0
|
|
100
|
+
}), null)]);
|
|
101
|
+
});
|
|
102
|
+
let motionGroupProps = {};
|
|
103
|
+
if (placementMotion.value) motionGroupProps = getTransitionGroupProps(placementMotion.value.name, placementMotion.value);
|
|
104
|
+
return createVNode(TransitionGroup, mergeProps({
|
|
105
|
+
"key": placement,
|
|
106
|
+
"tag": "div",
|
|
107
|
+
"appear": true
|
|
108
|
+
}, {
|
|
109
|
+
class: classNames(prefixCls, `${prefixCls}-${placement}`, ctx.value?.classNames?.list, attrs.class, {
|
|
110
|
+
[`${prefixCls}-stack-expanded`]: expanded.value,
|
|
111
|
+
[`${prefixCls}-stack`]: stackEnabled.value
|
|
112
|
+
}),
|
|
113
|
+
style: attrs.style
|
|
114
|
+
}, motionGroupProps, { "onAfterLeave": checkAllClosed }), _isSlot(_slot = renderNotify()) ? _slot : { default: () => [_slot] });
|
|
115
|
+
};
|
|
116
|
+
}, { props: {
|
|
117
|
+
configList: {
|
|
118
|
+
type: Array,
|
|
119
|
+
required: false,
|
|
120
|
+
default: void 0
|
|
121
|
+
},
|
|
122
|
+
placement: {
|
|
123
|
+
type: String,
|
|
124
|
+
required: false,
|
|
125
|
+
default: void 0
|
|
126
|
+
},
|
|
127
|
+
prefixCls: {
|
|
128
|
+
type: String,
|
|
129
|
+
required: false,
|
|
130
|
+
default: void 0
|
|
131
|
+
},
|
|
132
|
+
motion: {
|
|
133
|
+
type: Function,
|
|
134
|
+
required: false,
|
|
135
|
+
skipCheck: true,
|
|
136
|
+
default: void 0
|
|
137
|
+
},
|
|
138
|
+
stack: {
|
|
139
|
+
type: [Boolean, Object],
|
|
140
|
+
required: false,
|
|
141
|
+
default: void 0
|
|
142
|
+
},
|
|
143
|
+
onAllNoticeRemoved: {
|
|
144
|
+
type: Function,
|
|
145
|
+
required: false,
|
|
146
|
+
default: void 0
|
|
147
|
+
},
|
|
148
|
+
onNoticeClose: {
|
|
149
|
+
type: Function,
|
|
150
|
+
required: false,
|
|
151
|
+
default: void 0
|
|
152
|
+
}
|
|
153
|
+
} });
|
|
154
|
+
export { NoticeList_default as default };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const require_rolldown_runtime = require("./_virtual/rolldown_runtime.cjs");
|
|
2
|
+
let vue = require("vue");
|
|
3
|
+
const NotificationContext = Symbol("NotificationContext");
|
|
4
|
+
function useNotificationProvider(props) {
|
|
5
|
+
(0, vue.provide)(NotificationContext, props);
|
|
6
|
+
return props;
|
|
7
|
+
}
|
|
8
|
+
function useNotificationContext() {
|
|
9
|
+
return (0, vue.inject)(NotificationContext, (0, vue.ref)({}));
|
|
10
|
+
}
|
|
11
|
+
exports.NotificationContext = NotificationContext;
|
|
12
|
+
exports.useNotificationContext = useNotificationContext;
|
|
13
|
+
exports.useNotificationProvider = useNotificationProvider;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { InjectionKey, Ref } from 'vue';
|
|
2
|
+
export interface NotificationContextProps {
|
|
3
|
+
classNames?: {
|
|
4
|
+
notice?: string;
|
|
5
|
+
list?: string;
|
|
6
|
+
};
|
|
7
|
+
}
|
|
8
|
+
export declare const NotificationContext: InjectionKey<Ref<NotificationContextProps>>;
|
|
9
|
+
export declare function useNotificationProvider(props: Ref<NotificationContextProps>): Ref<NotificationContextProps, NotificationContextProps>;
|
|
10
|
+
export declare function useNotificationContext(): Ref<{}, {}>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { inject, provide, ref } from "vue";
|
|
2
|
+
const NotificationContext = Symbol("NotificationContext");
|
|
3
|
+
function useNotificationProvider(props) {
|
|
4
|
+
provide(NotificationContext, props);
|
|
5
|
+
return props;
|
|
6
|
+
}
|
|
7
|
+
function useNotificationContext() {
|
|
8
|
+
return inject(NotificationContext, ref({}));
|
|
9
|
+
}
|
|
10
|
+
export { NotificationContext, useNotificationContext, useNotificationProvider };
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
2
|
+
const require_rolldown_runtime = require("./_virtual/rolldown_runtime.cjs");
|
|
3
|
+
const require_NoticeList = require("./NoticeList.cjs");
|
|
4
|
+
let vue = require("vue");
|
|
5
|
+
function _isSlot(s) {
|
|
6
|
+
return typeof s === "function" || Object.prototype.toString.call(s) === "[object Object]" && !(0, vue.isVNode)(s);
|
|
7
|
+
}
|
|
8
|
+
var defaults = { prefixCls: "vc-notification" };
|
|
9
|
+
var Notifications = /* @__PURE__ */ (0, vue.defineComponent)((props, { expose }) => {
|
|
10
|
+
const configList = (0, vue.shallowRef)([]);
|
|
11
|
+
const onNoticeClose = (key) => {
|
|
12
|
+
const config = configList.value.find((item) => item.key === key);
|
|
13
|
+
const closable = config?.closable;
|
|
14
|
+
(closable && typeof closable === "object" ? closable : {}).onClose?.();
|
|
15
|
+
config?.onClose?.();
|
|
16
|
+
configList.value = configList.value.filter((item) => item.key !== key);
|
|
17
|
+
};
|
|
18
|
+
expose({
|
|
19
|
+
open: (config) => {
|
|
20
|
+
const list = configList.value;
|
|
21
|
+
let clone = [...configList.value];
|
|
22
|
+
const index = clone.findIndex((item) => item.key === config.key);
|
|
23
|
+
const innerConfig = { ...config };
|
|
24
|
+
if (index >= 0) {
|
|
25
|
+
innerConfig.times = (list[index]?.times || 0) + 1;
|
|
26
|
+
clone[index] = innerConfig;
|
|
27
|
+
} else {
|
|
28
|
+
innerConfig.times = 0;
|
|
29
|
+
clone.push(innerConfig);
|
|
30
|
+
}
|
|
31
|
+
const maxCount = props.maxCount ?? 0;
|
|
32
|
+
if (maxCount > 0 && clone.length > maxCount) clone = clone.slice(-maxCount);
|
|
33
|
+
configList.value = clone;
|
|
34
|
+
},
|
|
35
|
+
close: onNoticeClose,
|
|
36
|
+
destroy: () => {
|
|
37
|
+
configList.value = [];
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
const placements = (0, vue.shallowRef)({});
|
|
41
|
+
(0, vue.watch)(configList, () => {
|
|
42
|
+
const nextPlacements = {};
|
|
43
|
+
configList.value.forEach((config) => {
|
|
44
|
+
const { placement = "topRight" } = config;
|
|
45
|
+
if (placement) {
|
|
46
|
+
nextPlacements[placement] = nextPlacements[placement] || [];
|
|
47
|
+
nextPlacements[placement].push(config);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
Object.keys(placements.value).forEach((_placement) => {
|
|
51
|
+
const placement = _placement;
|
|
52
|
+
nextPlacements[placement] = nextPlacements[placement] || [];
|
|
53
|
+
});
|
|
54
|
+
placements.value = nextPlacements;
|
|
55
|
+
});
|
|
56
|
+
const onAllNoticeRemoved = (placement) => {
|
|
57
|
+
const clone = { ...placements.value };
|
|
58
|
+
if (!(clone[placement] || []).length) delete clone[placement];
|
|
59
|
+
placements.value = clone;
|
|
60
|
+
};
|
|
61
|
+
const emptyRef = (0, vue.shallowRef)(false);
|
|
62
|
+
(0, vue.watch)(placements, () => {
|
|
63
|
+
if (Object.keys(placements.value).length > 0) emptyRef.value = true;
|
|
64
|
+
else if (emptyRef.value) {
|
|
65
|
+
props?.onAllRemoved?.();
|
|
66
|
+
emptyRef.value = false;
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
return () => {
|
|
70
|
+
let _slot;
|
|
71
|
+
const { container } = props;
|
|
72
|
+
const prefixCls = props.prefixCls ?? defaults.prefixCls ?? "";
|
|
73
|
+
if (!container) return null;
|
|
74
|
+
return (0, vue.createVNode)(vue.Teleport, { "to": container }, _isSlot(_slot = Object.keys(placements.value).map((placement) => {
|
|
75
|
+
const placementConfigList = placements.value[placement];
|
|
76
|
+
const list = (0, vue.createVNode)(require_NoticeList.default, {
|
|
77
|
+
"key": placement,
|
|
78
|
+
"configList": placementConfigList,
|
|
79
|
+
"placement": placement,
|
|
80
|
+
"prefixCls": prefixCls,
|
|
81
|
+
"class": props.className?.(placement),
|
|
82
|
+
"style": props.style?.(placement),
|
|
83
|
+
"motion": props.motion,
|
|
84
|
+
"stack": props.stack,
|
|
85
|
+
"onAllNoticeRemoved": () => onAllNoticeRemoved(placement),
|
|
86
|
+
"onNoticeClose": onNoticeClose
|
|
87
|
+
}, null);
|
|
88
|
+
return props.renderNotifications ? props.renderNotifications(list, {
|
|
89
|
+
prefixCls,
|
|
90
|
+
key: placement
|
|
91
|
+
}) : list;
|
|
92
|
+
})) ? _slot : { default: () => [_slot] });
|
|
93
|
+
};
|
|
94
|
+
}, {
|
|
95
|
+
props: /* @__PURE__ */ (0, vue.mergeDefaults)({
|
|
96
|
+
prefixCls: {
|
|
97
|
+
type: String,
|
|
98
|
+
required: false,
|
|
99
|
+
default: void 0
|
|
100
|
+
},
|
|
101
|
+
motion: {
|
|
102
|
+
type: Function,
|
|
103
|
+
required: false,
|
|
104
|
+
skipCheck: true,
|
|
105
|
+
default: void 0
|
|
106
|
+
},
|
|
107
|
+
container: {
|
|
108
|
+
type: null,
|
|
109
|
+
required: false,
|
|
110
|
+
default: void 0
|
|
111
|
+
},
|
|
112
|
+
maxCount: {
|
|
113
|
+
type: Number,
|
|
114
|
+
required: false,
|
|
115
|
+
default: void 0
|
|
116
|
+
},
|
|
117
|
+
className: {
|
|
118
|
+
type: Function,
|
|
119
|
+
required: false,
|
|
120
|
+
default: void 0
|
|
121
|
+
},
|
|
122
|
+
style: {
|
|
123
|
+
type: Function,
|
|
124
|
+
required: false,
|
|
125
|
+
default: void 0
|
|
126
|
+
},
|
|
127
|
+
onAllRemoved: {
|
|
128
|
+
type: null,
|
|
129
|
+
required: false,
|
|
130
|
+
default: void 0
|
|
131
|
+
},
|
|
132
|
+
stack: {
|
|
133
|
+
type: [Boolean, Object],
|
|
134
|
+
required: false,
|
|
135
|
+
default: void 0
|
|
136
|
+
},
|
|
137
|
+
renderNotifications: {
|
|
138
|
+
type: Function,
|
|
139
|
+
required: false,
|
|
140
|
+
default: void 0
|
|
141
|
+
}
|
|
142
|
+
}, defaults),
|
|
143
|
+
name: "Notifications"
|
|
144
|
+
});
|
|
145
|
+
var Notifications_default = Notifications;
|
|
146
|
+
exports.default = Notifications_default;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { VueNode } from '@v-c/util/dist/type';
|
|
2
|
+
import { CSSProperties, TransitionGroupProps } from 'vue';
|
|
3
|
+
import { Key, OpenConfig, Placement, StackConfig } from './interface.ts';
|
|
4
|
+
export interface NotificationsProps {
|
|
5
|
+
prefixCls?: string;
|
|
6
|
+
motion?: TransitionGroupProps | ((placement: Placement) => TransitionGroupProps);
|
|
7
|
+
container?: HTMLElement | ShadowRoot;
|
|
8
|
+
maxCount?: number;
|
|
9
|
+
className?: (placement: Placement) => string;
|
|
10
|
+
style?: (placement: Placement) => CSSProperties;
|
|
11
|
+
onAllRemoved?: VoidFunction;
|
|
12
|
+
stack?: StackConfig;
|
|
13
|
+
renderNotifications?: (node: VueNode, info: {
|
|
14
|
+
prefixCls: string;
|
|
15
|
+
key: Key;
|
|
16
|
+
}) => VueNode;
|
|
17
|
+
}
|
|
18
|
+
export interface NotificationsRef {
|
|
19
|
+
open: (config: OpenConfig) => void;
|
|
20
|
+
close: (key: Key) => void;
|
|
21
|
+
destroy: () => void;
|
|
22
|
+
}
|
|
23
|
+
declare const Notifications: import('vue').DefineSetupFnComponent<NotificationsProps, {}, {}, NotificationsProps & {}, import('vue').PublicProps>;
|
|
24
|
+
export default Notifications;
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import NoticeList_default from "./NoticeList.js";
|
|
2
|
+
import { Teleport, createVNode, defineComponent, isVNode, mergeDefaults, shallowRef, watch } from "vue";
|
|
3
|
+
function _isSlot(s) {
|
|
4
|
+
return typeof s === "function" || Object.prototype.toString.call(s) === "[object Object]" && !isVNode(s);
|
|
5
|
+
}
|
|
6
|
+
var defaults = { prefixCls: "vc-notification" };
|
|
7
|
+
var Notifications_default = /* @__PURE__ */ defineComponent((props, { expose }) => {
|
|
8
|
+
const configList = shallowRef([]);
|
|
9
|
+
const onNoticeClose = (key) => {
|
|
10
|
+
const config = configList.value.find((item) => item.key === key);
|
|
11
|
+
const closable = config?.closable;
|
|
12
|
+
(closable && typeof closable === "object" ? closable : {}).onClose?.();
|
|
13
|
+
config?.onClose?.();
|
|
14
|
+
configList.value = configList.value.filter((item) => item.key !== key);
|
|
15
|
+
};
|
|
16
|
+
expose({
|
|
17
|
+
open: (config) => {
|
|
18
|
+
const list = configList.value;
|
|
19
|
+
let clone = [...configList.value];
|
|
20
|
+
const index = clone.findIndex((item) => item.key === config.key);
|
|
21
|
+
const innerConfig = { ...config };
|
|
22
|
+
if (index >= 0) {
|
|
23
|
+
innerConfig.times = (list[index]?.times || 0) + 1;
|
|
24
|
+
clone[index] = innerConfig;
|
|
25
|
+
} else {
|
|
26
|
+
innerConfig.times = 0;
|
|
27
|
+
clone.push(innerConfig);
|
|
28
|
+
}
|
|
29
|
+
const maxCount = props.maxCount ?? 0;
|
|
30
|
+
if (maxCount > 0 && clone.length > maxCount) clone = clone.slice(-maxCount);
|
|
31
|
+
configList.value = clone;
|
|
32
|
+
},
|
|
33
|
+
close: onNoticeClose,
|
|
34
|
+
destroy: () => {
|
|
35
|
+
configList.value = [];
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
const placements = shallowRef({});
|
|
39
|
+
watch(configList, () => {
|
|
40
|
+
const nextPlacements = {};
|
|
41
|
+
configList.value.forEach((config) => {
|
|
42
|
+
const { placement = "topRight" } = config;
|
|
43
|
+
if (placement) {
|
|
44
|
+
nextPlacements[placement] = nextPlacements[placement] || [];
|
|
45
|
+
nextPlacements[placement].push(config);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
Object.keys(placements.value).forEach((_placement) => {
|
|
49
|
+
const placement = _placement;
|
|
50
|
+
nextPlacements[placement] = nextPlacements[placement] || [];
|
|
51
|
+
});
|
|
52
|
+
placements.value = nextPlacements;
|
|
53
|
+
});
|
|
54
|
+
const onAllNoticeRemoved = (placement) => {
|
|
55
|
+
const clone = { ...placements.value };
|
|
56
|
+
if (!(clone[placement] || []).length) delete clone[placement];
|
|
57
|
+
placements.value = clone;
|
|
58
|
+
};
|
|
59
|
+
const emptyRef = shallowRef(false);
|
|
60
|
+
watch(placements, () => {
|
|
61
|
+
if (Object.keys(placements.value).length > 0) emptyRef.value = true;
|
|
62
|
+
else if (emptyRef.value) {
|
|
63
|
+
props?.onAllRemoved?.();
|
|
64
|
+
emptyRef.value = false;
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
return () => {
|
|
68
|
+
let _slot;
|
|
69
|
+
const { container } = props;
|
|
70
|
+
const prefixCls = props.prefixCls ?? defaults.prefixCls ?? "";
|
|
71
|
+
if (!container) return null;
|
|
72
|
+
return createVNode(Teleport, { "to": container }, _isSlot(_slot = Object.keys(placements.value).map((placement) => {
|
|
73
|
+
const placementConfigList = placements.value[placement];
|
|
74
|
+
const list = createVNode(NoticeList_default, {
|
|
75
|
+
"key": placement,
|
|
76
|
+
"configList": placementConfigList,
|
|
77
|
+
"placement": placement,
|
|
78
|
+
"prefixCls": prefixCls,
|
|
79
|
+
"class": props.className?.(placement),
|
|
80
|
+
"style": props.style?.(placement),
|
|
81
|
+
"motion": props.motion,
|
|
82
|
+
"stack": props.stack,
|
|
83
|
+
"onAllNoticeRemoved": () => onAllNoticeRemoved(placement),
|
|
84
|
+
"onNoticeClose": onNoticeClose
|
|
85
|
+
}, null);
|
|
86
|
+
return props.renderNotifications ? props.renderNotifications(list, {
|
|
87
|
+
prefixCls,
|
|
88
|
+
key: placement
|
|
89
|
+
}) : list;
|
|
90
|
+
})) ? _slot : { default: () => [_slot] });
|
|
91
|
+
};
|
|
92
|
+
}, {
|
|
93
|
+
props: /* @__PURE__ */ mergeDefaults({
|
|
94
|
+
prefixCls: {
|
|
95
|
+
type: String,
|
|
96
|
+
required: false,
|
|
97
|
+
default: void 0
|
|
98
|
+
},
|
|
99
|
+
motion: {
|
|
100
|
+
type: Function,
|
|
101
|
+
required: false,
|
|
102
|
+
skipCheck: true,
|
|
103
|
+
default: void 0
|
|
104
|
+
},
|
|
105
|
+
container: {
|
|
106
|
+
type: null,
|
|
107
|
+
required: false,
|
|
108
|
+
default: void 0
|
|
109
|
+
},
|
|
110
|
+
maxCount: {
|
|
111
|
+
type: Number,
|
|
112
|
+
required: false,
|
|
113
|
+
default: void 0
|
|
114
|
+
},
|
|
115
|
+
className: {
|
|
116
|
+
type: Function,
|
|
117
|
+
required: false,
|
|
118
|
+
default: void 0
|
|
119
|
+
},
|
|
120
|
+
style: {
|
|
121
|
+
type: Function,
|
|
122
|
+
required: false,
|
|
123
|
+
default: void 0
|
|
124
|
+
},
|
|
125
|
+
onAllRemoved: {
|
|
126
|
+
type: null,
|
|
127
|
+
required: false,
|
|
128
|
+
default: void 0
|
|
129
|
+
},
|
|
130
|
+
stack: {
|
|
131
|
+
type: [Boolean, Object],
|
|
132
|
+
required: false,
|
|
133
|
+
default: void 0
|
|
134
|
+
},
|
|
135
|
+
renderNotifications: {
|
|
136
|
+
type: Function,
|
|
137
|
+
required: false,
|
|
138
|
+
default: void 0
|
|
139
|
+
}
|
|
140
|
+
}, defaults),
|
|
141
|
+
name: "Notifications"
|
|
142
|
+
});
|
|
143
|
+
export { Notifications_default as default };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __copyProps = (to, from, except, desc) => {
|
|
8
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
9
|
+
key = keys[i];
|
|
10
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
11
|
+
get: ((k) => from[k]).bind(null, key),
|
|
12
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
18
|
+
value: mod,
|
|
19
|
+
enumerable: true
|
|
20
|
+
}) : target, mod));
|
|
21
|
+
exports.__toESM = __toESM;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
2
|
+
const require_rolldown_runtime = require("../_virtual/rolldown_runtime.cjs");
|
|
3
|
+
const require_Notifications = require("../Notifications.cjs");
|
|
4
|
+
let vue = require("vue");
|
|
5
|
+
var defaultGetContainer = () => document.body;
|
|
6
|
+
var uniqueKey = 0;
|
|
7
|
+
function mergeConfig(...objList) {
|
|
8
|
+
const clone = {};
|
|
9
|
+
objList.forEach((obj) => {
|
|
10
|
+
if (obj) Object.keys(obj).forEach((key) => {
|
|
11
|
+
const val = obj[key];
|
|
12
|
+
if (val !== void 0) clone[key] = val;
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
return clone;
|
|
16
|
+
}
|
|
17
|
+
function useNotification(rootConfig = {}) {
|
|
18
|
+
const { getContainer = defaultGetContainer, motion, prefixCls, maxCount, className, style, onAllRemoved, stack, renderNotifications,...shareConfig } = rootConfig;
|
|
19
|
+
const container = (0, vue.shallowRef)();
|
|
20
|
+
const notificationRef = (0, vue.shallowRef)();
|
|
21
|
+
const contextHolder = () => (0, vue.createVNode)(require_Notifications.default, {
|
|
22
|
+
"container": container.value,
|
|
23
|
+
"ref": notificationRef,
|
|
24
|
+
"prefixCls": prefixCls,
|
|
25
|
+
"motion": motion,
|
|
26
|
+
"maxCount": maxCount,
|
|
27
|
+
"className": className,
|
|
28
|
+
"style": style,
|
|
29
|
+
"onAllRemoved": onAllRemoved,
|
|
30
|
+
"stack": stack,
|
|
31
|
+
"renderNotifications": renderNotifications
|
|
32
|
+
}, null);
|
|
33
|
+
const taskQueue = (0, vue.shallowRef)([]);
|
|
34
|
+
const api = {
|
|
35
|
+
open(config) {
|
|
36
|
+
const mergedConfig = mergeConfig(shareConfig, config);
|
|
37
|
+
if (mergedConfig.key === null || mergedConfig.key === void 0) {
|
|
38
|
+
mergedConfig.key = `vc-notification-${uniqueKey}`;
|
|
39
|
+
uniqueKey += 1;
|
|
40
|
+
}
|
|
41
|
+
taskQueue.value = [...taskQueue.value, {
|
|
42
|
+
type: "open",
|
|
43
|
+
config: mergedConfig
|
|
44
|
+
}];
|
|
45
|
+
},
|
|
46
|
+
close(key) {
|
|
47
|
+
taskQueue.value = [...taskQueue.value, {
|
|
48
|
+
type: "close",
|
|
49
|
+
key
|
|
50
|
+
}];
|
|
51
|
+
},
|
|
52
|
+
destroy() {
|
|
53
|
+
taskQueue.value = [...taskQueue.value, { type: "destroy" }];
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
(0, vue.onMounted)(() => {
|
|
57
|
+
container.value = getContainer();
|
|
58
|
+
});
|
|
59
|
+
(0, vue.watch)(taskQueue, () => {
|
|
60
|
+
if (notificationRef.value && taskQueue.value.length) {
|
|
61
|
+
taskQueue.value.forEach((task) => {
|
|
62
|
+
switch (task.type) {
|
|
63
|
+
case "open":
|
|
64
|
+
notificationRef.value?.open(task.config);
|
|
65
|
+
break;
|
|
66
|
+
case "close":
|
|
67
|
+
notificationRef.value?.close(task.key);
|
|
68
|
+
break;
|
|
69
|
+
case "destroy":
|
|
70
|
+
notificationRef.value?.destroy();
|
|
71
|
+
break;
|
|
72
|
+
default: break;
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
taskQueue.value = taskQueue.value.filter((task) => !taskQueue.value.includes(task));
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
return [api, contextHolder];
|
|
79
|
+
}
|
|
80
|
+
exports.default = useNotification;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { VueNode } from '@v-c/util/dist/type';
|
|
2
|
+
import { CSSProperties, TransitionGroupProps } from 'vue';
|
|
3
|
+
import { Key, OpenConfig, Placement, StackConfig } from '../interface';
|
|
4
|
+
import { NotificationsProps } from '../Notifications';
|
|
5
|
+
type OptionalConfig = Partial<OpenConfig>;
|
|
6
|
+
export interface NotificationConfig {
|
|
7
|
+
prefixCls?: string;
|
|
8
|
+
/** Customize container. It will repeat call which means you should return same container element. */
|
|
9
|
+
getContainer?: () => HTMLElement | ShadowRoot;
|
|
10
|
+
motion?: TransitionGroupProps | ((placement: Placement) => TransitionGroupProps);
|
|
11
|
+
closeIcon?: VueNode;
|
|
12
|
+
closable?: boolean | ({
|
|
13
|
+
closeIcon?: VueNode;
|
|
14
|
+
onClose?: VoidFunction;
|
|
15
|
+
} & Record<string, any>);
|
|
16
|
+
maxCount?: number;
|
|
17
|
+
duration?: number | false | null;
|
|
18
|
+
showProgress?: boolean;
|
|
19
|
+
pauseOnHover?: boolean;
|
|
20
|
+
/** @private. Config for notification holder style. Safe to remove if refactor */
|
|
21
|
+
className?: (placement: Placement) => string;
|
|
22
|
+
/** @private. Config for notification holder style. Safe to remove if refactor */
|
|
23
|
+
style?: (placement: Placement) => CSSProperties;
|
|
24
|
+
/** @private Trigger when all the notification closed. */
|
|
25
|
+
onAllRemoved?: VoidFunction;
|
|
26
|
+
stack?: StackConfig;
|
|
27
|
+
/** @private Slot for style in Notifications */
|
|
28
|
+
renderNotifications?: NotificationsProps['renderNotifications'];
|
|
29
|
+
}
|
|
30
|
+
export interface NotificationAPI {
|
|
31
|
+
open: (config: OptionalConfig) => void;
|
|
32
|
+
close: (key: Key) => void;
|
|
33
|
+
destroy: () => void;
|
|
34
|
+
}
|
|
35
|
+
export default function useNotification(rootConfig?: NotificationConfig): [NotificationAPI, () => VueNode];
|
|
36
|
+
export {};
|