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