@zeus-js/output-vue-wrapper 0.1.0-beta.3 → 0.1.0-beta.5
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/output-vue-wrapper.cjs.js +324 -139
- package/dist/output-vue-wrapper.cjs.prod.js +324 -139
- package/dist/output-vue-wrapper.d.ts +31 -3
- package/dist/output-vue-wrapper.esm-bundler.js +324 -140
- package/dist/runtime/index.cjs.js +114 -0
- package/dist/runtime/index.cjs.prod.js +114 -0
- package/dist/runtime/index.d.ts +26 -0
- package/dist/runtime/index.js +110 -0
- package/dist/runtime/index.prod.js +110 -0
- package/package.json +15 -4
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* output-vue-wrapper v0.1.0-beta.
|
|
2
|
+
* output-vue-wrapper v0.1.0-beta.5
|
|
3
3
|
* (c) 2026 baicie
|
|
4
4
|
* Released under the MIT License.
|
|
5
5
|
**/
|
|
6
6
|
import { resolvePluginDts } from "@zeus-js/bundler-plugin";
|
|
7
7
|
import { generateVueDts, generateVueGlobalDts } from "@zeus-js/component-dts";
|
|
8
|
+
import { cloneVNode, defineComponent, h, onBeforeUnmount, onMounted, ref, withDirectives } from "vue";
|
|
8
9
|
//#region packages/web-c/output-vue-wrapper/src/generateVueIndex.ts
|
|
9
10
|
function generateVueIndex(components, options) {
|
|
10
11
|
const lines = [];
|
|
@@ -18,163 +19,192 @@ function generateVueIndex(components, options) {
|
|
|
18
19
|
//#endregion
|
|
19
20
|
//#region packages/web-c/output-vue-wrapper/src/generateVueWrapper.ts
|
|
20
21
|
function generateVueWrapper(input) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
return generateEventBridgeVueWrapper(input);
|
|
22
|
+
var _input$component$mode;
|
|
23
|
+
return input.mode === "runtime" ? generateRuntimeVueWrapper(input) : input.mode === "event-bridge" || ((_input$component$mode = input.component.models) === null || _input$component$mode === void 0 ? void 0 : _input$component$mode.length) ? generateEventBridgeVueWrapper(input) : generateMinimalVueWrapper(input);
|
|
24
24
|
}
|
|
25
25
|
function generateMinimalVueWrapper(input) {
|
|
26
26
|
const { component, wcModuleId } = input;
|
|
27
|
-
const slotNames =
|
|
27
|
+
const slotNames = getNamedSlots(component);
|
|
28
28
|
const hasNamedSlots = slotNames.length > 0;
|
|
29
|
-
const vueImports = hasNamedSlots ? `cloneVNode, defineComponent, h` : `defineComponent, h`;
|
|
30
|
-
const namedSlotBlock = hasNamedSlots ? `
|
|
31
|
-
for (const name of NAMED_SLOTS) {
|
|
32
|
-
const slot = slots[name];
|
|
33
|
-
if (!slot) continue;
|
|
34
|
-
|
|
35
|
-
for (const vnode of slot()) {
|
|
36
|
-
children.push(withSlot(name, vnode));
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
` : "";
|
|
40
|
-
const withSlotHelper = hasNamedSlots ? `
|
|
41
|
-
function withSlot(name, vnode) {
|
|
42
|
-
if (!vnode) return vnode;
|
|
43
|
-
|
|
44
|
-
if (typeof vnode === 'string') {
|
|
45
|
-
return h('span', { slot: name, style: 'display: contents' }, vnode);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return cloneVNode(vnode, { slot: name });
|
|
49
|
-
}
|
|
50
|
-
` : "";
|
|
51
29
|
return `
|
|
52
|
-
import { ${
|
|
30
|
+
import { ${hasNamedSlots ? "cloneVNode, defineComponent, h" : "defineComponent, h"} } from 'vue';
|
|
53
31
|
|
|
54
32
|
import ${JSON.stringify(wcModuleId)};
|
|
55
|
-
|
|
56
|
-
const NAMED_SLOTS = ${JSON.stringify(slotNames)};
|
|
57
|
-
|
|
33
|
+
${hasNamedSlots ? `\nconst NAMED_SLOTS = ${JSON.stringify(slotNames)};\n` : ""}
|
|
58
34
|
export const ${component.name} = defineComponent({
|
|
59
35
|
name: ${JSON.stringify(component.name)},
|
|
60
36
|
inheritAttrs: false,
|
|
61
37
|
|
|
62
38
|
setup(_props, { attrs, slots }) {
|
|
63
39
|
return () => {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
if (slots.default) {
|
|
67
|
-
children.push(...slots.default());
|
|
68
|
-
}
|
|
69
|
-
${namedSlotBlock}
|
|
70
|
-
return h(
|
|
71
|
-
${JSON.stringify(component.tag)},
|
|
72
|
-
{
|
|
73
|
-
...attrs,
|
|
74
|
-
},
|
|
75
|
-
children,
|
|
76
|
-
);
|
|
40
|
+
${generateVueChildren(slotNames)}
|
|
41
|
+
return h(${JSON.stringify(component.tag)}, attrs, children);
|
|
77
42
|
};
|
|
78
43
|
},
|
|
79
44
|
});
|
|
80
|
-
${
|
|
45
|
+
${hasNamedSlots ? VUE_NAMED_SLOT_HELPERS : ""}
|
|
81
46
|
`.trimStart();
|
|
82
47
|
}
|
|
83
48
|
function generateEventBridgeVueWrapper(input) {
|
|
84
49
|
const { component, wcModuleId } = input;
|
|
85
|
-
const
|
|
86
|
-
const eventNames =
|
|
87
|
-
|
|
88
|
-
const
|
|
50
|
+
const capabilities = getCapabilities(component);
|
|
51
|
+
const { eventNames, models, propNames, slotNames } = capabilities;
|
|
52
|
+
if (!propNames.length && !eventNames.length) return generateMinimalVueWrapper(input);
|
|
53
|
+
const hasProps = propNames.length > 0;
|
|
54
|
+
const hasEvents = eventNames.length > 0;
|
|
55
|
+
const emitNames = Array.from(new Set([...eventNames, ...models.map((model) => model.updateEvent)]));
|
|
56
|
+
const hasNamedSlots = slotNames.length > 0;
|
|
89
57
|
return `
|
|
90
58
|
import {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
59
|
+
${[
|
|
60
|
+
...hasNamedSlots ? ["cloneVNode"] : [],
|
|
61
|
+
"defineComponent",
|
|
62
|
+
...hasProps ? ["getCurrentInstance"] : [],
|
|
63
|
+
"h",
|
|
64
|
+
...hasEvents ? ["onBeforeUnmount"] : [],
|
|
65
|
+
...hasProps || hasEvents ? ["onMounted"] : [],
|
|
66
|
+
...hasProps ? ["onUpdated"] : [],
|
|
67
|
+
"ref"
|
|
68
|
+
].join(",\n ")},
|
|
99
69
|
} from 'vue';
|
|
100
70
|
|
|
101
71
|
import ${JSON.stringify(wcModuleId)};
|
|
102
|
-
|
|
103
|
-
const PROP_KEYS = ${JSON.stringify(propNames)};
|
|
104
|
-
const PROP_INPUT_KEYS = ${JSON.stringify(propInputKeys)};
|
|
105
|
-
const EVENT_NAMES = ${JSON.stringify(eventNames)};
|
|
106
|
-
const NAMED_SLOTS = ${JSON.stringify(slotNames)};
|
|
107
|
-
|
|
72
|
+
${generateVueConstants(capabilities)}
|
|
108
73
|
export const ${component.name} = defineComponent({
|
|
109
74
|
name: ${JSON.stringify(component.name)},
|
|
110
75
|
inheritAttrs: false,
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
},
|
|
115
|
-
|
|
116
|
-
emits: EVENT_NAMES,
|
|
117
|
-
|
|
118
|
-
setup(props, { attrs, slots, emit }) {
|
|
76
|
+
${hasProps ? `\n props: {\n ${generateVueProps(component)}\n },\n` : ""}
|
|
77
|
+
${hasEvents ? ` emits: ${models.length ? JSON.stringify(emitNames) : "EVENT_NAMES"},\n` : ""}
|
|
78
|
+
setup(${hasProps ? "props" : "_props"}, { attrs, slots${hasEvents ? ", emit" : ""} }) {
|
|
119
79
|
const elRef = ref(null);
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
80
|
+
${generateVuePropSetup(hasProps)}
|
|
81
|
+
${generateVueEventSetup(hasEvents, models.length > 0)}
|
|
82
|
+
${generateVueMountHook(hasProps, hasEvents)}
|
|
83
|
+
${hasProps ? " onUpdated(syncProps);\n" : ""}
|
|
84
|
+
${generateVueUnmountHook(hasEvents)}
|
|
85
|
+
return () => {
|
|
86
|
+
${generateVueChildren(slotNames)}
|
|
87
|
+
const hostProps = Object.assign({}, attrs);
|
|
88
|
+
hostProps.ref = elRef;
|
|
127
89
|
|
|
128
|
-
return
|
|
129
|
-
Object.prototype.hasOwnProperty.call(rawProps, key),
|
|
130
|
-
);
|
|
90
|
+
return h(${JSON.stringify(component.tag)}, hostProps, children);
|
|
131
91
|
};
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
${hasProps ? VUE_PROP_HELPERS : ""}
|
|
95
|
+
${hasNamedSlots ? VUE_NAMED_SLOT_HELPERS : ""}
|
|
96
|
+
${models.length ? VUE_MODEL_HELPERS : ""}
|
|
97
|
+
`.trimStart();
|
|
98
|
+
}
|
|
99
|
+
function getCapabilities(component) {
|
|
100
|
+
var _component$models;
|
|
101
|
+
const models = ((_component$models = component.models) !== null && _component$models !== void 0 ? _component$models : []).map((model) => ({
|
|
102
|
+
event: model.event,
|
|
103
|
+
eventPath: model.eventPath,
|
|
104
|
+
updateEvent: `update:${model.prop}`
|
|
105
|
+
}));
|
|
106
|
+
return {
|
|
107
|
+
propNames: Object.keys(component.props),
|
|
108
|
+
eventNames: Array.from(new Set([...Object.entries(component.events).map(([key, event]) => {
|
|
109
|
+
var _event$name, _event$key;
|
|
110
|
+
return (_event$name = event.name) !== null && _event$name !== void 0 ? _event$name : toKebabCase((_event$key = event.key) !== null && _event$key !== void 0 ? _event$key : key);
|
|
111
|
+
}), ...models.map((model) => model.event)])),
|
|
112
|
+
models,
|
|
113
|
+
slotNames: getNamedSlots(component)
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
function getNamedSlots(component) {
|
|
117
|
+
return Object.keys(component.slots).filter((name) => name !== "default");
|
|
118
|
+
}
|
|
119
|
+
function generateVueConstants(capabilities) {
|
|
120
|
+
const { eventNames, models, propNames, slotNames } = capabilities;
|
|
121
|
+
const lines = [];
|
|
122
|
+
if (propNames.length) {
|
|
123
|
+
lines.push(`const PROP_KEYS = ${JSON.stringify(propNames)};`);
|
|
124
|
+
lines.push(`const PROP_INPUT_KEYS = ${JSON.stringify(createVuePropInputKeys(propNames))};`);
|
|
125
|
+
lines.push("const EMPTY_PROPS = {};");
|
|
126
|
+
}
|
|
127
|
+
if (eventNames.length) lines.push(`const EVENT_NAMES = ${JSON.stringify(eventNames)};`);
|
|
128
|
+
if (models.length) lines.push(`const MODEL_BINDINGS = ${JSON.stringify(models)};`);
|
|
129
|
+
if (slotNames.length) lines.push(`const NAMED_SLOTS = ${JSON.stringify(slotNames)};`);
|
|
130
|
+
return lines.length ? `${lines.join("\n")}\n` : "";
|
|
131
|
+
}
|
|
132
|
+
function generateVuePropSetup(hasProps) {
|
|
133
|
+
if (!hasProps) return "";
|
|
134
|
+
return ` const instance = getCurrentInstance();
|
|
135
|
+
const syncedPropPresence = [];
|
|
136
|
+
const syncedPropValues = [];
|
|
132
137
|
|
|
133
138
|
const syncProps = () => {
|
|
134
139
|
const el = elRef.value;
|
|
135
140
|
if (!el) return;
|
|
136
141
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
142
|
+
const rawProps = instance?.vnode.props || EMPTY_PROPS;
|
|
143
|
+
|
|
144
|
+
for (let index = 0; index < PROP_KEYS.length; index += 1) {
|
|
145
|
+
const name = PROP_KEYS[index];
|
|
146
|
+
|
|
147
|
+
if (hasRawProp(rawProps, name)) {
|
|
148
|
+
const nextValue = props[name];
|
|
149
|
+
if (
|
|
150
|
+
!syncedPropPresence[index] ||
|
|
151
|
+
!Object.is(syncedPropValues[index], nextValue)
|
|
152
|
+
) {
|
|
153
|
+
el[name] = nextValue;
|
|
154
|
+
syncedPropValues[index] = nextValue;
|
|
155
|
+
}
|
|
156
|
+
syncedPropPresence[index] = true;
|
|
157
|
+
} else if (syncedPropPresence[index]) {
|
|
145
158
|
el[name] = undefined;
|
|
146
|
-
|
|
159
|
+
syncedPropPresence[index] = false;
|
|
160
|
+
syncedPropValues[index] = undefined;
|
|
147
161
|
}
|
|
148
162
|
}
|
|
149
163
|
};
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
for (const
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
cleanups.push(() => el.removeEventListener(eventName, handler));
|
|
164
|
+
`;
|
|
165
|
+
}
|
|
166
|
+
function generateVueEventSetup(hasEvents, hasModels) {
|
|
167
|
+
if (!hasEvents) return "";
|
|
168
|
+
return ` const eventHandlers = EVENT_NAMES.map(eventName => event => {
|
|
169
|
+
emit(eventName, event);
|
|
170
|
+
${hasModels ? `
|
|
171
|
+
for (const model of MODEL_BINDINGS) {
|
|
172
|
+
if (model.event !== eventName) continue;
|
|
173
|
+
emit(model.updateEvent, readEventPath(event, model.eventPath));
|
|
161
174
|
}
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
175
|
+
` : ""} });
|
|
176
|
+
let mountedEl = null;
|
|
177
|
+
`;
|
|
178
|
+
}
|
|
179
|
+
function generateVueMountHook(hasProps, hasEvents) {
|
|
180
|
+
if (!hasProps && !hasEvents) return "";
|
|
181
|
+
return ` onMounted(() => {
|
|
182
|
+
${hasProps ? " syncProps();\n" : ""}${hasEvents ? `
|
|
183
|
+
mountedEl = elRef.value;
|
|
184
|
+
if (!mountedEl) return;
|
|
185
|
+
|
|
186
|
+
for (let index = 0; index < EVENT_NAMES.length; index += 1) {
|
|
187
|
+
mountedEl.addEventListener(EVENT_NAMES[index], eventHandlers[index]);
|
|
188
|
+
}
|
|
189
|
+
` : ""} });
|
|
190
|
+
`;
|
|
191
|
+
}
|
|
192
|
+
function generateVueUnmountHook(hasEvents) {
|
|
193
|
+
if (!hasEvents) return "";
|
|
194
|
+
return ` onBeforeUnmount(() => {
|
|
195
|
+
if (!mountedEl) return;
|
|
174
196
|
|
|
175
|
-
|
|
176
|
-
|
|
197
|
+
for (let index = 0; index < EVENT_NAMES.length; index += 1) {
|
|
198
|
+
mountedEl.removeEventListener(EVENT_NAMES[index], eventHandlers[index]);
|
|
177
199
|
}
|
|
200
|
+
mountedEl = null;
|
|
201
|
+
});
|
|
202
|
+
`;
|
|
203
|
+
}
|
|
204
|
+
function generateVueChildren(slotNames) {
|
|
205
|
+
if (!slotNames.length) return ` const children = slots.default ? slots.default() : undefined;
|
|
206
|
+
`;
|
|
207
|
+
return ` const children = slots.default ? slots.default() : [];
|
|
178
208
|
|
|
179
209
|
for (const name of NAMED_SLOTS) {
|
|
180
210
|
const slot = slots[name];
|
|
@@ -184,35 +214,49 @@ export const ${component.name} = defineComponent({
|
|
|
184
214
|
children.push(withSlot(name, vnode));
|
|
185
215
|
}
|
|
186
216
|
}
|
|
187
|
-
|
|
188
|
-
return h(
|
|
189
|
-
${JSON.stringify(component.tag)},
|
|
190
|
-
{
|
|
191
|
-
...attrs,
|
|
192
|
-
ref: elRef,
|
|
193
|
-
},
|
|
194
|
-
children,
|
|
195
|
-
);
|
|
196
|
-
};
|
|
197
|
-
},
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
function withSlot(name, vnode) {
|
|
201
|
-
if (!vnode) return vnode;
|
|
202
|
-
|
|
203
|
-
if (typeof vnode === 'string') {
|
|
204
|
-
return h('span', { slot: name, style: 'display: contents' }, vnode);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
return cloneVNode(vnode, { slot: name });
|
|
208
|
-
}
|
|
209
|
-
`.trimStart();
|
|
217
|
+
`;
|
|
210
218
|
}
|
|
211
219
|
function generateVueProps(component) {
|
|
212
220
|
return Object.entries(component.props).map(([name, prop]) => {
|
|
213
221
|
return `${JSON.stringify(name)}: ${toVuePropOption(prop)}`;
|
|
214
222
|
}).join(",\n ");
|
|
215
223
|
}
|
|
224
|
+
function generateRuntimeVueWrapper(input) {
|
|
225
|
+
var _component$models2;
|
|
226
|
+
const { component } = input;
|
|
227
|
+
const propNames = Object.keys(component.props);
|
|
228
|
+
const eventNames = getEventNames(component);
|
|
229
|
+
const slotNames = Object.keys(component.slots).filter((name) => name !== "default");
|
|
230
|
+
const model = (_component$models2 = component.models) === null || _component$models2 === void 0 ? void 0 : _component$models2[0];
|
|
231
|
+
return [
|
|
232
|
+
`import { defineContainer } from '@zeus-js/output-vue-wrapper/runtime'`,
|
|
233
|
+
`import { defineCustomElement } from '../wc/loader.js'`,
|
|
234
|
+
``,
|
|
235
|
+
`export const ${component.name} = defineContainer({`,
|
|
236
|
+
` tagName: ${JSON.stringify(component.tag)},`,
|
|
237
|
+
` displayName: ${JSON.stringify(component.name)},`,
|
|
238
|
+
` defineCustomElement: () => defineCustomElement(${JSON.stringify(component.tag)}),`,
|
|
239
|
+
` props: ${JSON.stringify(propNames)},`,
|
|
240
|
+
` events: ${JSON.stringify(eventNames)},`,
|
|
241
|
+
` slots: ${JSON.stringify(slotNames)},`,
|
|
242
|
+
` model: ${model ? formatModel(model) : "undefined"},`,
|
|
243
|
+
`})`,
|
|
244
|
+
``
|
|
245
|
+
].join("\n");
|
|
246
|
+
}
|
|
247
|
+
function getEventNames(component) {
|
|
248
|
+
return Array.from(new Set(Object.entries(component.events).map(([key, event]) => {
|
|
249
|
+
var _event$name2, _event$key2;
|
|
250
|
+
return (_event$name2 = event.name) !== null && _event$name2 !== void 0 ? _event$name2 : toKebabCase((_event$key2 = event.key) !== null && _event$key2 !== void 0 ? _event$key2 : key);
|
|
251
|
+
})));
|
|
252
|
+
}
|
|
253
|
+
function formatModel(model) {
|
|
254
|
+
return `{
|
|
255
|
+
prop: ${JSON.stringify(model.prop)},
|
|
256
|
+
event: ${JSON.stringify(model.event)},
|
|
257
|
+
eventPath: ${JSON.stringify(model.eventPath)},
|
|
258
|
+
}`;
|
|
259
|
+
}
|
|
216
260
|
function toVuePropOption(prop) {
|
|
217
261
|
var _typeMap$prop$type;
|
|
218
262
|
return `{ type: ${(_typeMap$prop$type = {
|
|
@@ -221,6 +265,7 @@ function toVuePropOption(prop) {
|
|
|
221
265
|
boolean: "Boolean",
|
|
222
266
|
object: "Object",
|
|
223
267
|
array: "Array",
|
|
268
|
+
function: "Function",
|
|
224
269
|
unknown: "null"
|
|
225
270
|
}[prop.type]) !== null && _typeMap$prop$type !== void 0 ? _typeMap$prop$type : "null"}, required: ${prop.required === true ? "true" : "false"} }`;
|
|
226
271
|
}
|
|
@@ -230,6 +275,145 @@ function createVuePropInputKeys(propNames) {
|
|
|
230
275
|
function toKebabCase(value) {
|
|
231
276
|
return value.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
|
|
232
277
|
}
|
|
278
|
+
const VUE_PROP_HELPERS = `
|
|
279
|
+
function hasRawProp(rawProps, name) {
|
|
280
|
+
const keys = PROP_INPUT_KEYS[name];
|
|
281
|
+
for (const key of keys) {
|
|
282
|
+
if (hasOwn(rawProps, key)) return true;
|
|
283
|
+
}
|
|
284
|
+
return false;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
function hasOwn(source, key) {
|
|
288
|
+
return Object.prototype.hasOwnProperty.call(source, key);
|
|
289
|
+
}
|
|
290
|
+
`;
|
|
291
|
+
const VUE_NAMED_SLOT_HELPERS = `
|
|
292
|
+
function withSlot(name, vnode) {
|
|
293
|
+
if (!vnode) return vnode;
|
|
294
|
+
|
|
295
|
+
if (typeof vnode === 'string') {
|
|
296
|
+
return h('span', { slot: name, style: 'display: contents' }, vnode);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
return cloneVNode(vnode, { slot: name });
|
|
300
|
+
}
|
|
301
|
+
`;
|
|
302
|
+
const VUE_MODEL_HELPERS = `
|
|
303
|
+
function readEventPath(event, path) {
|
|
304
|
+
if (!path) return event.detail;
|
|
305
|
+
|
|
306
|
+
let value = event;
|
|
307
|
+
for (const segment of path.split('.')) {
|
|
308
|
+
if (value == null) return undefined;
|
|
309
|
+
value = value[segment];
|
|
310
|
+
}
|
|
311
|
+
return value;
|
|
312
|
+
}
|
|
313
|
+
`;
|
|
314
|
+
//#endregion
|
|
315
|
+
//#region packages/web-c/output-vue-wrapper/src/runtime/defineContainer.ts
|
|
316
|
+
const EMPTY_PROP = Symbol();
|
|
317
|
+
const DEFAULT_EMPTY_PROP = { default: EMPTY_PROP };
|
|
318
|
+
const UPDATE_MODEL_VALUE_EVENT = "update:modelValue";
|
|
319
|
+
const MODEL_VALUE = "modelValue";
|
|
320
|
+
function defineContainer(options) {
|
|
321
|
+
const { tagName, displayName, defineCustomElement, props: componentProps = [], events: emitProps = [], slots: slotNames = [], model, transformTag } = options;
|
|
322
|
+
defineCustomElement === null || defineCustomElement === void 0 || defineCustomElement();
|
|
323
|
+
const emits = [...emitProps];
|
|
324
|
+
const componentPropsMap = {};
|
|
325
|
+
for (const prop of componentProps) componentPropsMap[prop] = DEFAULT_EMPTY_PROP;
|
|
326
|
+
if (model) {
|
|
327
|
+
const updateEvent = getModelUpdateEvent(model.prop);
|
|
328
|
+
emits.push(updateEvent);
|
|
329
|
+
if (updateEvent !== UPDATE_MODEL_VALUE_EVENT) emits.push(UPDATE_MODEL_VALUE_EVENT);
|
|
330
|
+
componentPropsMap[MODEL_VALUE] = DEFAULT_EMPTY_PROP;
|
|
331
|
+
}
|
|
332
|
+
return defineComponent((propsValue, { attrs, slots: allSlots, emit }) => {
|
|
333
|
+
const containerRef = ref();
|
|
334
|
+
const listeners = [];
|
|
335
|
+
onMounted(() => {
|
|
336
|
+
const el = containerRef.value;
|
|
337
|
+
if (!el) return;
|
|
338
|
+
for (const eventName of emitProps) {
|
|
339
|
+
const listener = (event) => {
|
|
340
|
+
emit(eventName, event);
|
|
341
|
+
};
|
|
342
|
+
el.addEventListener(eventName, listener);
|
|
343
|
+
listeners.push({
|
|
344
|
+
eventName,
|
|
345
|
+
listener
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
});
|
|
349
|
+
onBeforeUnmount(() => {
|
|
350
|
+
const el = containerRef.value;
|
|
351
|
+
if (!el) return;
|
|
352
|
+
for (const item of listeners) el.removeEventListener(item.eventName, item.listener);
|
|
353
|
+
listeners.length = 0;
|
|
354
|
+
});
|
|
355
|
+
const vModelDirective = { created: (el) => {
|
|
356
|
+
if (!model) return;
|
|
357
|
+
for (const eventName of toArray(model.event)) el.addEventListener(eventName, (event) => {
|
|
358
|
+
var _model$eventPath;
|
|
359
|
+
if (event.target.tagName !== el.tagName) return;
|
|
360
|
+
const value = readEventPath(event, (_model$eventPath = model.eventPath) !== null && _model$eventPath !== void 0 ? _model$eventPath : `target.${model.prop}`);
|
|
361
|
+
emit(getModelUpdateEvent(model.prop), value);
|
|
362
|
+
if (propsValue[MODEL_VALUE] !== EMPTY_PROP) emit(UPDATE_MODEL_VALUE_EVENT, value);
|
|
363
|
+
});
|
|
364
|
+
} };
|
|
365
|
+
return () => {
|
|
366
|
+
const propsToAdd = { ref: containerRef };
|
|
367
|
+
for (const key in propsValue) {
|
|
368
|
+
const value = propsValue[key];
|
|
369
|
+
if (value !== EMPTY_PROP) propsToAdd[key] = value;
|
|
370
|
+
}
|
|
371
|
+
for (const key in attrs) propsToAdd[key] = attrs[key];
|
|
372
|
+
if (model) {
|
|
373
|
+
const modelValue = propsValue[MODEL_VALUE];
|
|
374
|
+
const modelPropValue = propsValue[model.prop];
|
|
375
|
+
if (modelValue !== EMPTY_PROP) propsToAdd[model.prop] = modelValue;
|
|
376
|
+
else if (modelPropValue !== EMPTY_PROP) propsToAdd[model.prop] = modelPropValue;
|
|
377
|
+
}
|
|
378
|
+
const children = createChildren(allSlots, slotNames);
|
|
379
|
+
const node = h(transformTag ? transformTag(tagName) : tagName, propsToAdd, children);
|
|
380
|
+
return model ? withDirectives(node, [[vModelDirective]]) : node;
|
|
381
|
+
};
|
|
382
|
+
}, {
|
|
383
|
+
name: displayName !== null && displayName !== void 0 ? displayName : tagName,
|
|
384
|
+
props: componentPropsMap,
|
|
385
|
+
emits
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
function createChildren(slots, slotNames) {
|
|
389
|
+
const children = slots.default ? slots.default() : [];
|
|
390
|
+
for (const name of slotNames) {
|
|
391
|
+
const slot = slots[name];
|
|
392
|
+
if (!slot) continue;
|
|
393
|
+
for (const vnode of slot()) children.push(withSlot(name, vnode));
|
|
394
|
+
}
|
|
395
|
+
return children;
|
|
396
|
+
}
|
|
397
|
+
function withSlot(name, vnode) {
|
|
398
|
+
if (!vnode) return vnode;
|
|
399
|
+
if (typeof vnode === "string") return h("span", {
|
|
400
|
+
slot: name,
|
|
401
|
+
style: "display: contents"
|
|
402
|
+
}, vnode);
|
|
403
|
+
return cloneVNode(vnode, { slot: name });
|
|
404
|
+
}
|
|
405
|
+
function getModelUpdateEvent(prop) {
|
|
406
|
+
return `update:${prop}`;
|
|
407
|
+
}
|
|
408
|
+
function toArray(value) {
|
|
409
|
+
return Array.isArray(value) ? value : [value];
|
|
410
|
+
}
|
|
411
|
+
function readEventPath(event, path) {
|
|
412
|
+
return path.split(".").reduce((value, key) => {
|
|
413
|
+
if (value == null) return void 0;
|
|
414
|
+
return value[key];
|
|
415
|
+
}, event);
|
|
416
|
+
}
|
|
233
417
|
//#endregion
|
|
234
418
|
//#region packages/web-c/output-vue-wrapper/src/index.ts
|
|
235
419
|
function vueWrapper(options = {}) {
|
|
@@ -241,7 +425,7 @@ function vueWrapper(options = {}) {
|
|
|
241
425
|
dts: (_options$dts = options.dts) !== null && _options$dts !== void 0 ? _options$dts : true,
|
|
242
426
|
globalDts: (_options$globalDts = options.globalDts) !== null && _options$globalDts !== void 0 ? _options$globalDts : true,
|
|
243
427
|
index: (_options$index = options.index) !== null && _options$index !== void 0 ? _options$index : true,
|
|
244
|
-
wrapper: (_options$wrapper = options.wrapper) !== null && _options$wrapper !== void 0 ? _options$wrapper : "
|
|
428
|
+
wrapper: (_options$wrapper = options.wrapper) !== null && _options$wrapper !== void 0 ? _options$wrapper : "runtime"
|
|
245
429
|
};
|
|
246
430
|
return {
|
|
247
431
|
name: "zeus-output-vue-wrapper",
|
|
@@ -289,4 +473,4 @@ function vueWrapper(options = {}) {
|
|
|
289
473
|
};
|
|
290
474
|
}
|
|
291
475
|
//#endregion
|
|
292
|
-
export { vueWrapper as default };
|
|
476
|
+
export { vueWrapper as default, defineContainer };
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* output-vue-wrapper v0.1.0-beta.5
|
|
3
|
+
* (c) 2026 baicie
|
|
4
|
+
* Released under the MIT License.
|
|
5
|
+
**/
|
|
6
|
+
Object.defineProperties(exports, {
|
|
7
|
+
__esModule: { value: true },
|
|
8
|
+
[Symbol.toStringTag]: { value: "Module" }
|
|
9
|
+
});
|
|
10
|
+
let vue = require("vue");
|
|
11
|
+
//#region packages/web-c/output-vue-wrapper/src/runtime/defineContainer.ts
|
|
12
|
+
const EMPTY_PROP = Symbol();
|
|
13
|
+
const DEFAULT_EMPTY_PROP = { default: EMPTY_PROP };
|
|
14
|
+
const UPDATE_MODEL_VALUE_EVENT = "update:modelValue";
|
|
15
|
+
const MODEL_VALUE = "modelValue";
|
|
16
|
+
function defineContainer(options) {
|
|
17
|
+
const { tagName, displayName, defineCustomElement, props: componentProps = [], events: emitProps = [], slots: slotNames = [], model, transformTag } = options;
|
|
18
|
+
defineCustomElement === null || defineCustomElement === void 0 || defineCustomElement();
|
|
19
|
+
const emits = [...emitProps];
|
|
20
|
+
const componentPropsMap = {};
|
|
21
|
+
for (const prop of componentProps) componentPropsMap[prop] = DEFAULT_EMPTY_PROP;
|
|
22
|
+
if (model) {
|
|
23
|
+
const updateEvent = getModelUpdateEvent(model.prop);
|
|
24
|
+
emits.push(updateEvent);
|
|
25
|
+
if (updateEvent !== UPDATE_MODEL_VALUE_EVENT) emits.push(UPDATE_MODEL_VALUE_EVENT);
|
|
26
|
+
componentPropsMap[MODEL_VALUE] = DEFAULT_EMPTY_PROP;
|
|
27
|
+
}
|
|
28
|
+
return (0, vue.defineComponent)((propsValue, { attrs, slots: allSlots, emit }) => {
|
|
29
|
+
const containerRef = (0, vue.ref)();
|
|
30
|
+
const listeners = [];
|
|
31
|
+
(0, vue.onMounted)(() => {
|
|
32
|
+
const el = containerRef.value;
|
|
33
|
+
if (!el) return;
|
|
34
|
+
for (const eventName of emitProps) {
|
|
35
|
+
const listener = (event) => {
|
|
36
|
+
emit(eventName, event);
|
|
37
|
+
};
|
|
38
|
+
el.addEventListener(eventName, listener);
|
|
39
|
+
listeners.push({
|
|
40
|
+
eventName,
|
|
41
|
+
listener
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
(0, vue.onBeforeUnmount)(() => {
|
|
46
|
+
const el = containerRef.value;
|
|
47
|
+
if (!el) return;
|
|
48
|
+
for (const item of listeners) el.removeEventListener(item.eventName, item.listener);
|
|
49
|
+
listeners.length = 0;
|
|
50
|
+
});
|
|
51
|
+
const vModelDirective = { created: (el) => {
|
|
52
|
+
if (!model) return;
|
|
53
|
+
for (const eventName of toArray(model.event)) el.addEventListener(eventName, (event) => {
|
|
54
|
+
var _model$eventPath;
|
|
55
|
+
if (event.target.tagName !== el.tagName) return;
|
|
56
|
+
const value = readEventPath(event, (_model$eventPath = model.eventPath) !== null && _model$eventPath !== void 0 ? _model$eventPath : `target.${model.prop}`);
|
|
57
|
+
emit(getModelUpdateEvent(model.prop), value);
|
|
58
|
+
if (propsValue[MODEL_VALUE] !== EMPTY_PROP) emit(UPDATE_MODEL_VALUE_EVENT, value);
|
|
59
|
+
});
|
|
60
|
+
} };
|
|
61
|
+
return () => {
|
|
62
|
+
const propsToAdd = { ref: containerRef };
|
|
63
|
+
for (const key in propsValue) {
|
|
64
|
+
const value = propsValue[key];
|
|
65
|
+
if (value !== EMPTY_PROP) propsToAdd[key] = value;
|
|
66
|
+
}
|
|
67
|
+
for (const key in attrs) propsToAdd[key] = attrs[key];
|
|
68
|
+
if (model) {
|
|
69
|
+
const modelValue = propsValue[MODEL_VALUE];
|
|
70
|
+
const modelPropValue = propsValue[model.prop];
|
|
71
|
+
if (modelValue !== EMPTY_PROP) propsToAdd[model.prop] = modelValue;
|
|
72
|
+
else if (modelPropValue !== EMPTY_PROP) propsToAdd[model.prop] = modelPropValue;
|
|
73
|
+
}
|
|
74
|
+
const children = createChildren(allSlots, slotNames);
|
|
75
|
+
const node = (0, vue.h)(transformTag ? transformTag(tagName) : tagName, propsToAdd, children);
|
|
76
|
+
return model ? (0, vue.withDirectives)(node, [[vModelDirective]]) : node;
|
|
77
|
+
};
|
|
78
|
+
}, {
|
|
79
|
+
name: displayName !== null && displayName !== void 0 ? displayName : tagName,
|
|
80
|
+
props: componentPropsMap,
|
|
81
|
+
emits
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
function createChildren(slots, slotNames) {
|
|
85
|
+
const children = slots.default ? slots.default() : [];
|
|
86
|
+
for (const name of slotNames) {
|
|
87
|
+
const slot = slots[name];
|
|
88
|
+
if (!slot) continue;
|
|
89
|
+
for (const vnode of slot()) children.push(withSlot(name, vnode));
|
|
90
|
+
}
|
|
91
|
+
return children;
|
|
92
|
+
}
|
|
93
|
+
function withSlot(name, vnode) {
|
|
94
|
+
if (!vnode) return vnode;
|
|
95
|
+
if (typeof vnode === "string") return (0, vue.h)("span", {
|
|
96
|
+
slot: name,
|
|
97
|
+
style: "display: contents"
|
|
98
|
+
}, vnode);
|
|
99
|
+
return (0, vue.cloneVNode)(vnode, { slot: name });
|
|
100
|
+
}
|
|
101
|
+
function getModelUpdateEvent(prop) {
|
|
102
|
+
return `update:${prop}`;
|
|
103
|
+
}
|
|
104
|
+
function toArray(value) {
|
|
105
|
+
return Array.isArray(value) ? value : [value];
|
|
106
|
+
}
|
|
107
|
+
function readEventPath(event, path) {
|
|
108
|
+
return path.split(".").reduce((value, key) => {
|
|
109
|
+
if (value == null) return void 0;
|
|
110
|
+
return value[key];
|
|
111
|
+
}, event);
|
|
112
|
+
}
|
|
113
|
+
//#endregion
|
|
114
|
+
exports.defineContainer = defineContainer;
|