@zeus-js/output-vue-wrapper 0.1.0-beta.2 → 0.1.0-beta.4

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.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * output-vue-wrapper v0.1.0-beta.2
2
+ * output-vue-wrapper v0.1.0-beta.4
3
3
  * (c) 2026 baicie
4
4
  * Released under the MIT License.
5
5
  **/
@@ -22,76 +22,192 @@ function generateVueIndex(components, options) {
22
22
  //#endregion
23
23
  //#region packages/web-c/output-vue-wrapper/src/generateVueWrapper.ts
24
24
  function generateVueWrapper(input) {
25
+ var _input$component$mode;
26
+ return 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);
27
+ }
28
+ function generateMinimalVueWrapper(input) {
25
29
  const { component, wcModuleId } = input;
26
- const propNames = Object.keys(component.props);
27
- const eventNames = Object.keys(component.events);
28
- const slotNames = Object.keys(component.slots).filter((name) => name !== "default");
29
- const syncPropsBody = generateVuePropSyncLines(propNames);
30
- const watchDeps = propNames.map((name) => `props.${name}`).join(", ");
31
- const watchBlock = propNames.length > 0 ? `watch(() => [${watchDeps}], syncProps);` : `// no reactive props`;
30
+ const slotNames = getNamedSlots(component);
31
+ const hasNamedSlots = slotNames.length > 0;
32
32
  return `
33
- import {
34
- cloneVNode,
35
- defineComponent,
36
- h,
37
- onBeforeUnmount,
38
- onMounted,
39
- ref,
40
- watch,
41
- } from 'vue';
33
+ import { ${hasNamedSlots ? "cloneVNode, defineComponent, h" : "defineComponent, h"} } from 'vue';
42
34
 
43
35
  import ${JSON.stringify(wcModuleId)};
44
-
45
- const PROP_KEYS = ${JSON.stringify(propNames)};
46
- const EVENT_NAMES = ${JSON.stringify(eventNames)};
47
- const NAMED_SLOTS = ${JSON.stringify(slotNames)};
48
-
36
+ ${hasNamedSlots ? `\nconst NAMED_SLOTS = ${JSON.stringify(slotNames)};\n` : ""}
49
37
  export const ${component.name} = defineComponent({
50
38
  name: ${JSON.stringify(component.name)},
39
+ inheritAttrs: false,
51
40
 
52
- props: {
53
- ${generateVueProps(component)}
41
+ setup(_props, { attrs, slots }) {
42
+ return () => {
43
+ ${generateVueChildren(slotNames)}
44
+ return h(${JSON.stringify(component.tag)}, attrs, children);
45
+ };
54
46
  },
47
+ });
48
+ ${hasNamedSlots ? VUE_NAMED_SLOT_HELPERS : ""}
49
+ `.trimStart();
50
+ }
51
+ function generateEventBridgeVueWrapper(input) {
52
+ const { component, wcModuleId } = input;
53
+ const capabilities = getCapabilities(component);
54
+ const { eventNames, models, propNames, slotNames } = capabilities;
55
+ if (!propNames.length && !eventNames.length) return generateMinimalVueWrapper(input);
56
+ const hasProps = propNames.length > 0;
57
+ const hasEvents = eventNames.length > 0;
58
+ const emitNames = Array.from(new Set([...eventNames, ...models.map((model) => model.updateEvent)]));
59
+ const hasNamedSlots = slotNames.length > 0;
60
+ return `
61
+ import {
62
+ ${[
63
+ ...hasNamedSlots ? ["cloneVNode"] : [],
64
+ "defineComponent",
65
+ ...hasProps ? ["getCurrentInstance"] : [],
66
+ "h",
67
+ ...hasEvents ? ["onBeforeUnmount"] : [],
68
+ ...hasProps || hasEvents ? ["onMounted"] : [],
69
+ ...hasProps ? ["onUpdated"] : [],
70
+ "ref"
71
+ ].join(",\n ")},
72
+ } from 'vue';
55
73
 
56
- emits: EVENT_NAMES,
57
-
58
- setup(props, { attrs, slots, emit }) {
74
+ import ${JSON.stringify(wcModuleId)};
75
+ ${generateVueConstants(capabilities)}
76
+ export const ${component.name} = defineComponent({
77
+ name: ${JSON.stringify(component.name)},
78
+ inheritAttrs: false,
79
+ ${hasProps ? `\n props: {\n ${generateVueProps(component)}\n },\n` : ""}
80
+ ${hasEvents ? ` emits: ${models.length ? JSON.stringify(emitNames) : "EVENT_NAMES"},\n` : ""}
81
+ setup(${hasProps ? "props" : "_props"}, { attrs, slots${hasEvents ? ", emit" : ""} }) {
59
82
  const elRef = ref(null);
60
- const cleanups = [];
61
-
62
- const syncProps = () => {
63
- const el = elRef.value;
64
- if (!el) return;
83
+ ${generateVuePropSetup(hasProps)}
84
+ ${generateVueEventSetup(hasEvents, models.length > 0)}
85
+ ${generateVueMountHook(hasProps, hasEvents)}
86
+ ${hasProps ? " onUpdated(syncProps);\n" : ""}
87
+ ${generateVueUnmountHook(hasEvents)}
88
+ return () => {
89
+ ${generateVueChildren(slotNames)}
90
+ const hostProps = Object.assign({}, attrs);
91
+ hostProps.ref = elRef;
65
92
 
66
- ${syncPropsBody}
93
+ return h(${JSON.stringify(component.tag)}, hostProps, children);
67
94
  };
95
+ },
96
+ });
97
+ ${hasProps ? VUE_PROP_HELPERS : ""}
98
+ ${hasNamedSlots ? VUE_NAMED_SLOT_HELPERS : ""}
99
+ ${models.length ? VUE_MODEL_HELPERS : ""}
100
+ `.trimStart();
101
+ }
102
+ function getCapabilities(component) {
103
+ var _component$models;
104
+ const models = ((_component$models = component.models) !== null && _component$models !== void 0 ? _component$models : []).map((model) => ({
105
+ event: model.event,
106
+ eventPath: model.eventPath,
107
+ updateEvent: `update:${model.prop}`
108
+ }));
109
+ return {
110
+ propNames: Object.keys(component.props),
111
+ eventNames: Array.from(new Set([...Object.entries(component.events).map(([key, event]) => {
112
+ var _event$name, _event$key;
113
+ 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);
114
+ }), ...models.map((model) => model.event)])),
115
+ models,
116
+ slotNames: getNamedSlots(component)
117
+ };
118
+ }
119
+ function getNamedSlots(component) {
120
+ return Object.keys(component.slots).filter((name) => name !== "default");
121
+ }
122
+ function generateVueConstants(capabilities) {
123
+ const { eventNames, models, propNames, slotNames } = capabilities;
124
+ const lines = [];
125
+ if (propNames.length) {
126
+ lines.push(`const PROP_KEYS = ${JSON.stringify(propNames)};`);
127
+ lines.push(`const PROP_INPUT_KEYS = ${JSON.stringify(createVuePropInputKeys(propNames))};`);
128
+ lines.push("const EMPTY_PROPS = {};");
129
+ }
130
+ if (eventNames.length) lines.push(`const EVENT_NAMES = ${JSON.stringify(eventNames)};`);
131
+ if (models.length) lines.push(`const MODEL_BINDINGS = ${JSON.stringify(models)};`);
132
+ if (slotNames.length) lines.push(`const NAMED_SLOTS = ${JSON.stringify(slotNames)};`);
133
+ return lines.length ? `${lines.join("\n")}\n` : "";
134
+ }
135
+ function generateVuePropSetup(hasProps) {
136
+ if (!hasProps) return "";
137
+ return ` const instance = getCurrentInstance();
138
+ const syncedPropPresence = [];
139
+ const syncedPropValues = [];
68
140
 
69
- onMounted(() => {
70
- syncProps();
71
-
141
+ const syncProps = () => {
72
142
  const el = elRef.value;
73
143
  if (!el) return;
74
144
 
75
- for (const eventName of EVENT_NAMES) {
76
- const handler = event => emit(eventName, event);
77
- el.addEventListener(eventName, handler);
78
- cleanups.push(() => el.removeEventListener(eventName, handler));
79
- }
80
- });
145
+ const rawProps = instance?.vnode.props || EMPTY_PROPS;
81
146
 
82
- onBeforeUnmount(() => {
83
- for (const cleanup of cleanups) cleanup();
84
- cleanups.length = 0;
85
- });
147
+ for (let index = 0; index < PROP_KEYS.length; index += 1) {
148
+ const name = PROP_KEYS[index];
86
149
 
87
- ${watchBlock}
150
+ if (hasRawProp(rawProps, name)) {
151
+ const nextValue = props[name];
152
+ if (
153
+ !syncedPropPresence[index] ||
154
+ !Object.is(syncedPropValues[index], nextValue)
155
+ ) {
156
+ el[name] = nextValue;
157
+ syncedPropValues[index] = nextValue;
158
+ }
159
+ syncedPropPresence[index] = true;
160
+ } else if (syncedPropPresence[index]) {
161
+ el[name] = undefined;
162
+ syncedPropPresence[index] = false;
163
+ syncedPropValues[index] = undefined;
164
+ }
165
+ }
166
+ };
167
+ `;
168
+ }
169
+ function generateVueEventSetup(hasEvents, hasModels) {
170
+ if (!hasEvents) return "";
171
+ return ` const eventHandlers = EVENT_NAMES.map(eventName => event => {
172
+ emit(eventName, event);
173
+ ${hasModels ? `
174
+ for (const model of MODEL_BINDINGS) {
175
+ if (model.event !== eventName) continue;
176
+ emit(model.updateEvent, readEventPath(event, model.eventPath));
177
+ }
178
+ ` : ""} });
179
+ let mountedEl = null;
180
+ `;
181
+ }
182
+ function generateVueMountHook(hasProps, hasEvents) {
183
+ if (!hasProps && !hasEvents) return "";
184
+ return ` onMounted(() => {
185
+ ${hasProps ? " syncProps();\n" : ""}${hasEvents ? `
186
+ mountedEl = elRef.value;
187
+ if (!mountedEl) return;
88
188
 
89
- return () => {
90
- const children = [];
189
+ for (let index = 0; index < EVENT_NAMES.length; index += 1) {
190
+ mountedEl.addEventListener(EVENT_NAMES[index], eventHandlers[index]);
191
+ }
192
+ ` : ""} });
193
+ `;
194
+ }
195
+ function generateVueUnmountHook(hasEvents) {
196
+ if (!hasEvents) return "";
197
+ return ` onBeforeUnmount(() => {
198
+ if (!mountedEl) return;
91
199
 
92
- if (slots.default) {
93
- children.push(...slots.default());
200
+ for (let index = 0; index < EVENT_NAMES.length; index += 1) {
201
+ mountedEl.removeEventListener(EVENT_NAMES[index], eventHandlers[index]);
94
202
  }
203
+ mountedEl = null;
204
+ });
205
+ `;
206
+ }
207
+ function generateVueChildren(slotNames) {
208
+ if (!slotNames.length) return ` const children = slots.default ? slots.default() : undefined;
209
+ `;
210
+ return ` const children = slots.default ? slots.default() : [];
95
211
 
96
212
  for (const name of NAMED_SLOTS) {
97
213
  const slot = slots[name];
@@ -101,29 +217,7 @@ export const ${component.name} = defineComponent({
101
217
  children.push(withSlot(name, vnode));
102
218
  }
103
219
  }
104
-
105
- return h(
106
- ${JSON.stringify(component.tag)},
107
- {
108
- ...attrs,
109
- ref: elRef,
110
- },
111
- children,
112
- );
113
- };
114
- },
115
- });
116
-
117
- function withSlot(name, vnode) {
118
- if (!vnode) return vnode;
119
-
120
- if (typeof vnode === 'string') {
121
- return h('span', { slot: name, style: 'display: contents' }, vnode);
122
- }
123
-
124
- return cloneVNode(vnode, { slot: name });
125
- }
126
- `.trimStart();
220
+ `;
127
221
  }
128
222
  function generateVueProps(component) {
129
223
  return Object.entries(component.props).map(([name, prop]) => {
@@ -132,32 +226,70 @@ function generateVueProps(component) {
132
226
  }
133
227
  function toVuePropOption(prop) {
134
228
  var _typeMap$prop$type;
135
- const type = (_typeMap$prop$type = {
229
+ return `{ type: ${(_typeMap$prop$type = {
136
230
  string: "String",
137
231
  number: "Number",
138
232
  boolean: "Boolean",
139
233
  object: "Object",
140
234
  array: "Array",
235
+ function: "Function",
141
236
  unknown: "null"
142
- }[prop.type]) !== null && _typeMap$prop$type !== void 0 ? _typeMap$prop$type : "null";
143
- if (prop.default !== void 0) return `{ type: ${type}, default: ${JSON.stringify(prop.default)} }`;
144
- return `{ type: ${type}, required: ${prop.required === true ? "true" : "false"} }`;
237
+ }[prop.type]) !== null && _typeMap$prop$type !== void 0 ? _typeMap$prop$type : "null"}, required: ${prop.required === true ? "true" : "false"} }`;
238
+ }
239
+ function createVuePropInputKeys(propNames) {
240
+ return Object.fromEntries(propNames.map((name) => [name, Array.from(new Set([name, toKebabCase(name)]))]));
241
+ }
242
+ function toKebabCase(value) {
243
+ return value.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
244
+ }
245
+ const VUE_PROP_HELPERS = `
246
+ function hasRawProp(rawProps, name) {
247
+ const keys = PROP_INPUT_KEYS[name];
248
+ for (const key of keys) {
249
+ if (hasOwn(rawProps, key)) return true;
250
+ }
251
+ return false;
252
+ }
253
+
254
+ function hasOwn(source, key) {
255
+ return Object.prototype.hasOwnProperty.call(source, key);
256
+ }
257
+ `;
258
+ const VUE_NAMED_SLOT_HELPERS = `
259
+ function withSlot(name, vnode) {
260
+ if (!vnode) return vnode;
261
+
262
+ if (typeof vnode === 'string') {
263
+ return h('span', { slot: name, style: 'display: contents' }, vnode);
264
+ }
265
+
266
+ return cloneVNode(vnode, { slot: name });
145
267
  }
146
- function generateVuePropSyncLines(propNames) {
147
- if (propNames.length === 0) return "// no props to sync";
148
- return propNames.map((name) => `el.${name} = props.${name};`).join("\n ");
268
+ `;
269
+ const VUE_MODEL_HELPERS = `
270
+ function readEventPath(event, path) {
271
+ if (!path) return event.detail;
272
+
273
+ let value = event;
274
+ for (const segment of path.split('.')) {
275
+ if (value == null) return undefined;
276
+ value = value[segment];
277
+ }
278
+ return value;
149
279
  }
280
+ `;
150
281
  //#endregion
151
282
  //#region packages/web-c/output-vue-wrapper/src/index.ts
152
283
  function vueWrapper(options = {}) {
153
- var _options$outDir, _options$stripPrefix, _options$dts, _options$globalDts, _options$index;
284
+ var _options$outDir, _options$stripPrefix, _options$dts, _options$globalDts, _options$index, _options$wrapper;
154
285
  const normalized = {
155
286
  outDir: (_options$outDir = options.outDir) !== null && _options$outDir !== void 0 ? _options$outDir : "vue",
156
287
  stripPrefix: (_options$stripPrefix = options.stripPrefix) !== null && _options$stripPrefix !== void 0 ? _options$stripPrefix : false,
157
288
  fileName: options.fileName,
158
- dts: (_options$dts = options.dts) !== null && _options$dts !== void 0 ? _options$dts : "auto",
159
- globalDts: (_options$globalDts = options.globalDts) !== null && _options$globalDts !== void 0 ? _options$globalDts : "auto",
160
- index: (_options$index = options.index) !== null && _options$index !== void 0 ? _options$index : true
289
+ dts: (_options$dts = options.dts) !== null && _options$dts !== void 0 ? _options$dts : true,
290
+ globalDts: (_options$globalDts = options.globalDts) !== null && _options$globalDts !== void 0 ? _options$globalDts : true,
291
+ index: (_options$index = options.index) !== null && _options$index !== void 0 ? _options$index : true,
292
+ wrapper: (_options$wrapper = options.wrapper) !== null && _options$wrapper !== void 0 ? _options$wrapper : "minimal"
161
293
  };
162
294
  return {
163
295
  name: "zeus-output-vue-wrapper",
@@ -177,7 +309,8 @@ function vueWrapper(options = {}) {
177
309
  fileName: ctx.outputs.join("vue", ctx.outputs.getFileName("vue", component.tag)),
178
310
  code: generateVueWrapper({
179
311
  component,
180
- wcModuleId: `zeus:wc:${component.tag}`
312
+ wcModuleId: `zeus:wc:${component.tag}`,
313
+ mode: normalized.wrapper
181
314
  })
182
315
  });
183
316
  if (normalized.index) modules.push({
@@ -1,5 +1,5 @@
1
1
  /**
2
- * output-vue-wrapper v0.1.0-beta.2
2
+ * output-vue-wrapper v0.1.0-beta.4
3
3
  * (c) 2026 baicie
4
4
  * Released under the MIT License.
5
5
  **/
@@ -22,76 +22,192 @@ function generateVueIndex(components, options) {
22
22
  //#endregion
23
23
  //#region packages/web-c/output-vue-wrapper/src/generateVueWrapper.ts
24
24
  function generateVueWrapper(input) {
25
+ var _input$component$mode;
26
+ return 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);
27
+ }
28
+ function generateMinimalVueWrapper(input) {
25
29
  const { component, wcModuleId } = input;
26
- const propNames = Object.keys(component.props);
27
- const eventNames = Object.keys(component.events);
28
- const slotNames = Object.keys(component.slots).filter((name) => name !== "default");
29
- const syncPropsBody = generateVuePropSyncLines(propNames);
30
- const watchDeps = propNames.map((name) => `props.${name}`).join(", ");
31
- const watchBlock = propNames.length > 0 ? `watch(() => [${watchDeps}], syncProps);` : `// no reactive props`;
30
+ const slotNames = getNamedSlots(component);
31
+ const hasNamedSlots = slotNames.length > 0;
32
32
  return `
33
- import {
34
- cloneVNode,
35
- defineComponent,
36
- h,
37
- onBeforeUnmount,
38
- onMounted,
39
- ref,
40
- watch,
41
- } from 'vue';
33
+ import { ${hasNamedSlots ? "cloneVNode, defineComponent, h" : "defineComponent, h"} } from 'vue';
42
34
 
43
35
  import ${JSON.stringify(wcModuleId)};
44
-
45
- const PROP_KEYS = ${JSON.stringify(propNames)};
46
- const EVENT_NAMES = ${JSON.stringify(eventNames)};
47
- const NAMED_SLOTS = ${JSON.stringify(slotNames)};
48
-
36
+ ${hasNamedSlots ? `\nconst NAMED_SLOTS = ${JSON.stringify(slotNames)};\n` : ""}
49
37
  export const ${component.name} = defineComponent({
50
38
  name: ${JSON.stringify(component.name)},
39
+ inheritAttrs: false,
51
40
 
52
- props: {
53
- ${generateVueProps(component)}
41
+ setup(_props, { attrs, slots }) {
42
+ return () => {
43
+ ${generateVueChildren(slotNames)}
44
+ return h(${JSON.stringify(component.tag)}, attrs, children);
45
+ };
54
46
  },
47
+ });
48
+ ${hasNamedSlots ? VUE_NAMED_SLOT_HELPERS : ""}
49
+ `.trimStart();
50
+ }
51
+ function generateEventBridgeVueWrapper(input) {
52
+ const { component, wcModuleId } = input;
53
+ const capabilities = getCapabilities(component);
54
+ const { eventNames, models, propNames, slotNames } = capabilities;
55
+ if (!propNames.length && !eventNames.length) return generateMinimalVueWrapper(input);
56
+ const hasProps = propNames.length > 0;
57
+ const hasEvents = eventNames.length > 0;
58
+ const emitNames = Array.from(new Set([...eventNames, ...models.map((model) => model.updateEvent)]));
59
+ const hasNamedSlots = slotNames.length > 0;
60
+ return `
61
+ import {
62
+ ${[
63
+ ...hasNamedSlots ? ["cloneVNode"] : [],
64
+ "defineComponent",
65
+ ...hasProps ? ["getCurrentInstance"] : [],
66
+ "h",
67
+ ...hasEvents ? ["onBeforeUnmount"] : [],
68
+ ...hasProps || hasEvents ? ["onMounted"] : [],
69
+ ...hasProps ? ["onUpdated"] : [],
70
+ "ref"
71
+ ].join(",\n ")},
72
+ } from 'vue';
55
73
 
56
- emits: EVENT_NAMES,
57
-
58
- setup(props, { attrs, slots, emit }) {
74
+ import ${JSON.stringify(wcModuleId)};
75
+ ${generateVueConstants(capabilities)}
76
+ export const ${component.name} = defineComponent({
77
+ name: ${JSON.stringify(component.name)},
78
+ inheritAttrs: false,
79
+ ${hasProps ? `\n props: {\n ${generateVueProps(component)}\n },\n` : ""}
80
+ ${hasEvents ? ` emits: ${models.length ? JSON.stringify(emitNames) : "EVENT_NAMES"},\n` : ""}
81
+ setup(${hasProps ? "props" : "_props"}, { attrs, slots${hasEvents ? ", emit" : ""} }) {
59
82
  const elRef = ref(null);
60
- const cleanups = [];
61
-
62
- const syncProps = () => {
63
- const el = elRef.value;
64
- if (!el) return;
83
+ ${generateVuePropSetup(hasProps)}
84
+ ${generateVueEventSetup(hasEvents, models.length > 0)}
85
+ ${generateVueMountHook(hasProps, hasEvents)}
86
+ ${hasProps ? " onUpdated(syncProps);\n" : ""}
87
+ ${generateVueUnmountHook(hasEvents)}
88
+ return () => {
89
+ ${generateVueChildren(slotNames)}
90
+ const hostProps = Object.assign({}, attrs);
91
+ hostProps.ref = elRef;
65
92
 
66
- ${syncPropsBody}
93
+ return h(${JSON.stringify(component.tag)}, hostProps, children);
67
94
  };
95
+ },
96
+ });
97
+ ${hasProps ? VUE_PROP_HELPERS : ""}
98
+ ${hasNamedSlots ? VUE_NAMED_SLOT_HELPERS : ""}
99
+ ${models.length ? VUE_MODEL_HELPERS : ""}
100
+ `.trimStart();
101
+ }
102
+ function getCapabilities(component) {
103
+ var _component$models;
104
+ const models = ((_component$models = component.models) !== null && _component$models !== void 0 ? _component$models : []).map((model) => ({
105
+ event: model.event,
106
+ eventPath: model.eventPath,
107
+ updateEvent: `update:${model.prop}`
108
+ }));
109
+ return {
110
+ propNames: Object.keys(component.props),
111
+ eventNames: Array.from(new Set([...Object.entries(component.events).map(([key, event]) => {
112
+ var _event$name, _event$key;
113
+ 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);
114
+ }), ...models.map((model) => model.event)])),
115
+ models,
116
+ slotNames: getNamedSlots(component)
117
+ };
118
+ }
119
+ function getNamedSlots(component) {
120
+ return Object.keys(component.slots).filter((name) => name !== "default");
121
+ }
122
+ function generateVueConstants(capabilities) {
123
+ const { eventNames, models, propNames, slotNames } = capabilities;
124
+ const lines = [];
125
+ if (propNames.length) {
126
+ lines.push(`const PROP_KEYS = ${JSON.stringify(propNames)};`);
127
+ lines.push(`const PROP_INPUT_KEYS = ${JSON.stringify(createVuePropInputKeys(propNames))};`);
128
+ lines.push("const EMPTY_PROPS = {};");
129
+ }
130
+ if (eventNames.length) lines.push(`const EVENT_NAMES = ${JSON.stringify(eventNames)};`);
131
+ if (models.length) lines.push(`const MODEL_BINDINGS = ${JSON.stringify(models)};`);
132
+ if (slotNames.length) lines.push(`const NAMED_SLOTS = ${JSON.stringify(slotNames)};`);
133
+ return lines.length ? `${lines.join("\n")}\n` : "";
134
+ }
135
+ function generateVuePropSetup(hasProps) {
136
+ if (!hasProps) return "";
137
+ return ` const instance = getCurrentInstance();
138
+ const syncedPropPresence = [];
139
+ const syncedPropValues = [];
68
140
 
69
- onMounted(() => {
70
- syncProps();
71
-
141
+ const syncProps = () => {
72
142
  const el = elRef.value;
73
143
  if (!el) return;
74
144
 
75
- for (const eventName of EVENT_NAMES) {
76
- const handler = event => emit(eventName, event);
77
- el.addEventListener(eventName, handler);
78
- cleanups.push(() => el.removeEventListener(eventName, handler));
79
- }
80
- });
145
+ const rawProps = instance?.vnode.props || EMPTY_PROPS;
81
146
 
82
- onBeforeUnmount(() => {
83
- for (const cleanup of cleanups) cleanup();
84
- cleanups.length = 0;
85
- });
147
+ for (let index = 0; index < PROP_KEYS.length; index += 1) {
148
+ const name = PROP_KEYS[index];
86
149
 
87
- ${watchBlock}
150
+ if (hasRawProp(rawProps, name)) {
151
+ const nextValue = props[name];
152
+ if (
153
+ !syncedPropPresence[index] ||
154
+ !Object.is(syncedPropValues[index], nextValue)
155
+ ) {
156
+ el[name] = nextValue;
157
+ syncedPropValues[index] = nextValue;
158
+ }
159
+ syncedPropPresence[index] = true;
160
+ } else if (syncedPropPresence[index]) {
161
+ el[name] = undefined;
162
+ syncedPropPresence[index] = false;
163
+ syncedPropValues[index] = undefined;
164
+ }
165
+ }
166
+ };
167
+ `;
168
+ }
169
+ function generateVueEventSetup(hasEvents, hasModels) {
170
+ if (!hasEvents) return "";
171
+ return ` const eventHandlers = EVENT_NAMES.map(eventName => event => {
172
+ emit(eventName, event);
173
+ ${hasModels ? `
174
+ for (const model of MODEL_BINDINGS) {
175
+ if (model.event !== eventName) continue;
176
+ emit(model.updateEvent, readEventPath(event, model.eventPath));
177
+ }
178
+ ` : ""} });
179
+ let mountedEl = null;
180
+ `;
181
+ }
182
+ function generateVueMountHook(hasProps, hasEvents) {
183
+ if (!hasProps && !hasEvents) return "";
184
+ return ` onMounted(() => {
185
+ ${hasProps ? " syncProps();\n" : ""}${hasEvents ? `
186
+ mountedEl = elRef.value;
187
+ if (!mountedEl) return;
88
188
 
89
- return () => {
90
- const children = [];
189
+ for (let index = 0; index < EVENT_NAMES.length; index += 1) {
190
+ mountedEl.addEventListener(EVENT_NAMES[index], eventHandlers[index]);
191
+ }
192
+ ` : ""} });
193
+ `;
194
+ }
195
+ function generateVueUnmountHook(hasEvents) {
196
+ if (!hasEvents) return "";
197
+ return ` onBeforeUnmount(() => {
198
+ if (!mountedEl) return;
91
199
 
92
- if (slots.default) {
93
- children.push(...slots.default());
200
+ for (let index = 0; index < EVENT_NAMES.length; index += 1) {
201
+ mountedEl.removeEventListener(EVENT_NAMES[index], eventHandlers[index]);
94
202
  }
203
+ mountedEl = null;
204
+ });
205
+ `;
206
+ }
207
+ function generateVueChildren(slotNames) {
208
+ if (!slotNames.length) return ` const children = slots.default ? slots.default() : undefined;
209
+ `;
210
+ return ` const children = slots.default ? slots.default() : [];
95
211
 
96
212
  for (const name of NAMED_SLOTS) {
97
213
  const slot = slots[name];
@@ -101,29 +217,7 @@ export const ${component.name} = defineComponent({
101
217
  children.push(withSlot(name, vnode));
102
218
  }
103
219
  }
104
-
105
- return h(
106
- ${JSON.stringify(component.tag)},
107
- {
108
- ...attrs,
109
- ref: elRef,
110
- },
111
- children,
112
- );
113
- };
114
- },
115
- });
116
-
117
- function withSlot(name, vnode) {
118
- if (!vnode) return vnode;
119
-
120
- if (typeof vnode === 'string') {
121
- return h('span', { slot: name, style: 'display: contents' }, vnode);
122
- }
123
-
124
- return cloneVNode(vnode, { slot: name });
125
- }
126
- `.trimStart();
220
+ `;
127
221
  }
128
222
  function generateVueProps(component) {
129
223
  return Object.entries(component.props).map(([name, prop]) => {
@@ -132,32 +226,70 @@ function generateVueProps(component) {
132
226
  }
133
227
  function toVuePropOption(prop) {
134
228
  var _typeMap$prop$type;
135
- const type = (_typeMap$prop$type = {
229
+ return `{ type: ${(_typeMap$prop$type = {
136
230
  string: "String",
137
231
  number: "Number",
138
232
  boolean: "Boolean",
139
233
  object: "Object",
140
234
  array: "Array",
235
+ function: "Function",
141
236
  unknown: "null"
142
- }[prop.type]) !== null && _typeMap$prop$type !== void 0 ? _typeMap$prop$type : "null";
143
- if (prop.default !== void 0) return `{ type: ${type}, default: ${JSON.stringify(prop.default)} }`;
144
- return `{ type: ${type}, required: ${prop.required === true ? "true" : "false"} }`;
237
+ }[prop.type]) !== null && _typeMap$prop$type !== void 0 ? _typeMap$prop$type : "null"}, required: ${prop.required === true ? "true" : "false"} }`;
238
+ }
239
+ function createVuePropInputKeys(propNames) {
240
+ return Object.fromEntries(propNames.map((name) => [name, Array.from(new Set([name, toKebabCase(name)]))]));
241
+ }
242
+ function toKebabCase(value) {
243
+ return value.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
244
+ }
245
+ const VUE_PROP_HELPERS = `
246
+ function hasRawProp(rawProps, name) {
247
+ const keys = PROP_INPUT_KEYS[name];
248
+ for (const key of keys) {
249
+ if (hasOwn(rawProps, key)) return true;
250
+ }
251
+ return false;
252
+ }
253
+
254
+ function hasOwn(source, key) {
255
+ return Object.prototype.hasOwnProperty.call(source, key);
256
+ }
257
+ `;
258
+ const VUE_NAMED_SLOT_HELPERS = `
259
+ function withSlot(name, vnode) {
260
+ if (!vnode) return vnode;
261
+
262
+ if (typeof vnode === 'string') {
263
+ return h('span', { slot: name, style: 'display: contents' }, vnode);
264
+ }
265
+
266
+ return cloneVNode(vnode, { slot: name });
145
267
  }
146
- function generateVuePropSyncLines(propNames) {
147
- if (propNames.length === 0) return "// no props to sync";
148
- return propNames.map((name) => `el.${name} = props.${name};`).join("\n ");
268
+ `;
269
+ const VUE_MODEL_HELPERS = `
270
+ function readEventPath(event, path) {
271
+ if (!path) return event.detail;
272
+
273
+ let value = event;
274
+ for (const segment of path.split('.')) {
275
+ if (value == null) return undefined;
276
+ value = value[segment];
277
+ }
278
+ return value;
149
279
  }
280
+ `;
150
281
  //#endregion
151
282
  //#region packages/web-c/output-vue-wrapper/src/index.ts
152
283
  function vueWrapper(options = {}) {
153
- var _options$outDir, _options$stripPrefix, _options$dts, _options$globalDts, _options$index;
284
+ var _options$outDir, _options$stripPrefix, _options$dts, _options$globalDts, _options$index, _options$wrapper;
154
285
  const normalized = {
155
286
  outDir: (_options$outDir = options.outDir) !== null && _options$outDir !== void 0 ? _options$outDir : "vue",
156
287
  stripPrefix: (_options$stripPrefix = options.stripPrefix) !== null && _options$stripPrefix !== void 0 ? _options$stripPrefix : false,
157
288
  fileName: options.fileName,
158
- dts: (_options$dts = options.dts) !== null && _options$dts !== void 0 ? _options$dts : "auto",
159
- globalDts: (_options$globalDts = options.globalDts) !== null && _options$globalDts !== void 0 ? _options$globalDts : "auto",
160
- index: (_options$index = options.index) !== null && _options$index !== void 0 ? _options$index : true
289
+ dts: (_options$dts = options.dts) !== null && _options$dts !== void 0 ? _options$dts : true,
290
+ globalDts: (_options$globalDts = options.globalDts) !== null && _options$globalDts !== void 0 ? _options$globalDts : true,
291
+ index: (_options$index = options.index) !== null && _options$index !== void 0 ? _options$index : true,
292
+ wrapper: (_options$wrapper = options.wrapper) !== null && _options$wrapper !== void 0 ? _options$wrapper : "minimal"
161
293
  };
162
294
  return {
163
295
  name: "zeus-output-vue-wrapper",
@@ -177,7 +309,8 @@ function vueWrapper(options = {}) {
177
309
  fileName: ctx.outputs.join("vue", ctx.outputs.getFileName("vue", component.tag)),
178
310
  code: generateVueWrapper({
179
311
  component,
180
- wcModuleId: `zeus:wc:${component.tag}`
312
+ wcModuleId: `zeus:wc:${component.tag}`,
313
+ mode: normalized.wrapper
181
314
  })
182
315
  });
183
316
  if (normalized.index) modules.push({
@@ -1,5 +1,6 @@
1
1
  import { DtsMode, ZeusComponentPlugin } from '@zeus-js/bundler-plugin';
2
2
 
3
+ type VueWrapperMode = 'minimal' | 'event-bridge';
3
4
  export interface OutputVueWrapperOptions {
4
5
  /**
5
6
  * Vue wrapper output directory.
@@ -20,13 +21,13 @@ export interface OutputVueWrapperOptions {
20
21
  /**
21
22
  * Generate vue/index.d.ts.
22
23
  *
23
- * @default 'auto'
24
+ * @default true
24
25
  */
25
26
  dts?: DtsMode;
26
27
  /**
27
28
  * Generate vue/global.d.ts.
28
29
  *
29
- * @default 'auto'
30
+ * @default true
30
31
  */
31
32
  globalDts?: DtsMode;
32
33
  /**
@@ -35,6 +36,15 @@ export interface OutputVueWrapperOptions {
35
36
  * @default true
36
37
  */
37
38
  index?: boolean;
39
+ /**
40
+ * minimal:
41
+ * Default. Vue wrapper only renders the custom element tag.
42
+ * No watch, no prop sync, no event listeners.
43
+ *
44
+ * event-bridge:
45
+ * Additional mode for React CustomEvent bridging.
46
+ */
47
+ wrapper?: VueWrapperMode;
38
48
  }
39
49
 
40
50
  export declare function vueWrapper(options?: OutputVueWrapperOptions): ZeusComponentPlugin;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * output-vue-wrapper v0.1.0-beta.2
2
+ * output-vue-wrapper v0.1.0-beta.4
3
3
  * (c) 2026 baicie
4
4
  * Released under the MIT License.
5
5
  **/
@@ -18,76 +18,192 @@ function generateVueIndex(components, options) {
18
18
  //#endregion
19
19
  //#region packages/web-c/output-vue-wrapper/src/generateVueWrapper.ts
20
20
  function generateVueWrapper(input) {
21
+ var _input$component$mode;
22
+ return 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);
23
+ }
24
+ function generateMinimalVueWrapper(input) {
21
25
  const { component, wcModuleId } = input;
22
- const propNames = Object.keys(component.props);
23
- const eventNames = Object.keys(component.events);
24
- const slotNames = Object.keys(component.slots).filter((name) => name !== "default");
25
- const syncPropsBody = generateVuePropSyncLines(propNames);
26
- const watchDeps = propNames.map((name) => `props.${name}`).join(", ");
27
- const watchBlock = propNames.length > 0 ? `watch(() => [${watchDeps}], syncProps);` : `// no reactive props`;
26
+ const slotNames = getNamedSlots(component);
27
+ const hasNamedSlots = slotNames.length > 0;
28
28
  return `
29
- import {
30
- cloneVNode,
31
- defineComponent,
32
- h,
33
- onBeforeUnmount,
34
- onMounted,
35
- ref,
36
- watch,
37
- } from 'vue';
29
+ import { ${hasNamedSlots ? "cloneVNode, defineComponent, h" : "defineComponent, h"} } from 'vue';
38
30
 
39
31
  import ${JSON.stringify(wcModuleId)};
40
-
41
- const PROP_KEYS = ${JSON.stringify(propNames)};
42
- const EVENT_NAMES = ${JSON.stringify(eventNames)};
43
- const NAMED_SLOTS = ${JSON.stringify(slotNames)};
44
-
32
+ ${hasNamedSlots ? `\nconst NAMED_SLOTS = ${JSON.stringify(slotNames)};\n` : ""}
45
33
  export const ${component.name} = defineComponent({
46
34
  name: ${JSON.stringify(component.name)},
35
+ inheritAttrs: false,
47
36
 
48
- props: {
49
- ${generateVueProps(component)}
37
+ setup(_props, { attrs, slots }) {
38
+ return () => {
39
+ ${generateVueChildren(slotNames)}
40
+ return h(${JSON.stringify(component.tag)}, attrs, children);
41
+ };
50
42
  },
43
+ });
44
+ ${hasNamedSlots ? VUE_NAMED_SLOT_HELPERS : ""}
45
+ `.trimStart();
46
+ }
47
+ function generateEventBridgeVueWrapper(input) {
48
+ const { component, wcModuleId } = input;
49
+ const capabilities = getCapabilities(component);
50
+ const { eventNames, models, propNames, slotNames } = capabilities;
51
+ if (!propNames.length && !eventNames.length) return generateMinimalVueWrapper(input);
52
+ const hasProps = propNames.length > 0;
53
+ const hasEvents = eventNames.length > 0;
54
+ const emitNames = Array.from(new Set([...eventNames, ...models.map((model) => model.updateEvent)]));
55
+ const hasNamedSlots = slotNames.length > 0;
56
+ return `
57
+ import {
58
+ ${[
59
+ ...hasNamedSlots ? ["cloneVNode"] : [],
60
+ "defineComponent",
61
+ ...hasProps ? ["getCurrentInstance"] : [],
62
+ "h",
63
+ ...hasEvents ? ["onBeforeUnmount"] : [],
64
+ ...hasProps || hasEvents ? ["onMounted"] : [],
65
+ ...hasProps ? ["onUpdated"] : [],
66
+ "ref"
67
+ ].join(",\n ")},
68
+ } from 'vue';
51
69
 
52
- emits: EVENT_NAMES,
53
-
54
- setup(props, { attrs, slots, emit }) {
70
+ import ${JSON.stringify(wcModuleId)};
71
+ ${generateVueConstants(capabilities)}
72
+ export const ${component.name} = defineComponent({
73
+ name: ${JSON.stringify(component.name)},
74
+ inheritAttrs: false,
75
+ ${hasProps ? `\n props: {\n ${generateVueProps(component)}\n },\n` : ""}
76
+ ${hasEvents ? ` emits: ${models.length ? JSON.stringify(emitNames) : "EVENT_NAMES"},\n` : ""}
77
+ setup(${hasProps ? "props" : "_props"}, { attrs, slots${hasEvents ? ", emit" : ""} }) {
55
78
  const elRef = ref(null);
56
- const cleanups = [];
57
-
58
- const syncProps = () => {
59
- const el = elRef.value;
60
- if (!el) return;
79
+ ${generateVuePropSetup(hasProps)}
80
+ ${generateVueEventSetup(hasEvents, models.length > 0)}
81
+ ${generateVueMountHook(hasProps, hasEvents)}
82
+ ${hasProps ? " onUpdated(syncProps);\n" : ""}
83
+ ${generateVueUnmountHook(hasEvents)}
84
+ return () => {
85
+ ${generateVueChildren(slotNames)}
86
+ const hostProps = Object.assign({}, attrs);
87
+ hostProps.ref = elRef;
61
88
 
62
- ${syncPropsBody}
89
+ return h(${JSON.stringify(component.tag)}, hostProps, children);
63
90
  };
91
+ },
92
+ });
93
+ ${hasProps ? VUE_PROP_HELPERS : ""}
94
+ ${hasNamedSlots ? VUE_NAMED_SLOT_HELPERS : ""}
95
+ ${models.length ? VUE_MODEL_HELPERS : ""}
96
+ `.trimStart();
97
+ }
98
+ function getCapabilities(component) {
99
+ var _component$models;
100
+ const models = ((_component$models = component.models) !== null && _component$models !== void 0 ? _component$models : []).map((model) => ({
101
+ event: model.event,
102
+ eventPath: model.eventPath,
103
+ updateEvent: `update:${model.prop}`
104
+ }));
105
+ return {
106
+ propNames: Object.keys(component.props),
107
+ eventNames: Array.from(new Set([...Object.entries(component.events).map(([key, event]) => {
108
+ var _event$name, _event$key;
109
+ 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);
110
+ }), ...models.map((model) => model.event)])),
111
+ models,
112
+ slotNames: getNamedSlots(component)
113
+ };
114
+ }
115
+ function getNamedSlots(component) {
116
+ return Object.keys(component.slots).filter((name) => name !== "default");
117
+ }
118
+ function generateVueConstants(capabilities) {
119
+ const { eventNames, models, propNames, slotNames } = capabilities;
120
+ const lines = [];
121
+ if (propNames.length) {
122
+ lines.push(`const PROP_KEYS = ${JSON.stringify(propNames)};`);
123
+ lines.push(`const PROP_INPUT_KEYS = ${JSON.stringify(createVuePropInputKeys(propNames))};`);
124
+ lines.push("const EMPTY_PROPS = {};");
125
+ }
126
+ if (eventNames.length) lines.push(`const EVENT_NAMES = ${JSON.stringify(eventNames)};`);
127
+ if (models.length) lines.push(`const MODEL_BINDINGS = ${JSON.stringify(models)};`);
128
+ if (slotNames.length) lines.push(`const NAMED_SLOTS = ${JSON.stringify(slotNames)};`);
129
+ return lines.length ? `${lines.join("\n")}\n` : "";
130
+ }
131
+ function generateVuePropSetup(hasProps) {
132
+ if (!hasProps) return "";
133
+ return ` const instance = getCurrentInstance();
134
+ const syncedPropPresence = [];
135
+ const syncedPropValues = [];
64
136
 
65
- onMounted(() => {
66
- syncProps();
67
-
137
+ const syncProps = () => {
68
138
  const el = elRef.value;
69
139
  if (!el) return;
70
140
 
71
- for (const eventName of EVENT_NAMES) {
72
- const handler = event => emit(eventName, event);
73
- el.addEventListener(eventName, handler);
74
- cleanups.push(() => el.removeEventListener(eventName, handler));
75
- }
76
- });
141
+ const rawProps = instance?.vnode.props || EMPTY_PROPS;
77
142
 
78
- onBeforeUnmount(() => {
79
- for (const cleanup of cleanups) cleanup();
80
- cleanups.length = 0;
81
- });
143
+ for (let index = 0; index < PROP_KEYS.length; index += 1) {
144
+ const name = PROP_KEYS[index];
82
145
 
83
- ${watchBlock}
146
+ if (hasRawProp(rawProps, name)) {
147
+ const nextValue = props[name];
148
+ if (
149
+ !syncedPropPresence[index] ||
150
+ !Object.is(syncedPropValues[index], nextValue)
151
+ ) {
152
+ el[name] = nextValue;
153
+ syncedPropValues[index] = nextValue;
154
+ }
155
+ syncedPropPresence[index] = true;
156
+ } else if (syncedPropPresence[index]) {
157
+ el[name] = undefined;
158
+ syncedPropPresence[index] = false;
159
+ syncedPropValues[index] = undefined;
160
+ }
161
+ }
162
+ };
163
+ `;
164
+ }
165
+ function generateVueEventSetup(hasEvents, hasModels) {
166
+ if (!hasEvents) return "";
167
+ return ` const eventHandlers = EVENT_NAMES.map(eventName => event => {
168
+ emit(eventName, event);
169
+ ${hasModels ? `
170
+ for (const model of MODEL_BINDINGS) {
171
+ if (model.event !== eventName) continue;
172
+ emit(model.updateEvent, readEventPath(event, model.eventPath));
173
+ }
174
+ ` : ""} });
175
+ let mountedEl = null;
176
+ `;
177
+ }
178
+ function generateVueMountHook(hasProps, hasEvents) {
179
+ if (!hasProps && !hasEvents) return "";
180
+ return ` onMounted(() => {
181
+ ${hasProps ? " syncProps();\n" : ""}${hasEvents ? `
182
+ mountedEl = elRef.value;
183
+ if (!mountedEl) return;
84
184
 
85
- return () => {
86
- const children = [];
185
+ for (let index = 0; index < EVENT_NAMES.length; index += 1) {
186
+ mountedEl.addEventListener(EVENT_NAMES[index], eventHandlers[index]);
187
+ }
188
+ ` : ""} });
189
+ `;
190
+ }
191
+ function generateVueUnmountHook(hasEvents) {
192
+ if (!hasEvents) return "";
193
+ return ` onBeforeUnmount(() => {
194
+ if (!mountedEl) return;
87
195
 
88
- if (slots.default) {
89
- children.push(...slots.default());
196
+ for (let index = 0; index < EVENT_NAMES.length; index += 1) {
197
+ mountedEl.removeEventListener(EVENT_NAMES[index], eventHandlers[index]);
90
198
  }
199
+ mountedEl = null;
200
+ });
201
+ `;
202
+ }
203
+ function generateVueChildren(slotNames) {
204
+ if (!slotNames.length) return ` const children = slots.default ? slots.default() : undefined;
205
+ `;
206
+ return ` const children = slots.default ? slots.default() : [];
91
207
 
92
208
  for (const name of NAMED_SLOTS) {
93
209
  const slot = slots[name];
@@ -97,29 +213,7 @@ export const ${component.name} = defineComponent({
97
213
  children.push(withSlot(name, vnode));
98
214
  }
99
215
  }
100
-
101
- return h(
102
- ${JSON.stringify(component.tag)},
103
- {
104
- ...attrs,
105
- ref: elRef,
106
- },
107
- children,
108
- );
109
- };
110
- },
111
- });
112
-
113
- function withSlot(name, vnode) {
114
- if (!vnode) return vnode;
115
-
116
- if (typeof vnode === 'string') {
117
- return h('span', { slot: name, style: 'display: contents' }, vnode);
118
- }
119
-
120
- return cloneVNode(vnode, { slot: name });
121
- }
122
- `.trimStart();
216
+ `;
123
217
  }
124
218
  function generateVueProps(component) {
125
219
  return Object.entries(component.props).map(([name, prop]) => {
@@ -128,32 +222,70 @@ function generateVueProps(component) {
128
222
  }
129
223
  function toVuePropOption(prop) {
130
224
  var _typeMap$prop$type;
131
- const type = (_typeMap$prop$type = {
225
+ return `{ type: ${(_typeMap$prop$type = {
132
226
  string: "String",
133
227
  number: "Number",
134
228
  boolean: "Boolean",
135
229
  object: "Object",
136
230
  array: "Array",
231
+ function: "Function",
137
232
  unknown: "null"
138
- }[prop.type]) !== null && _typeMap$prop$type !== void 0 ? _typeMap$prop$type : "null";
139
- if (prop.default !== void 0) return `{ type: ${type}, default: ${JSON.stringify(prop.default)} }`;
140
- return `{ type: ${type}, required: ${prop.required === true ? "true" : "false"} }`;
233
+ }[prop.type]) !== null && _typeMap$prop$type !== void 0 ? _typeMap$prop$type : "null"}, required: ${prop.required === true ? "true" : "false"} }`;
234
+ }
235
+ function createVuePropInputKeys(propNames) {
236
+ return Object.fromEntries(propNames.map((name) => [name, Array.from(new Set([name, toKebabCase(name)]))]));
237
+ }
238
+ function toKebabCase(value) {
239
+ return value.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
240
+ }
241
+ const VUE_PROP_HELPERS = `
242
+ function hasRawProp(rawProps, name) {
243
+ const keys = PROP_INPUT_KEYS[name];
244
+ for (const key of keys) {
245
+ if (hasOwn(rawProps, key)) return true;
246
+ }
247
+ return false;
248
+ }
249
+
250
+ function hasOwn(source, key) {
251
+ return Object.prototype.hasOwnProperty.call(source, key);
252
+ }
253
+ `;
254
+ const VUE_NAMED_SLOT_HELPERS = `
255
+ function withSlot(name, vnode) {
256
+ if (!vnode) return vnode;
257
+
258
+ if (typeof vnode === 'string') {
259
+ return h('span', { slot: name, style: 'display: contents' }, vnode);
260
+ }
261
+
262
+ return cloneVNode(vnode, { slot: name });
141
263
  }
142
- function generateVuePropSyncLines(propNames) {
143
- if (propNames.length === 0) return "// no props to sync";
144
- return propNames.map((name) => `el.${name} = props.${name};`).join("\n ");
264
+ `;
265
+ const VUE_MODEL_HELPERS = `
266
+ function readEventPath(event, path) {
267
+ if (!path) return event.detail;
268
+
269
+ let value = event;
270
+ for (const segment of path.split('.')) {
271
+ if (value == null) return undefined;
272
+ value = value[segment];
273
+ }
274
+ return value;
145
275
  }
276
+ `;
146
277
  //#endregion
147
278
  //#region packages/web-c/output-vue-wrapper/src/index.ts
148
279
  function vueWrapper(options = {}) {
149
- var _options$outDir, _options$stripPrefix, _options$dts, _options$globalDts, _options$index;
280
+ var _options$outDir, _options$stripPrefix, _options$dts, _options$globalDts, _options$index, _options$wrapper;
150
281
  const normalized = {
151
282
  outDir: (_options$outDir = options.outDir) !== null && _options$outDir !== void 0 ? _options$outDir : "vue",
152
283
  stripPrefix: (_options$stripPrefix = options.stripPrefix) !== null && _options$stripPrefix !== void 0 ? _options$stripPrefix : false,
153
284
  fileName: options.fileName,
154
- dts: (_options$dts = options.dts) !== null && _options$dts !== void 0 ? _options$dts : "auto",
155
- globalDts: (_options$globalDts = options.globalDts) !== null && _options$globalDts !== void 0 ? _options$globalDts : "auto",
156
- index: (_options$index = options.index) !== null && _options$index !== void 0 ? _options$index : true
285
+ dts: (_options$dts = options.dts) !== null && _options$dts !== void 0 ? _options$dts : true,
286
+ globalDts: (_options$globalDts = options.globalDts) !== null && _options$globalDts !== void 0 ? _options$globalDts : true,
287
+ index: (_options$index = options.index) !== null && _options$index !== void 0 ? _options$index : true,
288
+ wrapper: (_options$wrapper = options.wrapper) !== null && _options$wrapper !== void 0 ? _options$wrapper : "minimal"
157
289
  };
158
290
  return {
159
291
  name: "zeus-output-vue-wrapper",
@@ -173,7 +305,8 @@ function vueWrapper(options = {}) {
173
305
  fileName: ctx.outputs.join("vue", ctx.outputs.getFileName("vue", component.tag)),
174
306
  code: generateVueWrapper({
175
307
  component,
176
- wcModuleId: `zeus:wc:${component.tag}`
308
+ wcModuleId: `zeus:wc:${component.tag}`,
309
+ mode: normalized.wrapper
177
310
  })
178
311
  });
179
312
  if (normalized.index) modules.push({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeus-js/output-vue-wrapper",
3
- "version": "0.1.0-beta.2",
3
+ "version": "0.1.0-beta.4",
4
4
  "description": "Zeus Vue wrapper output plugin",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -13,14 +13,14 @@
13
13
  "exports": {
14
14
  ".": {
15
15
  "types": "./dist/output-vue-wrapper.d.ts",
16
+ "module": "./dist/output-vue-wrapper.esm-bundler.js",
17
+ "import": "./dist/output-vue-wrapper.esm-bundler.js",
18
+ "require": "./index.js",
16
19
  "node": {
17
20
  "production": "./dist/output-vue-wrapper.cjs.prod.js",
18
21
  "development": "./dist/output-vue-wrapper.cjs.js",
19
22
  "default": "./index.js"
20
- },
21
- "module": "./dist/output-vue-wrapper.esm-bundler.js",
22
- "import": "./dist/output-vue-wrapper.esm-bundler.js",
23
- "require": "./index.js"
23
+ }
24
24
  }
25
25
  },
26
26
  "sideEffects": false,
@@ -36,9 +36,9 @@
36
36
  ]
37
37
  },
38
38
  "dependencies": {
39
- "@zeus-js/component-dts": "0.1.0-beta.2",
40
- "@zeus-js/component-analyzer": "0.1.0-beta.2",
41
- "@zeus-js/bundler-plugin": "0.1.0-beta.2"
39
+ "@zeus-js/bundler-plugin": "0.1.0-beta.4",
40
+ "@zeus-js/component-dts": "0.1.0-beta.4",
41
+ "@zeus-js/component-analyzer": "0.1.0-beta.4"
42
42
  },
43
43
  "peerDependencies": {
44
44
  "vue": ">=3"