@zeus-js/output-vue-wrapper 0.1.0-beta.4 → 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.4
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 = [];
@@ -23,7 +24,7 @@ function generateVueIndex(components, options) {
23
24
  //#region packages/web-c/output-vue-wrapper/src/generateVueWrapper.ts
24
25
  function generateVueWrapper(input) {
25
26
  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
+ 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);
27
28
  }
28
29
  function generateMinimalVueWrapper(input) {
29
30
  const { component, wcModuleId } = input;
@@ -224,6 +225,42 @@ function generateVueProps(component) {
224
225
  return `${JSON.stringify(name)}: ${toVuePropOption(prop)}`;
225
226
  }).join(",\n ");
226
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
+ }
227
264
  function toVuePropOption(prop) {
228
265
  var _typeMap$prop$type;
229
266
  return `{ type: ${(_typeMap$prop$type = {
@@ -279,6 +316,109 @@ function readEventPath(event, path) {
279
316
  }
280
317
  `;
281
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
+ }
421
+ //#endregion
282
422
  //#region packages/web-c/output-vue-wrapper/src/index.ts
283
423
  function vueWrapper(options = {}) {
284
424
  var _options$outDir, _options$stripPrefix, _options$dts, _options$globalDts, _options$index, _options$wrapper;
@@ -289,7 +429,7 @@ function vueWrapper(options = {}) {
289
429
  dts: (_options$dts = options.dts) !== null && _options$dts !== void 0 ? _options$dts : true,
290
430
  globalDts: (_options$globalDts = options.globalDts) !== null && _options$globalDts !== void 0 ? _options$globalDts : true,
291
431
  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"
432
+ wrapper: (_options$wrapper = options.wrapper) !== null && _options$wrapper !== void 0 ? _options$wrapper : "runtime"
293
433
  };
294
434
  return {
295
435
  name: "zeus-output-vue-wrapper",
@@ -338,3 +478,4 @@ function vueWrapper(options = {}) {
338
478
  }
339
479
  //#endregion
340
480
  exports.default = vueWrapper;
481
+ exports.defineContainer = defineContainer;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * output-vue-wrapper v0.1.0-beta.4
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 = [];
@@ -23,7 +24,7 @@ function generateVueIndex(components, options) {
23
24
  //#region packages/web-c/output-vue-wrapper/src/generateVueWrapper.ts
24
25
  function generateVueWrapper(input) {
25
26
  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
+ 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);
27
28
  }
28
29
  function generateMinimalVueWrapper(input) {
29
30
  const { component, wcModuleId } = input;
@@ -224,6 +225,42 @@ function generateVueProps(component) {
224
225
  return `${JSON.stringify(name)}: ${toVuePropOption(prop)}`;
225
226
  }).join(",\n ");
226
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
+ }
227
264
  function toVuePropOption(prop) {
228
265
  var _typeMap$prop$type;
229
266
  return `{ type: ${(_typeMap$prop$type = {
@@ -279,6 +316,109 @@ function readEventPath(event, path) {
279
316
  }
280
317
  `;
281
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
+ }
421
+ //#endregion
282
422
  //#region packages/web-c/output-vue-wrapper/src/index.ts
283
423
  function vueWrapper(options = {}) {
284
424
  var _options$outDir, _options$stripPrefix, _options$dts, _options$globalDts, _options$index, _options$wrapper;
@@ -289,7 +429,7 @@ function vueWrapper(options = {}) {
289
429
  dts: (_options$dts = options.dts) !== null && _options$dts !== void 0 ? _options$dts : true,
290
430
  globalDts: (_options$globalDts = options.globalDts) !== null && _options$globalDts !== void 0 ? _options$globalDts : true,
291
431
  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"
432
+ wrapper: (_options$wrapper = options.wrapper) !== null && _options$wrapper !== void 0 ? _options$wrapper : "runtime"
293
433
  };
294
434
  return {
295
435
  name: "zeus-output-vue-wrapper",
@@ -338,3 +478,4 @@ function vueWrapper(options = {}) {
338
478
  }
339
479
  //#endregion
340
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 };
@@ -1,10 +1,11 @@
1
1
  /**
2
- * output-vue-wrapper v0.1.0-beta.4
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 = [];
@@ -19,7 +20,7 @@ function generateVueIndex(components, options) {
19
20
  //#region packages/web-c/output-vue-wrapper/src/generateVueWrapper.ts
20
21
  function generateVueWrapper(input) {
21
22
  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
+ 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);
23
24
  }
24
25
  function generateMinimalVueWrapper(input) {
25
26
  const { component, wcModuleId } = input;
@@ -220,6 +221,42 @@ function generateVueProps(component) {
220
221
  return `${JSON.stringify(name)}: ${toVuePropOption(prop)}`;
221
222
  }).join(",\n ");
222
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
+ }
223
260
  function toVuePropOption(prop) {
224
261
  var _typeMap$prop$type;
225
262
  return `{ type: ${(_typeMap$prop$type = {
@@ -275,6 +312,109 @@ function readEventPath(event, path) {
275
312
  }
276
313
  `;
277
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
+ }
417
+ //#endregion
278
418
  //#region packages/web-c/output-vue-wrapper/src/index.ts
279
419
  function vueWrapper(options = {}) {
280
420
  var _options$outDir, _options$stripPrefix, _options$dts, _options$globalDts, _options$index, _options$wrapper;
@@ -285,7 +425,7 @@ function vueWrapper(options = {}) {
285
425
  dts: (_options$dts = options.dts) !== null && _options$dts !== void 0 ? _options$dts : true,
286
426
  globalDts: (_options$globalDts = options.globalDts) !== null && _options$globalDts !== void 0 ? _options$globalDts : true,
287
427
  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"
428
+ wrapper: (_options$wrapper = options.wrapper) !== null && _options$wrapper !== void 0 ? _options$wrapper : "runtime"
289
429
  };
290
430
  return {
291
431
  name: "zeus-output-vue-wrapper",
@@ -333,4 +473,4 @@ function vueWrapper(options = {}) {
333
473
  };
334
474
  }
335
475
  //#endregion
336
- 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;
@@ -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;
@@ -0,0 +1,26 @@
1
+ import * as vue from 'vue';
2
+
3
+ export interface ZeusVueModelOptions {
4
+ prop: string;
5
+ event: string | string[];
6
+ eventPath?: string;
7
+ }
8
+ export interface ZeusVueContainerOptions {
9
+ tagName: string;
10
+ displayName?: string;
11
+ defineCustomElement?: () => void;
12
+ props?: string[];
13
+ events?: string[];
14
+ slots?: string[];
15
+ model?: ZeusVueModelOptions;
16
+ transformTag?: (tagName: string) => string;
17
+ }
18
+ export declare function defineContainer(options: ZeusVueContainerOptions): vue.DefineSetupFnComponent<{
19
+ [x: string]: /*elided*/ any;
20
+ }, string[], {}, {
21
+ [x: string]: /*elided*/ any;
22
+ } & {
23
+ [x: `on${Capitalize<string>}`]: ((...args: any[]) => any) | undefined;
24
+ }, vue.PublicProps>;
25
+
26
+
@@ -0,0 +1,110 @@
1
+ /**
2
+ * output-vue-wrapper v0.1.0-beta.5
3
+ * (c) 2026 baicie
4
+ * Released under the MIT License.
5
+ **/
6
+ import { cloneVNode, defineComponent, h, onBeforeUnmount, onMounted, ref, withDirectives } from "vue";
7
+ //#region packages/web-c/output-vue-wrapper/src/runtime/defineContainer.ts
8
+ const EMPTY_PROP = Symbol();
9
+ const DEFAULT_EMPTY_PROP = { default: EMPTY_PROP };
10
+ const UPDATE_MODEL_VALUE_EVENT = "update:modelValue";
11
+ const MODEL_VALUE = "modelValue";
12
+ function defineContainer(options) {
13
+ const { tagName, displayName, defineCustomElement, props: componentProps = [], events: emitProps = [], slots: slotNames = [], model, transformTag } = options;
14
+ defineCustomElement === null || defineCustomElement === void 0 || defineCustomElement();
15
+ const emits = [...emitProps];
16
+ const componentPropsMap = {};
17
+ for (const prop of componentProps) componentPropsMap[prop] = DEFAULT_EMPTY_PROP;
18
+ if (model) {
19
+ const updateEvent = getModelUpdateEvent(model.prop);
20
+ emits.push(updateEvent);
21
+ if (updateEvent !== UPDATE_MODEL_VALUE_EVENT) emits.push(UPDATE_MODEL_VALUE_EVENT);
22
+ componentPropsMap[MODEL_VALUE] = DEFAULT_EMPTY_PROP;
23
+ }
24
+ return defineComponent((propsValue, { attrs, slots: allSlots, emit }) => {
25
+ const containerRef = ref();
26
+ const listeners = [];
27
+ onMounted(() => {
28
+ const el = containerRef.value;
29
+ if (!el) return;
30
+ for (const eventName of emitProps) {
31
+ const listener = (event) => {
32
+ emit(eventName, event);
33
+ };
34
+ el.addEventListener(eventName, listener);
35
+ listeners.push({
36
+ eventName,
37
+ listener
38
+ });
39
+ }
40
+ });
41
+ onBeforeUnmount(() => {
42
+ const el = containerRef.value;
43
+ if (!el) return;
44
+ for (const item of listeners) el.removeEventListener(item.eventName, item.listener);
45
+ listeners.length = 0;
46
+ });
47
+ const vModelDirective = { created: (el) => {
48
+ if (!model) return;
49
+ for (const eventName of toArray(model.event)) el.addEventListener(eventName, (event) => {
50
+ var _model$eventPath;
51
+ if (event.target.tagName !== el.tagName) return;
52
+ const value = readEventPath(event, (_model$eventPath = model.eventPath) !== null && _model$eventPath !== void 0 ? _model$eventPath : `target.${model.prop}`);
53
+ emit(getModelUpdateEvent(model.prop), value);
54
+ if (propsValue[MODEL_VALUE] !== EMPTY_PROP) emit(UPDATE_MODEL_VALUE_EVENT, value);
55
+ });
56
+ } };
57
+ return () => {
58
+ const propsToAdd = { ref: containerRef };
59
+ for (const key in propsValue) {
60
+ const value = propsValue[key];
61
+ if (value !== EMPTY_PROP) propsToAdd[key] = value;
62
+ }
63
+ for (const key in attrs) propsToAdd[key] = attrs[key];
64
+ if (model) {
65
+ const modelValue = propsValue[MODEL_VALUE];
66
+ const modelPropValue = propsValue[model.prop];
67
+ if (modelValue !== EMPTY_PROP) propsToAdd[model.prop] = modelValue;
68
+ else if (modelPropValue !== EMPTY_PROP) propsToAdd[model.prop] = modelPropValue;
69
+ }
70
+ const children = createChildren(allSlots, slotNames);
71
+ const node = h(transformTag ? transformTag(tagName) : tagName, propsToAdd, children);
72
+ return model ? withDirectives(node, [[vModelDirective]]) : node;
73
+ };
74
+ }, {
75
+ name: displayName !== null && displayName !== void 0 ? displayName : tagName,
76
+ props: componentPropsMap,
77
+ emits
78
+ });
79
+ }
80
+ function createChildren(slots, slotNames) {
81
+ const children = slots.default ? slots.default() : [];
82
+ for (const name of slotNames) {
83
+ const slot = slots[name];
84
+ if (!slot) continue;
85
+ for (const vnode of slot()) children.push(withSlot(name, vnode));
86
+ }
87
+ return children;
88
+ }
89
+ function withSlot(name, vnode) {
90
+ if (!vnode) return vnode;
91
+ if (typeof vnode === "string") return h("span", {
92
+ slot: name,
93
+ style: "display: contents"
94
+ }, vnode);
95
+ return cloneVNode(vnode, { slot: name });
96
+ }
97
+ function getModelUpdateEvent(prop) {
98
+ return `update:${prop}`;
99
+ }
100
+ function toArray(value) {
101
+ return Array.isArray(value) ? value : [value];
102
+ }
103
+ function readEventPath(event, path) {
104
+ return path.split(".").reduce((value, key) => {
105
+ if (value == null) return void 0;
106
+ return value[key];
107
+ }, event);
108
+ }
109
+ //#endregion
110
+ export { defineContainer };
@@ -0,0 +1,110 @@
1
+ /**
2
+ * output-vue-wrapper v0.1.0-beta.5
3
+ * (c) 2026 baicie
4
+ * Released under the MIT License.
5
+ **/
6
+ import { cloneVNode, defineComponent, h, onBeforeUnmount, onMounted, ref, withDirectives } from "vue";
7
+ //#region packages/web-c/output-vue-wrapper/src/runtime/defineContainer.ts
8
+ const EMPTY_PROP = Symbol();
9
+ const DEFAULT_EMPTY_PROP = { default: EMPTY_PROP };
10
+ const UPDATE_MODEL_VALUE_EVENT = "update:modelValue";
11
+ const MODEL_VALUE = "modelValue";
12
+ function defineContainer(options) {
13
+ const { tagName, displayName, defineCustomElement, props: componentProps = [], events: emitProps = [], slots: slotNames = [], model, transformTag } = options;
14
+ defineCustomElement === null || defineCustomElement === void 0 || defineCustomElement();
15
+ const emits = [...emitProps];
16
+ const componentPropsMap = {};
17
+ for (const prop of componentProps) componentPropsMap[prop] = DEFAULT_EMPTY_PROP;
18
+ if (model) {
19
+ const updateEvent = getModelUpdateEvent(model.prop);
20
+ emits.push(updateEvent);
21
+ if (updateEvent !== UPDATE_MODEL_VALUE_EVENT) emits.push(UPDATE_MODEL_VALUE_EVENT);
22
+ componentPropsMap[MODEL_VALUE] = DEFAULT_EMPTY_PROP;
23
+ }
24
+ return defineComponent((propsValue, { attrs, slots: allSlots, emit }) => {
25
+ const containerRef = ref();
26
+ const listeners = [];
27
+ onMounted(() => {
28
+ const el = containerRef.value;
29
+ if (!el) return;
30
+ for (const eventName of emitProps) {
31
+ const listener = (event) => {
32
+ emit(eventName, event);
33
+ };
34
+ el.addEventListener(eventName, listener);
35
+ listeners.push({
36
+ eventName,
37
+ listener
38
+ });
39
+ }
40
+ });
41
+ onBeforeUnmount(() => {
42
+ const el = containerRef.value;
43
+ if (!el) return;
44
+ for (const item of listeners) el.removeEventListener(item.eventName, item.listener);
45
+ listeners.length = 0;
46
+ });
47
+ const vModelDirective = { created: (el) => {
48
+ if (!model) return;
49
+ for (const eventName of toArray(model.event)) el.addEventListener(eventName, (event) => {
50
+ var _model$eventPath;
51
+ if (event.target.tagName !== el.tagName) return;
52
+ const value = readEventPath(event, (_model$eventPath = model.eventPath) !== null && _model$eventPath !== void 0 ? _model$eventPath : `target.${model.prop}`);
53
+ emit(getModelUpdateEvent(model.prop), value);
54
+ if (propsValue[MODEL_VALUE] !== EMPTY_PROP) emit(UPDATE_MODEL_VALUE_EVENT, value);
55
+ });
56
+ } };
57
+ return () => {
58
+ const propsToAdd = { ref: containerRef };
59
+ for (const key in propsValue) {
60
+ const value = propsValue[key];
61
+ if (value !== EMPTY_PROP) propsToAdd[key] = value;
62
+ }
63
+ for (const key in attrs) propsToAdd[key] = attrs[key];
64
+ if (model) {
65
+ const modelValue = propsValue[MODEL_VALUE];
66
+ const modelPropValue = propsValue[model.prop];
67
+ if (modelValue !== EMPTY_PROP) propsToAdd[model.prop] = modelValue;
68
+ else if (modelPropValue !== EMPTY_PROP) propsToAdd[model.prop] = modelPropValue;
69
+ }
70
+ const children = createChildren(allSlots, slotNames);
71
+ const node = h(transformTag ? transformTag(tagName) : tagName, propsToAdd, children);
72
+ return model ? withDirectives(node, [[vModelDirective]]) : node;
73
+ };
74
+ }, {
75
+ name: displayName !== null && displayName !== void 0 ? displayName : tagName,
76
+ props: componentPropsMap,
77
+ emits
78
+ });
79
+ }
80
+ function createChildren(slots, slotNames) {
81
+ const children = slots.default ? slots.default() : [];
82
+ for (const name of slotNames) {
83
+ const slot = slots[name];
84
+ if (!slot) continue;
85
+ for (const vnode of slot()) children.push(withSlot(name, vnode));
86
+ }
87
+ return children;
88
+ }
89
+ function withSlot(name, vnode) {
90
+ if (!vnode) return vnode;
91
+ if (typeof vnode === "string") return h("span", {
92
+ slot: name,
93
+ style: "display: contents"
94
+ }, vnode);
95
+ return cloneVNode(vnode, { slot: name });
96
+ }
97
+ function getModelUpdateEvent(prop) {
98
+ return `update:${prop}`;
99
+ }
100
+ function toArray(value) {
101
+ return Array.isArray(value) ? value : [value];
102
+ }
103
+ function readEventPath(event, path) {
104
+ return path.split(".").reduce((value, key) => {
105
+ if (value == null) return void 0;
106
+ return value[key];
107
+ }, event);
108
+ }
109
+ //#endregion
110
+ export { defineContainer };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeus-js/output-vue-wrapper",
3
- "version": "0.1.0-beta.4",
3
+ "version": "0.1.0-beta.5",
4
4
  "description": "Zeus Vue wrapper output plugin",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -21,6 +21,11 @@
21
21
  "development": "./dist/output-vue-wrapper.cjs.js",
22
22
  "default": "./index.js"
23
23
  }
24
+ },
25
+ "./runtime": {
26
+ "types": "./dist/runtime/index.d.ts",
27
+ "import": "./dist/runtime/index.js",
28
+ "require": "./dist/runtime/index.cjs.js"
24
29
  }
25
30
  },
26
31
  "sideEffects": false,
@@ -33,12 +38,18 @@
33
38
  "formats": [
34
39
  "esm-bundler",
35
40
  "cjs"
41
+ ],
42
+ "additionalEntries": [
43
+ {
44
+ "entry": "runtime/index.ts",
45
+ "output": "dist/runtime/index.js"
46
+ }
36
47
  ]
37
48
  },
38
49
  "dependencies": {
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"
50
+ "@zeus-js/bundler-plugin": "0.1.0-beta.5",
51
+ "@zeus-js/component-dts": "0.1.0-beta.5",
52
+ "@zeus-js/component-analyzer": "0.1.0-beta.5"
42
53
  },
43
54
  "peerDependencies": {
44
55
  "vue": ">=3"