@jumerry/elplus-hooks 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,14 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0 - 2026-03-06
4
+
5
+ - 初始化 `elplus-hooks` npm 包。
6
+ - 新增 `useDialog` 组合式函数导出。
7
+ - 增加 `README.md`(安装、API、示例、发布说明)。
8
+ - 增加 `tsup` 构建配置(ESM/CJS/类型声明)。
9
+ - 配置 `peerDependencies`:`vue`、`element-plus`、`lodash`。
10
+
11
+ ## 0.1.1 - 2026-03-06
12
+
13
+ - 包名调整为 `@jumerry/elplus-hooks`
14
+ - README 安装与导入示例已同步 scoped 包名
package/README.md ADDED
@@ -0,0 +1,86 @@
1
+ # elplus-hooks
2
+
3
+ Element Plus 相关 Vue 组合式函数库(当前仅包含 `useDialog`)。
4
+
5
+ ## 安装
6
+
7
+ ```bash
8
+ npm i @jumerry/elplus-hooks
9
+ ```
10
+
11
+ 你还需要在业务项目中安装以下 peer 依赖(若已安装可忽略):
12
+
13
+ ```bash
14
+ npm i vue element-plus lodash
15
+ ```
16
+
17
+ ## 导出
18
+
19
+ ```ts
20
+ import { useDialog } from "@jumerry/elplus-hooks";
21
+ ```
22
+
23
+ ## API
24
+
25
+ ### `useDialog<P = any>(content, options?)`
26
+
27
+ #### 参数
28
+
29
+ - `content`: `string | Component | JSX.Element`
30
+ - `options`: `DialogOptions<P> | Ref<DialogOptions<P>>`
31
+
32
+ #### `DialogOptions<P>`
33
+
34
+ - `dialogProps`: 透传给 `ElDialog` 的属性,额外支持 `onBeforeOpen?: () => boolean | void`
35
+ - `dialogSlots`: Dialog 插槽(`header`、`footer`)
36
+ - `contentProps`: 透传给内容组件 props
37
+ - `callBack`: 内容组件触发回调时执行
38
+ - `closeEventName`: 自定义关闭事件名(默认 `closeDialog`)
39
+ - `emits`: 事件映射,会自动转换为 `onXxx` 监听
40
+
41
+ #### 返回值
42
+
43
+ - `openDialog(modifyOptions?)`: 打开弹窗,可临时覆盖 `options`
44
+ - `closeDialog()`: 关闭弹窗
45
+
46
+ ## 使用示例
47
+
48
+ ```ts
49
+ import { defineComponent } from "vue";
50
+ import { useDialog } from "@jumerry/elplus-hooks";
51
+
52
+ const ContentComp = defineComponent({
53
+ props: {
54
+ title: String,
55
+ closeDialog: Function
56
+ },
57
+ setup(props) {
58
+ return () => (
59
+ <div>
60
+ <p>{props.title}</p>
61
+ <button onClick={() => props.closeDialog?.()}>关闭</button>
62
+ </div>
63
+ );
64
+ }
65
+ });
66
+
67
+ const { openDialog } = useDialog(ContentComp, {
68
+ contentProps: { title: "弹窗内容" },
69
+ dialogProps: { title: "提示", width: "480px" }
70
+ });
71
+
72
+ openDialog();
73
+ ```
74
+
75
+ ## 发布
76
+
77
+ ```bash
78
+ npm login
79
+ npm run build
80
+ npm publish --access public
81
+ ```
82
+
83
+ ## 注意事项
84
+
85
+ - 本库会操作 `document.body`,请仅在浏览器端调用。
86
+ - SSR 场景请在客户端生命周期中调用 `openDialog`。
package/dist/index.cjs ADDED
@@ -0,0 +1,135 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ useDialog: () => useDialog
34
+ });
35
+ module.exports = __toCommonJS(index_exports);
36
+
37
+ // src/useDialog.ts
38
+ var import_element_plus = require("element-plus");
39
+ var import_lodash = require("lodash");
40
+ var import_merge = __toESM(require("lodash/merge"), 1);
41
+ var import_vue = require("vue");
42
+ function getOptions(options) {
43
+ if (!options) return {};
44
+ return (0, import_vue.isRef)(options) ? options.value : options;
45
+ }
46
+ function useDialog(content, options) {
47
+ let dialogInstance = null;
48
+ let fragment = null;
49
+ const closeAfter = () => {
50
+ if (fragment) {
51
+ (0, import_vue.render)(null, fragment);
52
+ fragment.textContent = "";
53
+ fragment = null;
54
+ }
55
+ dialogInstance = null;
56
+ };
57
+ async function closeDialog() {
58
+ if (dialogInstance) {
59
+ dialogInstance.props.modelValue = false;
60
+ }
61
+ }
62
+ const instance = (0, import_vue.getCurrentInstance)();
63
+ function openDialog(modifyOptions) {
64
+ if (dialogInstance) {
65
+ closeDialog().then(() => closeAfter());
66
+ }
67
+ const baseOptions = getOptions(options);
68
+ const mergedOptions = modifyOptions ? (0, import_merge.default)({}, baseOptions, modifyOptions) : baseOptions;
69
+ const { dialogProps, contentProps } = mergedOptions;
70
+ if (dialogProps?.onBeforeOpen?.() === false) {
71
+ return;
72
+ }
73
+ fragment = document.createDocumentFragment();
74
+ const closeEventName = `on${(0, import_lodash.upperFirst)(
75
+ mergedOptions.closeEventName || "closeDialog"
76
+ )}`;
77
+ let onBeforeClose = null;
78
+ const contentAttrs = {
79
+ ...contentProps,
80
+ [closeEventName]: closeDialog,
81
+ callBack: (data) => {
82
+ mergedOptions.callBack?.(data);
83
+ closeDialog();
84
+ },
85
+ beforeCloseDialog: (fn) => {
86
+ onBeforeClose = fn;
87
+ }
88
+ };
89
+ const eventListeners = {};
90
+ if (mergedOptions.emits) {
91
+ for (const [eventName, handler] of Object.entries(mergedOptions.emits)) {
92
+ const listenerName = `on${(0, import_lodash.upperFirst)(eventName)}`;
93
+ eventListeners[listenerName] = handler;
94
+ }
95
+ }
96
+ const vNode = (0, import_vue.h)(
97
+ import_element_plus.ElDialog,
98
+ {
99
+ ...dialogProps,
100
+ modelValue: true,
101
+ beforeClose: async (done) => {
102
+ const result = await onBeforeClose?.();
103
+ if (result === false) return;
104
+ done();
105
+ },
106
+ onClosed: () => {
107
+ dialogProps?.onClosed?.();
108
+ closeAfter();
109
+ onBeforeClose = null;
110
+ }
111
+ },
112
+ {
113
+ default: () => [
114
+ typeof content === "string" ? content : (0, import_vue.h)(content, {
115
+ ...contentAttrs,
116
+ ...eventListeners
117
+ })
118
+ ],
119
+ ...mergedOptions.dialogSlots
120
+ }
121
+ );
122
+ vNode.appContext = instance?.appContext || null;
123
+ (0, import_vue.render)(vNode, fragment);
124
+ dialogInstance = vNode.component;
125
+ document.body.appendChild(fragment);
126
+ }
127
+ (0, import_vue.onUnmounted)(() => {
128
+ closeDialog();
129
+ });
130
+ return { openDialog, closeDialog };
131
+ }
132
+ // Annotate the CommonJS export names for ESM import in node:
133
+ 0 && (module.exports = {
134
+ useDialog
135
+ });
@@ -0,0 +1,27 @@
1
+ import { ElDialog } from 'element-plus';
2
+ import { h, Ref } from 'vue';
3
+ import { JSX } from 'vue/jsx-runtime';
4
+
5
+ type Content = Parameters<typeof h>[0] | string | object | JSX.Element;
6
+ type ElDialogInstance = InstanceType<typeof ElDialog>;
7
+ type DialogProps = ElDialogInstance["$props"] & {
8
+ onBeforeOpen?: () => boolean | void;
9
+ };
10
+ interface ElDialogSlots {
11
+ header?: (...args: any[]) => Content;
12
+ footer?: (...args: any[]) => Content;
13
+ }
14
+ interface DialogOptions<P> {
15
+ dialogProps?: DialogProps;
16
+ dialogSlots?: ElDialogSlots;
17
+ contentProps?: P;
18
+ callBack?: (data: any) => void;
19
+ closeEventName?: string;
20
+ emits?: Record<string, (...args: any[]) => void>;
21
+ }
22
+ declare function useDialog<P = any>(content: Content, options?: Ref<DialogOptions<P>> | DialogOptions<P>): {
23
+ openDialog: (modifyOptions?: Partial<DialogOptions<P>>) => void;
24
+ closeDialog: () => Promise<void>;
25
+ };
26
+
27
+ export { type DialogOptions, useDialog };
@@ -0,0 +1,27 @@
1
+ import { ElDialog } from 'element-plus';
2
+ import { h, Ref } from 'vue';
3
+ import { JSX } from 'vue/jsx-runtime';
4
+
5
+ type Content = Parameters<typeof h>[0] | string | object | JSX.Element;
6
+ type ElDialogInstance = InstanceType<typeof ElDialog>;
7
+ type DialogProps = ElDialogInstance["$props"] & {
8
+ onBeforeOpen?: () => boolean | void;
9
+ };
10
+ interface ElDialogSlots {
11
+ header?: (...args: any[]) => Content;
12
+ footer?: (...args: any[]) => Content;
13
+ }
14
+ interface DialogOptions<P> {
15
+ dialogProps?: DialogProps;
16
+ dialogSlots?: ElDialogSlots;
17
+ contentProps?: P;
18
+ callBack?: (data: any) => void;
19
+ closeEventName?: string;
20
+ emits?: Record<string, (...args: any[]) => void>;
21
+ }
22
+ declare function useDialog<P = any>(content: Content, options?: Ref<DialogOptions<P>> | DialogOptions<P>): {
23
+ openDialog: (modifyOptions?: Partial<DialogOptions<P>>) => void;
24
+ closeDialog: () => Promise<void>;
25
+ };
26
+
27
+ export { type DialogOptions, useDialog };
package/dist/index.js ADDED
@@ -0,0 +1,98 @@
1
+ // src/useDialog.ts
2
+ import { ElDialog } from "element-plus";
3
+ import { upperFirst } from "lodash";
4
+ import merge from "lodash/merge";
5
+ import { getCurrentInstance, h, isRef, onUnmounted, render } from "vue";
6
+ function getOptions(options) {
7
+ if (!options) return {};
8
+ return isRef(options) ? options.value : options;
9
+ }
10
+ function useDialog(content, options) {
11
+ let dialogInstance = null;
12
+ let fragment = null;
13
+ const closeAfter = () => {
14
+ if (fragment) {
15
+ render(null, fragment);
16
+ fragment.textContent = "";
17
+ fragment = null;
18
+ }
19
+ dialogInstance = null;
20
+ };
21
+ async function closeDialog() {
22
+ if (dialogInstance) {
23
+ dialogInstance.props.modelValue = false;
24
+ }
25
+ }
26
+ const instance = getCurrentInstance();
27
+ function openDialog(modifyOptions) {
28
+ if (dialogInstance) {
29
+ closeDialog().then(() => closeAfter());
30
+ }
31
+ const baseOptions = getOptions(options);
32
+ const mergedOptions = modifyOptions ? merge({}, baseOptions, modifyOptions) : baseOptions;
33
+ const { dialogProps, contentProps } = mergedOptions;
34
+ if (dialogProps?.onBeforeOpen?.() === false) {
35
+ return;
36
+ }
37
+ fragment = document.createDocumentFragment();
38
+ const closeEventName = `on${upperFirst(
39
+ mergedOptions.closeEventName || "closeDialog"
40
+ )}`;
41
+ let onBeforeClose = null;
42
+ const contentAttrs = {
43
+ ...contentProps,
44
+ [closeEventName]: closeDialog,
45
+ callBack: (data) => {
46
+ mergedOptions.callBack?.(data);
47
+ closeDialog();
48
+ },
49
+ beforeCloseDialog: (fn) => {
50
+ onBeforeClose = fn;
51
+ }
52
+ };
53
+ const eventListeners = {};
54
+ if (mergedOptions.emits) {
55
+ for (const [eventName, handler] of Object.entries(mergedOptions.emits)) {
56
+ const listenerName = `on${upperFirst(eventName)}`;
57
+ eventListeners[listenerName] = handler;
58
+ }
59
+ }
60
+ const vNode = h(
61
+ ElDialog,
62
+ {
63
+ ...dialogProps,
64
+ modelValue: true,
65
+ beforeClose: async (done) => {
66
+ const result = await onBeforeClose?.();
67
+ if (result === false) return;
68
+ done();
69
+ },
70
+ onClosed: () => {
71
+ dialogProps?.onClosed?.();
72
+ closeAfter();
73
+ onBeforeClose = null;
74
+ }
75
+ },
76
+ {
77
+ default: () => [
78
+ typeof content === "string" ? content : h(content, {
79
+ ...contentAttrs,
80
+ ...eventListeners
81
+ })
82
+ ],
83
+ ...mergedOptions.dialogSlots
84
+ }
85
+ );
86
+ vNode.appContext = instance?.appContext || null;
87
+ render(vNode, fragment);
88
+ dialogInstance = vNode.component;
89
+ document.body.appendChild(fragment);
90
+ }
91
+ onUnmounted(() => {
92
+ closeDialog();
93
+ });
94
+ return { openDialog, closeDialog };
95
+ }
96
+ export {
97
+ useDialog
98
+ };
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@jumerry/elplus-hooks",
3
+ "version": "0.1.1",
4
+ "description": "Element Plus 相关 Vue 组合式函数集合(当前仅 useDialog)",
5
+ "keywords": [
6
+ "vue",
7
+ "element-plus",
8
+ "composable",
9
+ "hook",
10
+ "dialog"
11
+ ],
12
+ "license": "MIT",
13
+ "author": "zyc",
14
+ "type": "module",
15
+ "main": "./dist/index.cjs",
16
+ "module": "./dist/index.js",
17
+ "types": "./dist/index.d.ts",
18
+ "exports": {
19
+ ".": {
20
+ "types": "./dist/index.d.ts",
21
+ "import": "./dist/index.js",
22
+ "require": "./dist/index.cjs"
23
+ }
24
+ },
25
+ "files": [
26
+ "dist",
27
+ "README.md",
28
+ "CHANGELOG.md"
29
+ ],
30
+ "scripts": {
31
+ "build": "tsup src/index.ts --format esm,cjs --dts --clean --external vue,element-plus,lodash,lodash/merge",
32
+ "check": "tsc --noEmit",
33
+ "prepublishOnly": "npm run build"
34
+ },
35
+ "peerDependencies": {
36
+ "element-plus": ">=2.8.0",
37
+ "lodash": ">=4.17.21",
38
+ "vue": ">=3.4.0"
39
+ },
40
+ "devDependencies": {
41
+ "tsup": "^8.5.0",
42
+ "typescript": "^5.9.2"
43
+ },
44
+ "publishConfig": {
45
+ "access": "public"
46
+ }
47
+ }