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

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.3
3
3
  * (c) 2026 baicie
4
4
  * Released under the MIT License.
5
5
  **/
@@ -22,32 +22,96 @@ 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
+ const { mode = "minimal" } = input;
26
+ if (mode === "minimal") return generateMinimalVueWrapper(input);
27
+ return generateEventBridgeVueWrapper(input);
28
+ }
29
+ function generateMinimalVueWrapper(input) {
30
+ const { component, wcModuleId } = input;
31
+ const slotNames = Object.keys(component.slots).filter((name) => name !== "default");
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
+ return `
56
+ import { ${vueImports} } from 'vue';
57
+
58
+ import ${JSON.stringify(wcModuleId)};
59
+
60
+ const NAMED_SLOTS = ${JSON.stringify(slotNames)};
61
+
62
+ export const ${component.name} = defineComponent({
63
+ name: ${JSON.stringify(component.name)},
64
+ inheritAttrs: false,
65
+
66
+ setup(_props, { attrs, slots }) {
67
+ 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
+ );
81
+ };
82
+ },
83
+ });
84
+ ${withSlotHelper}
85
+ `.trimStart();
86
+ }
87
+ function generateEventBridgeVueWrapper(input) {
25
88
  const { component, wcModuleId } = input;
26
89
  const propNames = Object.keys(component.props);
27
90
  const eventNames = Object.keys(component.events);
28
91
  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`;
92
+ const propInputKeys = createVuePropInputKeys(propNames);
32
93
  return `
33
94
  import {
34
95
  cloneVNode,
35
96
  defineComponent,
97
+ getCurrentInstance,
36
98
  h,
37
99
  onBeforeUnmount,
38
100
  onMounted,
101
+ onUpdated,
39
102
  ref,
40
- watch,
41
103
  } from 'vue';
42
104
 
43
105
  import ${JSON.stringify(wcModuleId)};
44
106
 
45
107
  const PROP_KEYS = ${JSON.stringify(propNames)};
108
+ const PROP_INPUT_KEYS = ${JSON.stringify(propInputKeys)};
46
109
  const EVENT_NAMES = ${JSON.stringify(eventNames)};
47
110
  const NAMED_SLOTS = ${JSON.stringify(slotNames)};
48
111
 
49
112
  export const ${component.name} = defineComponent({
50
113
  name: ${JSON.stringify(component.name)},
114
+ inheritAttrs: false,
51
115
 
52
116
  props: {
53
117
  ${generateVueProps(component)}
@@ -57,13 +121,35 @@ export const ${component.name} = defineComponent({
57
121
 
58
122
  setup(props, { attrs, slots, emit }) {
59
123
  const elRef = ref(null);
124
+ const instance = getCurrentInstance();
60
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];
131
+
132
+ return keys.some(key =>
133
+ Object.prototype.hasOwnProperty.call(rawProps, key),
134
+ );
135
+ };
61
136
 
62
137
  const syncProps = () => {
63
138
  const el = elRef.value;
64
139
  if (!el) return;
65
140
 
66
- ${syncPropsBody}
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)) {
149
+ el[name] = undefined;
150
+ syncedPropKeys.delete(name);
151
+ }
152
+ }
67
153
  };
68
154
 
69
155
  onMounted(() => {
@@ -79,13 +165,14 @@ export const ${component.name} = defineComponent({
79
165
  }
80
166
  });
81
167
 
168
+ onUpdated(syncProps);
169
+
82
170
  onBeforeUnmount(() => {
83
171
  for (const cleanup of cleanups) cleanup();
84
172
  cleanups.length = 0;
173
+ syncedPropKeys.clear();
85
174
  });
86
175
 
87
- ${watchBlock}
88
-
89
176
  return () => {
90
177
  const children = [];
91
178
 
@@ -132,32 +219,33 @@ function generateVueProps(component) {
132
219
  }
133
220
  function toVuePropOption(prop) {
134
221
  var _typeMap$prop$type;
135
- const type = (_typeMap$prop$type = {
222
+ return `{ type: ${(_typeMap$prop$type = {
136
223
  string: "String",
137
224
  number: "Number",
138
225
  boolean: "Boolean",
139
226
  object: "Object",
140
227
  array: "Array",
141
228
  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"} }`;
229
+ }[prop.type]) !== null && _typeMap$prop$type !== void 0 ? _typeMap$prop$type : "null"}, required: ${prop.required === true ? "true" : "false"} }`;
230
+ }
231
+ function createVuePropInputKeys(propNames) {
232
+ return Object.fromEntries(propNames.map((name) => [name, Array.from(new Set([name, toKebabCase(name)]))]));
145
233
  }
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 ");
234
+ function toKebabCase(value) {
235
+ return value.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
149
236
  }
150
237
  //#endregion
151
238
  //#region packages/web-c/output-vue-wrapper/src/index.ts
152
239
  function vueWrapper(options = {}) {
153
- var _options$outDir, _options$stripPrefix, _options$dts, _options$globalDts, _options$index;
240
+ var _options$outDir, _options$stripPrefix, _options$dts, _options$globalDts, _options$index, _options$wrapper;
154
241
  const normalized = {
155
242
  outDir: (_options$outDir = options.outDir) !== null && _options$outDir !== void 0 ? _options$outDir : "vue",
156
243
  stripPrefix: (_options$stripPrefix = options.stripPrefix) !== null && _options$stripPrefix !== void 0 ? _options$stripPrefix : false,
157
244
  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
245
+ dts: (_options$dts = options.dts) !== null && _options$dts !== void 0 ? _options$dts : true,
246
+ globalDts: (_options$globalDts = options.globalDts) !== null && _options$globalDts !== void 0 ? _options$globalDts : true,
247
+ 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"
161
249
  };
162
250
  return {
163
251
  name: "zeus-output-vue-wrapper",
@@ -177,7 +265,8 @@ function vueWrapper(options = {}) {
177
265
  fileName: ctx.outputs.join("vue", ctx.outputs.getFileName("vue", component.tag)),
178
266
  code: generateVueWrapper({
179
267
  component,
180
- wcModuleId: `zeus:wc:${component.tag}`
268
+ wcModuleId: `zeus:wc:${component.tag}`,
269
+ mode: normalized.wrapper
181
270
  })
182
271
  });
183
272
  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.3
3
3
  * (c) 2026 baicie
4
4
  * Released under the MIT License.
5
5
  **/
@@ -22,32 +22,96 @@ 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
+ const { mode = "minimal" } = input;
26
+ if (mode === "minimal") return generateMinimalVueWrapper(input);
27
+ return generateEventBridgeVueWrapper(input);
28
+ }
29
+ function generateMinimalVueWrapper(input) {
30
+ const { component, wcModuleId } = input;
31
+ const slotNames = Object.keys(component.slots).filter((name) => name !== "default");
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
+ return `
56
+ import { ${vueImports} } from 'vue';
57
+
58
+ import ${JSON.stringify(wcModuleId)};
59
+
60
+ const NAMED_SLOTS = ${JSON.stringify(slotNames)};
61
+
62
+ export const ${component.name} = defineComponent({
63
+ name: ${JSON.stringify(component.name)},
64
+ inheritAttrs: false,
65
+
66
+ setup(_props, { attrs, slots }) {
67
+ 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
+ );
81
+ };
82
+ },
83
+ });
84
+ ${withSlotHelper}
85
+ `.trimStart();
86
+ }
87
+ function generateEventBridgeVueWrapper(input) {
25
88
  const { component, wcModuleId } = input;
26
89
  const propNames = Object.keys(component.props);
27
90
  const eventNames = Object.keys(component.events);
28
91
  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`;
92
+ const propInputKeys = createVuePropInputKeys(propNames);
32
93
  return `
33
94
  import {
34
95
  cloneVNode,
35
96
  defineComponent,
97
+ getCurrentInstance,
36
98
  h,
37
99
  onBeforeUnmount,
38
100
  onMounted,
101
+ onUpdated,
39
102
  ref,
40
- watch,
41
103
  } from 'vue';
42
104
 
43
105
  import ${JSON.stringify(wcModuleId)};
44
106
 
45
107
  const PROP_KEYS = ${JSON.stringify(propNames)};
108
+ const PROP_INPUT_KEYS = ${JSON.stringify(propInputKeys)};
46
109
  const EVENT_NAMES = ${JSON.stringify(eventNames)};
47
110
  const NAMED_SLOTS = ${JSON.stringify(slotNames)};
48
111
 
49
112
  export const ${component.name} = defineComponent({
50
113
  name: ${JSON.stringify(component.name)},
114
+ inheritAttrs: false,
51
115
 
52
116
  props: {
53
117
  ${generateVueProps(component)}
@@ -57,13 +121,35 @@ export const ${component.name} = defineComponent({
57
121
 
58
122
  setup(props, { attrs, slots, emit }) {
59
123
  const elRef = ref(null);
124
+ const instance = getCurrentInstance();
60
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];
131
+
132
+ return keys.some(key =>
133
+ Object.prototype.hasOwnProperty.call(rawProps, key),
134
+ );
135
+ };
61
136
 
62
137
  const syncProps = () => {
63
138
  const el = elRef.value;
64
139
  if (!el) return;
65
140
 
66
- ${syncPropsBody}
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)) {
149
+ el[name] = undefined;
150
+ syncedPropKeys.delete(name);
151
+ }
152
+ }
67
153
  };
68
154
 
69
155
  onMounted(() => {
@@ -79,13 +165,14 @@ export const ${component.name} = defineComponent({
79
165
  }
80
166
  });
81
167
 
168
+ onUpdated(syncProps);
169
+
82
170
  onBeforeUnmount(() => {
83
171
  for (const cleanup of cleanups) cleanup();
84
172
  cleanups.length = 0;
173
+ syncedPropKeys.clear();
85
174
  });
86
175
 
87
- ${watchBlock}
88
-
89
176
  return () => {
90
177
  const children = [];
91
178
 
@@ -132,32 +219,33 @@ function generateVueProps(component) {
132
219
  }
133
220
  function toVuePropOption(prop) {
134
221
  var _typeMap$prop$type;
135
- const type = (_typeMap$prop$type = {
222
+ return `{ type: ${(_typeMap$prop$type = {
136
223
  string: "String",
137
224
  number: "Number",
138
225
  boolean: "Boolean",
139
226
  object: "Object",
140
227
  array: "Array",
141
228
  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"} }`;
229
+ }[prop.type]) !== null && _typeMap$prop$type !== void 0 ? _typeMap$prop$type : "null"}, required: ${prop.required === true ? "true" : "false"} }`;
230
+ }
231
+ function createVuePropInputKeys(propNames) {
232
+ return Object.fromEntries(propNames.map((name) => [name, Array.from(new Set([name, toKebabCase(name)]))]));
145
233
  }
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 ");
234
+ function toKebabCase(value) {
235
+ return value.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
149
236
  }
150
237
  //#endregion
151
238
  //#region packages/web-c/output-vue-wrapper/src/index.ts
152
239
  function vueWrapper(options = {}) {
153
- var _options$outDir, _options$stripPrefix, _options$dts, _options$globalDts, _options$index;
240
+ var _options$outDir, _options$stripPrefix, _options$dts, _options$globalDts, _options$index, _options$wrapper;
154
241
  const normalized = {
155
242
  outDir: (_options$outDir = options.outDir) !== null && _options$outDir !== void 0 ? _options$outDir : "vue",
156
243
  stripPrefix: (_options$stripPrefix = options.stripPrefix) !== null && _options$stripPrefix !== void 0 ? _options$stripPrefix : false,
157
244
  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
245
+ dts: (_options$dts = options.dts) !== null && _options$dts !== void 0 ? _options$dts : true,
246
+ globalDts: (_options$globalDts = options.globalDts) !== null && _options$globalDts !== void 0 ? _options$globalDts : true,
247
+ 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"
161
249
  };
162
250
  return {
163
251
  name: "zeus-output-vue-wrapper",
@@ -177,7 +265,8 @@ function vueWrapper(options = {}) {
177
265
  fileName: ctx.outputs.join("vue", ctx.outputs.getFileName("vue", component.tag)),
178
266
  code: generateVueWrapper({
179
267
  component,
180
- wcModuleId: `zeus:wc:${component.tag}`
268
+ wcModuleId: `zeus:wc:${component.tag}`,
269
+ mode: normalized.wrapper
181
270
  })
182
271
  });
183
272
  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.3
3
3
  * (c) 2026 baicie
4
4
  * Released under the MIT License.
5
5
  **/
@@ -18,32 +18,96 @@ 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
+ const { mode = "minimal" } = input;
22
+ if (mode === "minimal") return generateMinimalVueWrapper(input);
23
+ return generateEventBridgeVueWrapper(input);
24
+ }
25
+ function generateMinimalVueWrapper(input) {
26
+ const { component, wcModuleId } = input;
27
+ const slotNames = Object.keys(component.slots).filter((name) => name !== "default");
28
+ const hasNamedSlots = slotNames.length > 0;
29
+ const vueImports = hasNamedSlots ? `cloneVNode, defineComponent, h` : `defineComponent, h`;
30
+ const namedSlotBlock = hasNamedSlots ? `
31
+ for (const name of NAMED_SLOTS) {
32
+ const slot = slots[name];
33
+ if (!slot) continue;
34
+
35
+ for (const vnode of slot()) {
36
+ children.push(withSlot(name, vnode));
37
+ }
38
+ }
39
+ ` : "";
40
+ const withSlotHelper = hasNamedSlots ? `
41
+ function withSlot(name, vnode) {
42
+ if (!vnode) return vnode;
43
+
44
+ if (typeof vnode === 'string') {
45
+ return h('span', { slot: name, style: 'display: contents' }, vnode);
46
+ }
47
+
48
+ return cloneVNode(vnode, { slot: name });
49
+ }
50
+ ` : "";
51
+ return `
52
+ import { ${vueImports} } from 'vue';
53
+
54
+ import ${JSON.stringify(wcModuleId)};
55
+
56
+ const NAMED_SLOTS = ${JSON.stringify(slotNames)};
57
+
58
+ export const ${component.name} = defineComponent({
59
+ name: ${JSON.stringify(component.name)},
60
+ inheritAttrs: false,
61
+
62
+ setup(_props, { attrs, slots }) {
63
+ return () => {
64
+ const children = [];
65
+
66
+ if (slots.default) {
67
+ children.push(...slots.default());
68
+ }
69
+ ${namedSlotBlock}
70
+ return h(
71
+ ${JSON.stringify(component.tag)},
72
+ {
73
+ ...attrs,
74
+ },
75
+ children,
76
+ );
77
+ };
78
+ },
79
+ });
80
+ ${withSlotHelper}
81
+ `.trimStart();
82
+ }
83
+ function generateEventBridgeVueWrapper(input) {
21
84
  const { component, wcModuleId } = input;
22
85
  const propNames = Object.keys(component.props);
23
86
  const eventNames = Object.keys(component.events);
24
87
  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`;
88
+ const propInputKeys = createVuePropInputKeys(propNames);
28
89
  return `
29
90
  import {
30
91
  cloneVNode,
31
92
  defineComponent,
93
+ getCurrentInstance,
32
94
  h,
33
95
  onBeforeUnmount,
34
96
  onMounted,
97
+ onUpdated,
35
98
  ref,
36
- watch,
37
99
  } from 'vue';
38
100
 
39
101
  import ${JSON.stringify(wcModuleId)};
40
102
 
41
103
  const PROP_KEYS = ${JSON.stringify(propNames)};
104
+ const PROP_INPUT_KEYS = ${JSON.stringify(propInputKeys)};
42
105
  const EVENT_NAMES = ${JSON.stringify(eventNames)};
43
106
  const NAMED_SLOTS = ${JSON.stringify(slotNames)};
44
107
 
45
108
  export const ${component.name} = defineComponent({
46
109
  name: ${JSON.stringify(component.name)},
110
+ inheritAttrs: false,
47
111
 
48
112
  props: {
49
113
  ${generateVueProps(component)}
@@ -53,13 +117,35 @@ export const ${component.name} = defineComponent({
53
117
 
54
118
  setup(props, { attrs, slots, emit }) {
55
119
  const elRef = ref(null);
120
+ const instance = getCurrentInstance();
56
121
  const cleanups = [];
122
+ const syncedPropKeys = new Set();
123
+
124
+ const hasRawProp = name => {
125
+ const rawProps = instance?.vnode.props ?? {};
126
+ const keys = PROP_INPUT_KEYS[name] ?? [name];
127
+
128
+ return keys.some(key =>
129
+ Object.prototype.hasOwnProperty.call(rawProps, key),
130
+ );
131
+ };
57
132
 
58
133
  const syncProps = () => {
59
134
  const el = elRef.value;
60
135
  if (!el) return;
61
136
 
62
- ${syncPropsBody}
137
+ for (const name of PROP_KEYS) {
138
+ if (hasRawProp(name)) {
139
+ el[name] = props[name];
140
+ syncedPropKeys.add(name);
141
+ continue;
142
+ }
143
+
144
+ if (syncedPropKeys.has(name)) {
145
+ el[name] = undefined;
146
+ syncedPropKeys.delete(name);
147
+ }
148
+ }
63
149
  };
64
150
 
65
151
  onMounted(() => {
@@ -75,13 +161,14 @@ export const ${component.name} = defineComponent({
75
161
  }
76
162
  });
77
163
 
164
+ onUpdated(syncProps);
165
+
78
166
  onBeforeUnmount(() => {
79
167
  for (const cleanup of cleanups) cleanup();
80
168
  cleanups.length = 0;
169
+ syncedPropKeys.clear();
81
170
  });
82
171
 
83
- ${watchBlock}
84
-
85
172
  return () => {
86
173
  const children = [];
87
174
 
@@ -128,32 +215,33 @@ function generateVueProps(component) {
128
215
  }
129
216
  function toVuePropOption(prop) {
130
217
  var _typeMap$prop$type;
131
- const type = (_typeMap$prop$type = {
218
+ return `{ type: ${(_typeMap$prop$type = {
132
219
  string: "String",
133
220
  number: "Number",
134
221
  boolean: "Boolean",
135
222
  object: "Object",
136
223
  array: "Array",
137
224
  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"} }`;
225
+ }[prop.type]) !== null && _typeMap$prop$type !== void 0 ? _typeMap$prop$type : "null"}, required: ${prop.required === true ? "true" : "false"} }`;
226
+ }
227
+ function createVuePropInputKeys(propNames) {
228
+ return Object.fromEntries(propNames.map((name) => [name, Array.from(new Set([name, toKebabCase(name)]))]));
141
229
  }
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 ");
230
+ function toKebabCase(value) {
231
+ return value.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
145
232
  }
146
233
  //#endregion
147
234
  //#region packages/web-c/output-vue-wrapper/src/index.ts
148
235
  function vueWrapper(options = {}) {
149
- var _options$outDir, _options$stripPrefix, _options$dts, _options$globalDts, _options$index;
236
+ var _options$outDir, _options$stripPrefix, _options$dts, _options$globalDts, _options$index, _options$wrapper;
150
237
  const normalized = {
151
238
  outDir: (_options$outDir = options.outDir) !== null && _options$outDir !== void 0 ? _options$outDir : "vue",
152
239
  stripPrefix: (_options$stripPrefix = options.stripPrefix) !== null && _options$stripPrefix !== void 0 ? _options$stripPrefix : false,
153
240
  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
241
+ dts: (_options$dts = options.dts) !== null && _options$dts !== void 0 ? _options$dts : true,
242
+ globalDts: (_options$globalDts = options.globalDts) !== null && _options$globalDts !== void 0 ? _options$globalDts : true,
243
+ index: (_options$index = options.index) !== null && _options$index !== void 0 ? _options$index : true,
244
+ wrapper: (_options$wrapper = options.wrapper) !== null && _options$wrapper !== void 0 ? _options$wrapper : "minimal"
157
245
  };
158
246
  return {
159
247
  name: "zeus-output-vue-wrapper",
@@ -173,7 +261,8 @@ function vueWrapper(options = {}) {
173
261
  fileName: ctx.outputs.join("vue", ctx.outputs.getFileName("vue", component.tag)),
174
262
  code: generateVueWrapper({
175
263
  component,
176
- wcModuleId: `zeus:wc:${component.tag}`
264
+ wcModuleId: `zeus:wc:${component.tag}`,
265
+ mode: normalized.wrapper
177
266
  })
178
267
  });
179
268
  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.3",
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.3",
40
+ "@zeus-js/component-dts": "0.1.0-beta.3",
41
+ "@zeus-js/component-analyzer": "0.1.0-beta.3"
42
42
  },
43
43
  "peerDependencies": {
44
44
  "vue": ">=3"