@junnyontop-pixel/neo-app 1.1.6 → 1.1.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.
package/compiler/index.js CHANGED
@@ -14,38 +14,38 @@ if (!inputFile) {
14
14
  const source = fs.readFileSync(inputFile, 'utf8');
15
15
  const { root, scriptContent } = NeoParser.parse(source);
16
16
 
17
+ // compiler/index.js 내부 generateCode 함수 수정
18
+
17
19
  function generateCode(node, indent = " ") {
18
- // 자식 노드들을 재귀적으로 호출하며 들여쓰기를 한 단계 더 깊게(indent + " ") 적용합니다.
19
20
  const childrenCode = node.children
20
21
  .map(child => generateCode(child, indent + " "))
21
22
  .join(',\n');
22
23
 
23
- // 이벤트 처리 로직 (보내주신 로직 유지)
24
24
  const eventProps = {};
25
25
  for (const [evt, action] of Object.entries(node.events)) {
26
26
  const propName = `on${evt.charAt(0).toUpperCase() + evt.slice(1)}`;
27
27
  let processedAction = action;
28
28
 
29
- // 단순 연산(++) 대응
30
29
  if (action.includes('++')) processedAction = `state.${action}`;
31
30
 
32
- // 괄호 자동 보정
33
31
  if (processedAction.includes('(') && !processedAction.includes(')')) {
34
32
  processedAction += ')';
35
33
  }
36
- eventProps[propName] = `() => { ${processedAction}; renderApp(); }`; // renderApp() 호출 추가로 화면 갱신 유도
34
+ // Proxy가 있으므로 renderApp() 호출은 빼도 됩니다.
35
+ eventProps[propName] = `() => { ${processedAction} }`;
37
36
  }
38
37
 
39
38
  const eventString = Object.entries(eventProps)
40
39
  .map(([k, v]) => `${k}: ${v}`)
41
40
  .join(', ');
42
41
 
43
- // 템플릿 리터럴을 사용하여 들여쓰기가 적용된 문자열 생성
42
+ // 💡 innerHtml을 innerHTML(대문자)로 변경!
43
+ // index.js의 generateCode 함수 리턴 부분
44
44
  return `${indent}h('${node.tag}', {
45
- ${indent} id: '${node.id}',
46
- ${indent} style: ${JSON.stringify(node.styles)},
47
- ${indent} innerHtml: \`${node.innerHtml.replace(/\$(\w+)/g, '${state.$1}')}\`${eventString ? ',\n' + indent + ' ' + eventString : ''}
48
- ${indent}}, [${childrenCode ? '\n' + childrenCode + '\n' + indent : ''}])`;
45
+ ${indent} id: '${node.id}',
46
+ ${indent} style: ${JSON.stringify(node.styles)},
47
+ ${indent} innerHTML: \`${node.innerHtml.replace(/\$(\w+)/g, '${state.$1}')}\`${eventString ? ',\n' + indent + ' ' + eventString : ''}
48
+ ${indent}}, [${childrenCode ? '\n' + childrenCode + '\n' + indent : ''}])`;
49
49
  }
50
50
 
51
51
  // compiler/index.js 내부
package/core/NeoCore.js CHANGED
@@ -2,10 +2,12 @@ export class NeoCore {
2
2
  constructor(state, rootRenderFn, containerId) {
3
3
  this.container = document.getElementById(containerId);
4
4
  this.rootRenderFn = rootRenderFn;
5
+
6
+ // Proxy를 사용하여 state가 바뀔 때마다 자동으로 mount() 호출
5
7
  this.state = new Proxy(state, {
6
8
  set: (target, key, value) => {
7
9
  target[key] = value;
8
- this.mount(); // 상태 변화 시 리렌더링
10
+ this.mount(); // 상태 변화 시 자동으로 리렌더링
9
11
  return true;
10
12
  }
11
13
  });
@@ -13,38 +15,46 @@ export class NeoCore {
13
15
 
14
16
  mount() {
15
17
  if (!this.container) return;
16
- this.container.innerHTML = '';
18
+ this.container.innerHTML = ''; // 화면 초기화
17
19
  const domTree = this.rootRenderFn(this.state);
18
20
  this.container.appendChild(domTree);
19
21
  }
20
22
  }
21
23
 
22
- // 가상 노드를 DOM 요소로 바꾸는 함수
24
+ // 가상 노드를 실제 DOM 요소로 변환하는 함수
23
25
  export function h(tag, props, children = []) {
26
+ // 1. 태그 생성
24
27
  const el = document.createElement(tag);
25
28
 
26
- // 1. ID 설정
29
+ // 2. 속성 설정
27
30
  if (props.id) el.id = props.id;
28
-
29
- // 2. 스타일 설정
30
31
  if (props.style) Object.assign(el.style, props.style);
32
+
33
+ // 💡 [수정] 대소문자 문제 해결: innerHTML과 innerHtml 둘 다 지원
34
+ const content = props.innerHTML || props.innerHtml;
35
+ if (content !== undefined) {
36
+ el.innerHTML = content;
37
+ }
31
38
 
32
- // 3. 내용물 설정
33
- if (props.innerHtml) el.innerHTML = props.innerHtml;
34
-
35
- // 💡 4. 이벤트 연결 (이 부분이 빠져있을 거예요!)
36
- // props에 on으로 시작하는 속성(onClick 등)이 있다면 이벤트를 등록합니다.
39
+ // 3. 이벤트 연결
37
40
  Object.keys(props).forEach(key => {
38
41
  if (key.startsWith('on') && typeof props[key] === 'function') {
39
- const eventType = key.toLowerCase().substring(2); // 'onClick' -> 'click'
42
+ const eventType = key.toLowerCase().substring(2);
40
43
  el.addEventListener(eventType, props[key]);
41
44
  }
42
45
  });
43
46
 
44
- // 5. 자식 요소 추가
45
- children.forEach(child => {
47
+ // 4. 자식 요소 추가 (배열 중첩 및 텍스트 노드 대응 강화)
48
+ const flattenChildren = Array.isArray(children) ? children.flat() : [children];
49
+
50
+ flattenChildren.forEach(child => {
51
+ if (child === null || child === undefined) return;
52
+
46
53
  if (child instanceof HTMLElement) {
47
54
  el.appendChild(child);
55
+ } else {
56
+ // 숫자나 문자열 등은 텍스트 노드로 변환하여 추가
57
+ el.appendChild(document.createTextNode(String(child)));
48
58
  }
49
59
  });
50
60
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@junnyontop-pixel/neo-app",
3
- "version": "1.1.6",
3
+ "version": "1.1.8",
4
4
  "description": "나만의 커스텀 프레임워크 Neo",
5
5
  "main": "core/NeoCore.js",
6
6
  "type": "module",
package/src/App.js CHANGED
@@ -8,8 +8,8 @@ function sayHello() {
8
8
 
9
9
  export default function render(state) {
10
10
  return h('button', {
11
- id: 'Btn',
12
- style: {},
13
- innerHtml: ``
14
- }, []);
11
+ id: 'Btn',
12
+ style: {},
13
+ innerHTML: ``
14
+ }, []);
15
15
  }