@sprlab/wccompiler 0.7.1 → 0.7.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.
- package/README.md +17 -4
- package/integrations/angular.js +38 -21
- package/integrations/react.js +30 -9
- package/lib/codegen.js +6 -2
- package/lib/parser-extractors.js +4 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -656,12 +656,21 @@ export default defineConfig({
|
|
|
656
656
|
|
|
657
657
|
### React
|
|
658
658
|
|
|
659
|
-
React 19+ supports custom elements natively. For React 18, use the event hook:
|
|
659
|
+
React 19+ supports custom elements natively. For React 18, use the event hook to bridge CustomEvents:
|
|
660
660
|
|
|
661
661
|
```jsx
|
|
662
|
+
import { useRef } from 'react'
|
|
662
663
|
import { useWccEvent } from '@sprlab/wccompiler/integrations/react'
|
|
663
664
|
|
|
664
665
|
function App() {
|
|
666
|
+
// Form 1: Pass an existing ref
|
|
667
|
+
const counterRef = useRef(null)
|
|
668
|
+
useWccEvent(counterRef, 'change', (e) => console.log(e.detail))
|
|
669
|
+
return <wcc-counter ref={counterRef}></wcc-counter>
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
// Form 2: Let the hook create the ref
|
|
673
|
+
function App2() {
|
|
665
674
|
const ref = useWccEvent('change', (e) => console.log(e.detail))
|
|
666
675
|
return <wcc-counter ref={ref}></wcc-counter>
|
|
667
676
|
}
|
|
@@ -669,19 +678,23 @@ function App() {
|
|
|
669
678
|
|
|
670
679
|
### Angular
|
|
671
680
|
|
|
681
|
+
Add `CUSTOM_ELEMENTS_SCHEMA` to your component or module — this is Angular's built-in way to allow custom elements:
|
|
682
|
+
|
|
672
683
|
```ts
|
|
673
|
-
import {
|
|
684
|
+
import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'
|
|
674
685
|
|
|
675
686
|
// Standalone component (Angular 17+)
|
|
676
687
|
@Component({
|
|
677
|
-
schemas:
|
|
688
|
+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
678
689
|
template: `<wcc-counter></wcc-counter>`
|
|
679
690
|
})
|
|
691
|
+
export class AppComponent {}
|
|
680
692
|
|
|
681
693
|
// Or NgModule approach
|
|
682
694
|
@NgModule({
|
|
683
|
-
schemas:
|
|
695
|
+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
684
696
|
})
|
|
697
|
+
export class AppModule {}
|
|
685
698
|
```
|
|
686
699
|
|
|
687
700
|
### Vanilla
|
package/integrations/angular.js
CHANGED
|
@@ -1,31 +1,48 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Angular
|
|
3
|
-
* Provides CUSTOM_ELEMENTS_SCHEMA configuration for Angular modules/components.
|
|
2
|
+
* Angular integration guide for WCC custom elements.
|
|
4
3
|
*
|
|
5
4
|
* @module @sprlab/wccompiler/integrations/angular
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Schema array for Angular components/modules that use WCC custom elements.
|
|
12
|
-
* Use in @Component({ schemas: WCC_SCHEMAS }) or @NgModule({ schemas: WCC_SCHEMAS })
|
|
13
5
|
*
|
|
14
|
-
*
|
|
6
|
+
* Angular's AOT compiler requires schemas to be statically analyzable,
|
|
7
|
+
* so we cannot provide a re-exported schema constant that works at compile time.
|
|
8
|
+
* Instead, use Angular's built-in CUSTOM_ELEMENTS_SCHEMA directly:
|
|
9
|
+
*
|
|
10
|
+
* @example Standalone component (Angular 17+)
|
|
11
|
+
* ```ts
|
|
12
|
+
* import { Component } from '@angular/core';
|
|
13
|
+
* import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
|
14
|
+
*
|
|
15
|
+
* @Component({
|
|
16
|
+
* selector: 'app-root',
|
|
17
|
+
* schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
18
|
+
* template: `<wcc-counter></wcc-counter>`
|
|
19
|
+
* })
|
|
20
|
+
* export class AppComponent {}
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* @example NgModule approach
|
|
24
|
+
* ```ts
|
|
25
|
+
* import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
|
26
|
+
*
|
|
27
|
+
* @NgModule({
|
|
28
|
+
* schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
29
|
+
* })
|
|
30
|
+
* export class AppModule {}
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* That's it — one line of config. WCC components work as native custom elements
|
|
34
|
+
* in Angular without any additional wrapper or helper.
|
|
15
35
|
*/
|
|
16
|
-
export const WCC_SCHEMAS = [CUSTOM_ELEMENTS_SCHEMA]
|
|
17
36
|
|
|
18
37
|
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* Usage:
|
|
23
|
-
* @NgModule({ imports: [WccModule] })
|
|
24
|
-
* export class AppModule {}
|
|
38
|
+
* Configuration instructions for Angular projects using WCC components.
|
|
39
|
+
* This is a documentation-only export — Angular's AOT compiler requires
|
|
40
|
+
* CUSTOM_ELEMENTS_SCHEMA to be imported directly from @angular/core.
|
|
25
41
|
*
|
|
26
|
-
*
|
|
27
|
-
* @Component({ schemas: WCC_SCHEMAS })
|
|
42
|
+
* @type {{ schema: string, standalone: string, ngModule: string }}
|
|
28
43
|
*/
|
|
29
|
-
export
|
|
30
|
-
|
|
44
|
+
export const WCC_ANGULAR_CONFIG = {
|
|
45
|
+
schema: "import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'",
|
|
46
|
+
standalone: "@Component({ schemas: [CUSTOM_ELEMENTS_SCHEMA] })",
|
|
47
|
+
ngModule: "@NgModule({ schemas: [CUSTOM_ELEMENTS_SCHEMA] })",
|
|
31
48
|
}
|
package/integrations/react.js
CHANGED
|
@@ -3,6 +3,16 @@
|
|
|
3
3
|
* Bridges CustomEvent to React's ref-based event system.
|
|
4
4
|
*
|
|
5
5
|
* @module @sprlab/wccompiler/integrations/react
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* // Form 1: Pass an existing ref
|
|
9
|
+
* const ref = useRef(null)
|
|
10
|
+
* useWccEvent(ref, 'change', (e) => console.log(e.detail))
|
|
11
|
+
* <wcc-counter ref={ref}></wcc-counter>
|
|
12
|
+
*
|
|
13
|
+
* // Form 2: Let the hook create the ref
|
|
14
|
+
* const ref = useWccEvent('change', (e) => console.log(e.detail))
|
|
15
|
+
* <wcc-counter ref={ref}></wcc-counter>
|
|
6
16
|
*/
|
|
7
17
|
|
|
8
18
|
import { useRef, useEffect } from 'react'
|
|
@@ -10,22 +20,33 @@ import { useRef, useEffect } from 'react'
|
|
|
10
20
|
/**
|
|
11
21
|
* Hook that attaches a CustomEvent listener to a DOM element via ref.
|
|
12
22
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
23
|
+
* Supports two calling conventions:
|
|
24
|
+
* - useWccEvent(ref, eventName, handler) — uses an existing ref
|
|
25
|
+
* - useWccEvent(eventName, handler) — creates and returns a new ref
|
|
26
|
+
*
|
|
27
|
+
* @param {import('react').RefObject<HTMLElement> | string} refOrEventName
|
|
28
|
+
* @param {string | ((event: CustomEvent) => void)} eventNameOrHandler
|
|
29
|
+
* @param {((event: CustomEvent) => void)} [handler]
|
|
30
|
+
* @returns {import('react').RefObject<HTMLElement> | void}
|
|
16
31
|
*/
|
|
17
|
-
export function useWccEvent(
|
|
18
|
-
|
|
19
|
-
const
|
|
20
|
-
|
|
32
|
+
export function useWccEvent(refOrEventName, eventNameOrHandler, handler) {
|
|
33
|
+
// Detect calling convention
|
|
34
|
+
const isRefForm = typeof refOrEventName !== 'string'
|
|
35
|
+
const elementRef = isRefForm ? refOrEventName : useRef(null)
|
|
36
|
+
const eventName = isRefForm ? eventNameOrHandler : refOrEventName
|
|
37
|
+
const callback = isRefForm ? handler : eventNameOrHandler
|
|
38
|
+
|
|
39
|
+
const handlerRef = useRef(callback)
|
|
40
|
+
handlerRef.current = callback
|
|
21
41
|
|
|
22
42
|
useEffect(() => {
|
|
23
|
-
const el =
|
|
43
|
+
const el = elementRef.current
|
|
24
44
|
if (!el) return
|
|
25
45
|
const listener = (e) => handlerRef.current(e)
|
|
26
46
|
el.addEventListener(eventName, listener)
|
|
27
47
|
return () => el.removeEventListener(eventName, listener)
|
|
28
48
|
}, [eventName])
|
|
29
49
|
|
|
30
|
-
return ref
|
|
50
|
+
// Only return ref if we created it (Form 2)
|
|
51
|
+
if (!isRefForm) return elementRef
|
|
31
52
|
}
|
package/lib/codegen.js
CHANGED
|
@@ -1186,7 +1186,9 @@ export function generateComponent(parseResult, options = {}) {
|
|
|
1186
1186
|
lines.push(' this.__disposers.push(__effect(() => {');
|
|
1187
1187
|
lines.push(` const ${w.newParam} = ${watchRef};`);
|
|
1188
1188
|
lines.push(` if (this.__prev_${w.target} !== undefined && this.__prev_${w.target} !== ${w.newParam}) {`);
|
|
1189
|
-
|
|
1189
|
+
if (w.oldParam) {
|
|
1190
|
+
lines.push(` const ${w.oldParam} = this.__prev_${w.target};`);
|
|
1191
|
+
}
|
|
1190
1192
|
lines.push(' __untrack(() => {');
|
|
1191
1193
|
const bodyLines = body.split('\n');
|
|
1192
1194
|
for (const line of bodyLines) {
|
|
@@ -1203,7 +1205,9 @@ export function generateComponent(parseResult, options = {}) {
|
|
|
1203
1205
|
lines.push(' this.__disposers.push(__effect(() => {');
|
|
1204
1206
|
lines.push(` const ${w.newParam} = ${getterExpr};`);
|
|
1205
1207
|
lines.push(` if (this.${prevName} !== undefined && this.${prevName} !== ${w.newParam}) {`);
|
|
1206
|
-
|
|
1208
|
+
if (w.oldParam) {
|
|
1209
|
+
lines.push(` const ${w.oldParam} = this.${prevName};`);
|
|
1210
|
+
}
|
|
1207
1211
|
lines.push(' __untrack(() => {');
|
|
1208
1212
|
const bodyLines2 = body.split('\n');
|
|
1209
1213
|
for (const line of bodyLines2) {
|
package/lib/parser-extractors.js
CHANGED
|
@@ -782,10 +782,10 @@ export function extractWatchers(source) {
|
|
|
782
782
|
while (i < lines.length) {
|
|
783
783
|
const line = lines[i];
|
|
784
784
|
|
|
785
|
-
// Form 2 — Getter function: watch(() => expr, (newVal, oldVal) => {
|
|
786
|
-
const mGetter = line.match(/\bwatch\s*\(\s*\(\)\s*=>\s*(.+?)\s*,\s*\((\w+)
|
|
787
|
-
// Form 1 — Signal direct: watch(identifier, (newVal, oldVal) => {
|
|
788
|
-
const mSignal = !mGetter ? line.match(/\bwatch\s*\(\s*(\w+)\s*,\s*\((\w+)
|
|
785
|
+
// Form 2 — Getter function: watch(() => expr, (newVal, oldVal) => { OR watch(() => expr, (newVal) => {
|
|
786
|
+
const mGetter = line.match(/\bwatch\s*\(\s*\(\)\s*=>\s*(.+?)\s*,\s*\((\w+)(?:\s*,\s*(\w+))?\)\s*=>\s*\{/);
|
|
787
|
+
// Form 1 — Signal direct: watch(identifier, (newVal, oldVal) => { OR watch(identifier, (newVal) => {
|
|
788
|
+
const mSignal = !mGetter ? line.match(/\bwatch\s*\(\s*(\w+)\s*,\s*\((\w+)(?:\s*,\s*(\w+))?\)\s*=>\s*\{/) : null;
|
|
789
789
|
|
|
790
790
|
const m = mGetter || mSignal;
|
|
791
791
|
|
package/package.json
CHANGED