@sprlab/wccompiler 0.8.5 → 0.8.8

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,51 +1,32 @@
1
1
  /**
2
- * Angular adapter for WCC defineModel — enables [(propName)] two-way binding.
2
+ * Angular adapter for WCC defineModel (OPTIONAL).
3
3
  *
4
- * Import this ONCE in your Angular app's main.ts:
5
- * import '@sprlab/wccompiler/adapters/angular'
4
+ * The WCC component already emits `propNameChange` directly from _modelSet,
5
+ * so Angular's [(prop)] banana-box syntax works WITHOUT this adapter.
6
6
  *
7
- * What it does:
8
- * 1. Translates wcc:model events propNameChange (enables [(prop)] syntax)
9
- * 2. Uses queueMicrotask to defer event emission outside Angular's render cycle
10
- * (prevents NG0600: "Writing to signals is not allowed while Angular renders")
7
+ * This file is kept for:
8
+ * 1. Documentation of the Angular integration approach
9
+ * 2. The ControlValueAccessor guide for ngModel support
10
+ *
11
+ * Setup (Angular):
12
+ * // No adapter import needed! Just use CUSTOM_ELEMENTS_SCHEMA:
13
+ * import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'
14
+ * @Component({ schemas: [CUSTOM_ELEMENTS_SCHEMA] })
11
15
  *
12
16
  * Usage:
13
- * <!-- In Angular template (with CUSTOM_ELEMENTS_SCHEMA) -->
14
17
  * <wcc-input [(value)]="text"></wcc-input>
15
18
  * <wcc-counter [(count)]="myCount"></wcc-counter>
16
19
  *
17
- * For ngModel support, you need a ControlValueAccessor.
18
- * See the exported WccValueAccessor class below.
20
+ * How it works:
21
+ * Angular's [(prop)] expands to [prop]="value" (propChange)="value = $event.detail"
22
+ * WCC _modelSet emits propNameChange CustomEvent with detail=newValue
23
+ * Angular picks it up automatically — no adapter needed.
19
24
  *
20
25
  * @module @sprlab/wccompiler/adapters/angular
21
26
  */
22
27
 
23
- // ── Document-level adapter: wcc:model → propNameChange ──────────────
24
- // Angular's [(prop)] syntax listens for `propChange` events.
25
- // Uses queueMicrotask to defer the re-dispatch outside Angular's synchronous
26
- // render cycle, preventing NG0600 errors when Angular is mid-render.
27
-
28
- if (typeof document !== 'undefined') {
29
- document.addEventListener('wcc:model', (e) => {
30
- const { prop, value } = e.detail;
31
- const target = e.target;
32
-
33
- // Defer to next microtask to avoid NG0600
34
- // (Angular doesn't allow signal writes during render)
35
- queueMicrotask(() => {
36
- target.dispatchEvent(new CustomEvent(`${prop}Change`, {
37
- detail: value,
38
- bubbles: true
39
- }));
40
- });
41
- });
42
- }
43
-
44
28
  // ── ControlValueAccessor for ngModel/ReactiveForms ──────────────────
45
29
  // Angular's ngModel requires a ControlValueAccessor to bridge form controls.
46
- // Since this is a JS file (not TypeScript with decorators), we export the
47
- // implementation as a guide. Users need to create a TypeScript directive.
48
- //
49
30
  // Copy this into your Angular project as a .ts file:
50
31
  //
51
32
  // ```ts
@@ -67,7 +48,6 @@ if (typeof document !== 'undefined') {
67
48
  // constructor(private el: ElementRef<HTMLElement>) {}
68
49
  //
69
50
  // writeValue(value: any): void {
70
- // // Parent → Child: set attribute
71
51
  // if (value != null) {
72
52
  // this.el.nativeElement.setAttribute('value', String(value));
73
53
  // } else {
@@ -96,9 +76,3 @@ if (typeof document !== 'undefined') {
96
76
  // }
97
77
  // }
98
78
  // ```
99
- //
100
- // Usage with ngModel:
101
- // <wcc-input wccModel [(ngModel)]="text"></wcc-input>
102
- //
103
- // Usage with Reactive Forms:
104
- // <wcc-input wccModel [formControl]="myControl"></wcc-input>
package/adapters/vue.js CHANGED
@@ -1,69 +1,30 @@
1
1
  /**
2
- * Vue adapter for WCC defineModel — enables v-model and multi-model binding.
2
+ * Vue adapter for WCC defineModel (OPTIONAL only needed without wccVuePlugin).
3
3
  *
4
- * Setup (ONE line in main.js):
5
- * import { createApp } from 'vue'
6
- * import { wccVue } from '@sprlab/wccompiler/adapters/vue'
7
- *
8
- * const app = createApp(App)
9
- * app.use(wccVue) // registers adapter + v-wcc-model directive globally
10
- * app.mount('#app')
11
- *
12
- * IMPORTANT: Also use wccVuePlugin() in vite.config.js to enable v-model:propName
13
- * on custom elements (via AST nodeTransform):
14
- * import { wccVuePlugin } from '@sprlab/wccompiler/integrations/vue'
15
- * export default { plugins: [wccVuePlugin()] }
4
+ * If you use wccVuePlugin() in vite.config.js, you DON'T need this adapter.
5
+ * The plugin handles v-model:propName transformation at build time.
16
6
  *
17
- * With both configured, you can use:
18
- * <!-- Native v-model:propName (preferred, requires wccVuePlugin) -->
19
- * <wcc-input v-model:value="text"></wcc-input>
20
- * <wcc-form v-model:count="countRef" v-model:title="titleRef"></wcc-form>
7
+ * This adapter is for non-Vite setups (webpack, etc.) where you can't use
8
+ * the Vite pre-transform plugin. It provides a Vue directive for two-way binding.
21
9
  *
22
- * <!-- v-model without argument (uses modelValue convention) -->
23
- * <wcc-input v-model="text"></wcc-input>
10
+ * Setup:
11
+ * import { createApp } from 'vue'
12
+ * import { wccVue } from '@sprlab/wccompiler/adapters/vue'
13
+ * app.use(wccVue)
24
14
  *
25
- * <!-- Fallback directive (for non-Vite setups without nodeTransform) -->
15
+ * Usage:
26
16
  * <wcc-input v-wcc-model:value="textRef"></wcc-input>
17
+ * <wcc-form v-wcc-model:count="countRef"></wcc-form>
27
18
  *
28
19
  * @module @sprlab/wccompiler/adapters/vue
29
20
  */
30
21
 
31
- // ── Document-level adapter: wcc:model → update:propName ─────────────
32
- // This enables Vue's native v-model on WCC custom elements.
33
- // Vue v-model on custom elements listens for `update:modelValue` by default.
34
- // The nodeTransform in wccVuePlugin makes v-model:propName listen for `update:propName`.
35
- //
36
- // IMPORTANT: We listen in CAPTURE phase so the update:propName event is dispatched
37
- // BEFORE Vue's own bubble-phase listeners process the element. This ensures Vue
38
- // picks up the translated event synchronously.
39
-
40
- if (typeof document !== 'undefined') {
41
- document.addEventListener('wcc:model', (e) => {
42
- const { prop, value } = e.detail;
43
- // Dispatch update:propName synchronously on the target element.
44
- // bubbles:false because Vue listens directly on the element via addEventListener.
45
- e.target.dispatchEvent(new CustomEvent(`update:${prop}`, {
46
- detail: value,
47
- bubbles: false
48
- }));
49
- }, true); // ← capture phase
50
- }
51
-
52
22
  // ── Vue directive: v-wcc-model ──────────────────────────────────────
53
- // Fallback for non-Vite setups. If using wccVuePlugin(), prefer v-model:propName instead.
54
- //
55
- // Usage:
56
- // <wcc-input v-wcc-model:value="textRef"></wcc-input>
57
- //
58
- // The bound value MUST be a Vue ref (or reactive property).
59
- // The directive writes directly to ref.value for WCC→Vue updates.
23
+ // Fallback for non-Vite setups. Listens for propName-changed events directly.
60
24
 
61
25
  /**
62
26
  * Vue custom directive for two-way binding with WCC defineModel props.
63
- * This is a FALLBACK prefer v-model:propName with wccVuePlugin() nodeTransform.
64
- *
65
- * @example
66
- * <wcc-counter v-wcc-model:count="myCountRef"></wcc-counter>
27
+ * Listens for `propName-changed` CustomEvent (emitted by WCC _modelSet).
67
28
  */
68
29
  export const vWccModel = {
69
30
  mounted(el, binding) {
@@ -74,62 +35,41 @@ export const vWccModel = {
74
35
  }
75
36
 
76
37
  // Set initial value (parent → child)
77
- // Vue sets camelCase attributes, so set both camelCase and kebab-case
78
38
  if (binding.value != null) {
79
39
  el.setAttribute(propName, String(binding.value));
80
40
  }
81
41
 
82
- // Listen for childparent changes
83
- const wccHandler = (e) => {
84
- if (e.detail && e.detail.prop === propName) {
85
- const newValue = e.detail.value;
86
-
87
- // Try to update the Vue ref directly
88
- // In Vue 3, if the binding expression is a ref, binding.value is the ref's current value
89
- // We need to find the ref on the component instance and write to it
90
- const instance = binding.instance;
91
- if (instance) {
92
- // Access the setup state to find the ref
93
- const setupState = instance.$.setupState;
94
- // The binding expression is stored in the directive's internal data
95
- // In Vue 3, we can use the dir's exp to find the variable name
96
- // Fallback: emit a custom event that a parent @update handler can catch
97
- const refName = binding.dir?.__wccRefName?.[el]?.[propName];
98
- if (refName && setupState[refName] !== undefined) {
99
- // Direct ref write
100
- if (setupState[refName]?.value !== undefined) {
101
- setupState[refName].value = newValue;
42
+ // Listen for propName-changed (WCC Vue)
43
+ const kebabName = propName.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();
44
+ const handler = (e) => {
45
+ // Try to update the Vue ref via setupState
46
+ const instance = binding.instance;
47
+ if (instance) {
48
+ const setupState = instance.$.setupState;
49
+ // Find the ref that matches the current binding value
50
+ for (const key of Object.keys(setupState)) {
51
+ const val = setupState[key];
52
+ if (val === binding.value || val?.value === binding.value) {
53
+ if (val?.value !== undefined) {
54
+ val.value = e.detail;
102
55
  } else {
103
- setupState[refName] = newValue;
104
- }
105
- } else {
106
- // Fallback: try to find by matching current value
107
- for (const key of Object.keys(setupState)) {
108
- const val = setupState[key];
109
- if (val?.value === binding.value || val === binding.value) {
110
- if (val?.value !== undefined) {
111
- val.value = newValue;
112
- } else {
113
- setupState[key] = newValue;
114
- }
115
- break;
116
- }
56
+ setupState[key] = e.detail;
117
57
  }
58
+ break;
118
59
  }
119
60
  }
120
61
  }
121
62
  };
122
63
 
123
- el.addEventListener('wcc:model', wccHandler);
64
+ el.addEventListener(`${kebabName}-changed`, handler);
124
65
  el.__wccModelHandlers = el.__wccModelHandlers || {};
125
- el.__wccModelHandlers[propName] = wccHandler;
66
+ el.__wccModelHandlers[propName] = { handler, eventName: `${kebabName}-changed` };
126
67
  },
127
68
 
128
69
  updated(el, binding) {
129
70
  const propName = binding.arg;
130
71
  if (!propName) return;
131
72
 
132
- // Sync parent → child on updates
133
73
  if (binding.value != null) {
134
74
  el.setAttribute(propName, String(binding.value));
135
75
  } else {
@@ -141,27 +81,19 @@ export const vWccModel = {
141
81
  const propName = binding.arg;
142
82
  if (!propName) return;
143
83
 
144
- const handler = el.__wccModelHandlers?.[propName];
145
- if (handler) {
146
- el.removeEventListener('wcc:model', handler);
84
+ const entry = el.__wccModelHandlers?.[propName];
85
+ if (entry) {
86
+ el.removeEventListener(entry.eventName, entry.handler);
147
87
  delete el.__wccModelHandlers[propName];
148
88
  }
149
89
  }
150
90
  };
151
91
 
152
- // ── Vue Plugin: app.use(wccVue) ─────────────────────────────────────
92
+ // ── Vue Plugin ──────────────────────────────────────────────────────
153
93
 
154
94
  /**
155
- * Vue plugin that registers the v-wcc-model directive globally.
156
- * The document-level adapter is registered on import (side-effect above).
157
- *
158
- * @example
159
- * import { createApp } from 'vue'
160
- * import { wccVue } from '@sprlab/wccompiler/adapters/vue'
161
- *
162
- * const app = createApp(App)
163
- * app.use(wccVue)
164
- * app.mount('#app')
95
+ * Vue plugin that registers v-wcc-model directive globally.
96
+ * Only needed if NOT using wccVuePlugin() in vite.config.js.
165
97
  */
166
98
  export const wccVue = {
167
99
  install(app) {
@@ -5,7 +5,7 @@
5
5
  * @module @sprlab/wccompiler/integrations/vue
6
6
  *
7
7
  * IMPORTANT: This file is for vite.config.js (Node.js context).
8
- * For browser-side model adapter, use app.use(wccVue) from '@sprlab/wccompiler/adapters/vue'.
8
+ * For browser-side, use app.use(wccVue) from '@sprlab/wccompiler/adapters/vue'.
9
9
  *
10
10
  * @example vite.config.js
11
11
  * ```js
@@ -13,17 +13,25 @@
13
13
  * export default { plugins: [wccVuePlugin()] }
14
14
  * ```
15
15
  *
16
- * @example main.js (browserenables v-model event translation)
16
+ * @example main.js (optionalonly needed if NOT using wccVuePlugin)
17
17
  * ```js
18
18
  * import { wccVue } from '@sprlab/wccompiler/adapters/vue'
19
19
  * app.use(wccVue)
20
20
  * ```
21
21
  *
22
- * With this plugin, v-model:propName works natively on WCC custom elements:
22
+ * With wccVuePlugin(), v-model:propName works natively on WCC custom elements:
23
23
  * ```vue
24
24
  * <wcc-input v-model="text"></wcc-input>
25
25
  * <wcc-form v-model:count="countRef" v-model:title="titleRef"></wcc-form>
26
26
  * ```
27
+ *
28
+ * How it works:
29
+ * The plugin runs BEFORE @vitejs/plugin-vue and rewrites the template string:
30
+ * v-model:count="expr" → :count="expr" @count-changed="expr = $event.detail"
31
+ * v-model="expr" → :model-value="expr" @model-value-changed="expr = $event.detail"
32
+ *
33
+ * The WCC component emits `propName-changed` CustomEvent with detail=value on internal writes.
34
+ * Vue compiles @propName-changed as a normal event listener (not filtered like update:*).
27
35
  */
28
36
 
29
37
  import vue from '@vitejs/plugin-vue'
@@ -34,115 +42,96 @@ import vue from '@vitejs/plugin-vue'
34
42
  */
35
43
 
36
44
  /**
37
- * AST node transform that enables v-model:propName on custom elements.
38
- *
39
- * Vue's compiler normally doesn't support v-model with arguments on custom elements.
40
- * This transform intercepts v-model:arg directives on custom elements and rewrites them
41
- * to the equivalent :prop + @update:prop binding that Vue understands.
45
+ * Vite plugin that pre-transforms v-model:propName on custom elements
46
+ * before Vue's compiler processes the template.
42
47
  *
43
- * Transforms:
44
- * <wcc-input v-model:value="text" />
45
- * Into the equivalent of:
46
- * <wcc-input :value="text" @update:value="text = $event" />
48
+ * This is necessary because Vue's compiler filters out `onUpdate:*` event listeners
49
+ * for custom elements (isModelListener check in patchProp). By rewriting to
50
+ * `@propName-changed`, we use an event name that Vue registers normally.
47
51
  *
48
- * @param {object} node - Vue compiler AST node
49
- * @param {object} context - Vue compiler transform context
52
+ * @param {WccVuePluginOptions} [options]
53
+ * @returns {import('vite').Plugin[]}
50
54
  */
51
- function wccVModelTransform(node, context) {
52
- // Only process element nodes (type 1 = ELEMENT)
53
- if (node.type !== 1) return;
55
+ export function wccVuePlugin(options = {}) {
56
+ const prefix = typeof options.prefix === 'string' ? options.prefix : 'wcc-'
54
57
 
55
- // Only process custom elements (tag contains a hyphen)
56
- if (!node.tag.includes('-')) return;
58
+ const preTransformPlugin = {
59
+ name: 'vite-plugin-wcc-vmodel',
60
+ enforce: 'pre',
61
+ transform(code, id) {
62
+ if (!id.endsWith('.vue')) return null
57
63
 
58
- // Find v-model directives with arguments
59
- const newProps = [];
60
- let modified = false;
64
+ let result = code
61
65
 
62
- for (const prop of node.props) {
63
- // Check if this is a v-model directive (with or without argument)
64
- if (
65
- prop.type === 7 && // DIRECTIVE
66
- prop.name === 'model'
67
- ) {
68
- // Determine prop name: explicit arg or default 'modelValue'
69
- const propName = prop.arg ? prop.arg.content : 'modelValue';
70
- const expr = prop.exp;
66
+ // Transform v-model:propName="expr" on custom elements (tags with hyphens)
67
+ // :propName="expr" @propName-changed="expr = $event.detail"
68
+ // Run in a loop to handle multiple v-model on the same element
69
+ let prev = ''
70
+ while (prev !== result) {
71
+ prev = result
72
+ result = result.replace(
73
+ /(<[\w]+-[\w-]*(?:\s[^>]*?)?)\bv-model:(\w+)="([^"]+)"/,
74
+ (match, prefix, prop, expr) => {
75
+ return `${prefix}:${prop}="${expr}" @${prop}-changed="${expr} = $event.detail"`
76
+ }
77
+ )
78
+ }
71
79
 
72
- if (!expr) {
73
- newProps.push(prop);
74
- continue;
80
+ // Transform v-model="expr" (without argument) on custom elements
81
+ // → :model-value="expr" @model-value-changed="expr = $event.detail"
82
+ prev = ''
83
+ while (prev !== result) {
84
+ prev = result
85
+ result = result.replace(
86
+ /(<[\w]+-[\w-]*(?:\s[^>]*?)?)\bv-model="([^"]+)"/,
87
+ (match, prefix, expr) => {
88
+ return `${prefix}:model-value="${expr}" @model-value-changed="${expr} = $event.detail"`
89
+ }
90
+ )
75
91
  }
76
92
 
77
- // Create the arg node (use existing or create for modelValue)
78
- const argNode = prop.arg || {
79
- type: 4, // SIMPLE_EXPRESSION
80
- content: 'modelValue',
81
- isStatic: true,
82
- constType: 3,
83
- loc: prop.loc
84
- };
93
+ // ── Slot transforms ──
94
+ // Transform <template #name>content</template> inside custom elements
95
+ // <div slot="name">content</div>
96
+ // This prevents Vue from intercepting the slot syntax and erroring.
97
+ // The WCC component's runtime slot parser detects slot="name" on regular elements.
85
98
 
86
- // Replace v-model:propName="expr" with:
87
- // :propName="expr" (bind directive)
88
- newProps.push({
89
- type: 7, // DIRECTIVE
90
- name: 'bind',
91
- arg: argNode,
92
- exp: expr,
93
- modifiers: [],
94
- loc: prop.loc
95
- });
99
+ // Handle <template #name>...</template> (shorthand)
100
+ prev = ''
101
+ while (prev !== result) {
102
+ prev = result
103
+ result = result.replace(
104
+ /<template\s+#(\w+)>([\s\S]*?)<\/template>/,
105
+ (match, slotName, content) => {
106
+ return `<div slot="${slotName}">${content}</div>`
107
+ }
108
+ )
109
+ }
96
110
 
97
- // @update:propName="$event => { expr = $event }" (on directive)
98
- newProps.push({
99
- type: 7, // DIRECTIVE
100
- name: 'on',
101
- arg: {
102
- type: 4, // SIMPLE_EXPRESSION
103
- content: `update:${propName}`,
104
- isStatic: true,
105
- constType: 3,
106
- loc: prop.loc
107
- },
108
- exp: {
109
- type: 4, // SIMPLE_EXPRESSION
110
- content: `$event => { ${expr.content} = $event.detail ?? $event }`,
111
- isStatic: false,
112
- constType: 0,
113
- loc: prop.loc
114
- },
115
- modifiers: [],
116
- loc: prop.loc
117
- });
111
+ // Handle <template v-slot:name>...</template> (verbose)
112
+ prev = ''
113
+ while (prev !== result) {
114
+ prev = result
115
+ result = result.replace(
116
+ /<template\s+v-slot:(\w+)>([\s\S]*?)<\/template>/,
117
+ (match, slotName, content) => {
118
+ return `<div slot="${slotName}">${content}</div>`
119
+ }
120
+ )
121
+ }
118
122
 
119
- modified = true;
120
- } else {
121
- newProps.push(prop);
123
+ if (result !== code) return result
124
+ return null
122
125
  }
123
126
  }
124
127
 
125
- if (modified) {
126
- node.props = newProps;
127
- }
128
- }
129
-
130
- /**
131
- * Creates a Vite plugin that configures Vue's template compiler
132
- * to recognize custom elements with the given prefix and enables
133
- * v-model:propName on those elements.
134
- *
135
- * @param {WccVuePluginOptions} [options]
136
- * @returns {import('vite').Plugin}
137
- */
138
- export function wccVuePlugin(options = {}) {
139
- const prefix = typeof options.prefix === 'string' ? options.prefix : 'wcc-'
140
- return vue({
128
+ const vuePlugin = vue({
141
129
  template: {
142
130
  compilerOptions: {
143
- isCustomElement: (tag) => tag.startsWith(prefix),
144
- nodeTransforms: [wccVModelTransform]
131
+ isCustomElement: (tag) => tag.startsWith(prefix)
145
132
  }
146
133
  }
147
134
  })
135
+
136
+ return [preTransformPlugin, vuePlugin]
148
137
  }
package/lib/codegen.js CHANGED
@@ -1039,6 +1039,11 @@ export function generateComponent(parseResult, options = {}) {
1039
1039
  lines.push(' __slotMap[slotName] = { content: child.innerHTML, propsExpr: attr.value };');
1040
1040
  lines.push(' }');
1041
1041
  lines.push(' }');
1042
+ lines.push(" } else if (child.nodeType === 1 && child.getAttribute('slot')) {");
1043
+ // NEW: regular element with slot="name" (cross-framework support)
1044
+ lines.push(" const slotName = child.getAttribute('slot');");
1045
+ lines.push(" child.removeAttribute('slot');");
1046
+ lines.push(' __slotMap[slotName] = { content: child.outerHTML, propsExpr: \'\' };');
1042
1047
  lines.push(" } else if (child.nodeType === 1 || (child.nodeType === 3 && child.textContent.trim())) {");
1043
1048
  lines.push(' __defaultSlotNodes.push(child);');
1044
1049
  lines.push(' }');
@@ -1664,8 +1669,13 @@ export function generateComponent(parseResult, options = {}) {
1664
1669
  lines.push('');
1665
1670
  }
1666
1671
 
1667
- // _modelSet methods (one per defineModel prop — emits wcc:model on internal write)
1672
+ // _modelSet methods (one per defineModel prop — emits events on internal write)
1673
+ // Emits:
1674
+ // 1. wcc:model — generic event for vanilla JS and WCC-to-WCC binding
1675
+ // 2. propName-changed — for Vue v-model (Vue doesn't filter this name)
1676
+ // 3. propNameChange — for Angular [(prop)] banana-box syntax
1668
1677
  for (const md of modelDefs) {
1678
+ const kebabName = camelToKebab(md.name);
1669
1679
  lines.push(` _modelSet_${md.name}(newVal) {`);
1670
1680
  lines.push(` const oldVal = this._m_${md.name}();`);
1671
1681
  lines.push(` this._m_${md.name}(newVal);`);
@@ -1674,6 +1684,10 @@ export function generateComponent(parseResult, options = {}) {
1674
1684
  lines.push(` bubbles: true,`);
1675
1685
  lines.push(` composed: true`);
1676
1686
  lines.push(` }));`);
1687
+ // Vue: propName-changed (not filtered by Vue's isModelListener)
1688
+ lines.push(` this.dispatchEvent(new CustomEvent('${kebabName}-changed', { detail: newVal, bubbles: true }));`);
1689
+ // Angular: propNameChange (Angular's [(prop)] listens for propChange)
1690
+ lines.push(` this.dispatchEvent(new CustomEvent('${md.name}Change', { detail: newVal, bubbles: true }));`);
1677
1691
  lines.push(' }');
1678
1692
  lines.push('');
1679
1693
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sprlab/wccompiler",
3
- "version": "0.8.5",
3
+ "version": "0.8.8",
4
4
  "description": "Zero-runtime compiler that transforms .wcc single-file components into native web components with signals-based reactivity",
5
5
  "type": "module",
6
6
  "exports": {