@iyulab/modern-app 0.3.0 → 0.3.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.1 (2026-03-05)
4
+
5
+ ### Breaking Changes
6
+ - **Slot 기반 Outlet 구조**: `SidebarLayout` 내부의 `<u-outlet>`을 `<slot>`으로 변경하고, `App`에서 Light DOM에 `<u-outlet>`을 추가하는 방식으로 전환. 이를 통해 React 라우팅 시 외부 CSS가 정상적으로 적용됨
7
+
8
+ ### Changes
9
+ - **BaseElement → UElement 마이그레이션**: 모든 컴포넌트의 기반 클래스를 `BaseElement`에서 `UElement`로 변경
10
+ - **SidebarLinkConfig**: `type` 속성을 optional에서 required로 변경
11
+ - **import 경로 수정**: `Theme.js`, `Notifier.js` 등 대소문자 교정
12
+
13
+ ### Dependencies
14
+ - `@iyulab/components` ^0.2.0 → ^0.4.0
15
+ - `@iyulab/router` ^0.6.2 → ^0.7.2
16
+ - `i18next` ^25.8.0 → ^25.8.13
17
+ - `@types/node` ^25.0.9 → ^25.3.2
18
+
19
+ ### Fixes
20
+ - `SidebarButton.styles.ts`에서 중복된 `color` 속성 제거
21
+ - `repeat` 디렉티브의 미사용 콜백 파라미터 정리
22
+
3
23
  ## 0.3.0 (2026-01-21)
4
24
 
5
25
  ### Breaking Changes
package/README.md CHANGED
@@ -10,6 +10,24 @@ For complete examples and documentation, visit our demo site: [https://modern-ap
10
10
  npm install @iyulab/modern-app
11
11
  ```
12
12
 
13
+ ## Architecture
14
+
15
+ `@iyulab/modern-app` is a **client-side SPA framework** built on Lit Element. It is designed for:
16
+
17
+ ✅ **Suitable for:**
18
+ - Single Page Applications (SPA)
19
+ - Admin dashboards and internal tools
20
+ - Progressive Web Apps (PWA)
21
+ - Projects where SEO is not a primary concern
22
+
23
+ ❌ **Not suitable for:**
24
+ - Server-Side Rendering (SSR) frameworks (Next.js, Nuxt, SvelteKit, etc.)
25
+ - Static Site Generation (SSG)
26
+ - SEO-critical public-facing pages
27
+ - Projects requiring initial HTML content for search engines
28
+
29
+ This is by design — Lit components render on the client side. If you need SSR capabilities, consider using Lit's experimental SSR support separately or choose a framework designed for SSR from the start.
30
+
13
31
  ## Quick Start
14
32
 
15
33
  ```typescript
package/dist/App.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import r from "i18next";
2
2
  import { Router as u } from "@iyulab/router";
3
3
  import { setDefaultBaseUrl as h } from "@iyulab/components/dist/utilities/IconRegistry.js";
4
- import { Theme as s } from "@iyulab/components/dist/utilities/Theme.js";
5
- import { Notifier as y } from "@iyulab/components/dist/utilities/Notifier.js";
6
- import { ScreenObserver as c } from "./internals/ScreenObserver.js";
4
+ import { Theme as n } from "@iyulab/components/dist/utilities/Theme.js";
5
+ import { Notifier as c } from "@iyulab/components/dist/utilities/Notifier.js";
6
+ import { ScreenObserver as y } from "./internals/ScreenObserver.js";
7
7
  class o {
8
8
  // private 생성자로 외부에서 인스턴스 생성 방지
9
9
  constructor() {
@@ -26,7 +26,7 @@ class o {
26
26
  }
27
27
  /** 스타일 테마 관리 유틸리티 객체 반환 */
28
28
  get theme() {
29
- return s;
29
+ return n;
30
30
  }
31
31
  /** 다국어 로컬라이저(i18next) 반환 */
32
32
  get i18n() {
@@ -34,16 +34,18 @@ class o {
34
34
  }
35
35
  /** 앱 로드 및 초기화 */
36
36
  async load(t) {
37
- if (this.unload(), this._config = t, await s.init(t.theme), t.iconBasepath && h(t.iconBasepath), t.i18n) {
38
- for (const i of t.i18n.plugins || [])
39
- r.use(i);
37
+ if (this.unload(), this._config = t, await n.init(t.theme), t.iconBasepath && h(t.iconBasepath), t.i18n) {
38
+ for (const a of t.i18n.plugins || [])
39
+ r.use(a);
40
40
  await r.init(t.i18n);
41
41
  }
42
42
  const e = t.root || document.body;
43
- this._layout = await this.createLayout(e, t.layout), this._screen = new c({
43
+ this._layout = await this.createLayout(e, t.layout), this._screen = new y({
44
44
  element: e,
45
45
  breakpoints: t.layout.breakpoints || [768, 1024]
46
- }), this._router = new u({
46
+ });
47
+ const i = document.createElement("u-outlet");
48
+ this._layout.appendChild(i), this._router = new u({
47
49
  root: this._layout,
48
50
  basepath: t.basepath,
49
51
  routes: t.routes,
@@ -80,7 +82,7 @@ class o {
80
82
  }
81
83
  /** 알림 표시 */
82
84
  async notify(t, e, i) {
83
- await y.toast({
85
+ await c.toast({
84
86
  type: t,
85
87
  content: e,
86
88
  heading: i?.title,
@@ -93,8 +95,8 @@ class o {
93
95
  t === document.body && (document.body.style.margin = "0", document.body.style.width = "100vw", document.body.style.height = "100vh");
94
96
  let i;
95
97
  if (e.type === "sidebar") {
96
- const { SidebarLayout: n } = await import("./layouts/SidebarLayout.js"), a = new n();
97
- a.config = e, i = a;
98
+ const { SidebarLayout: a } = await import("./layouts/SidebarLayout.js"), s = new a();
99
+ s.config = e, i = s;
98
100
  } else
99
101
  throw new Error(`Unsupported layout type: ${e.type}`);
100
102
  return t.appendChild(i), "updateComplete" in i && await i.updateComplete, i;
@@ -1,5 +1,5 @@
1
1
  import { DirectiveResult } from 'lit/directive.js';
2
- import { BaseElement } from '@iyulab/components/dist/components/BaseElement.js';
2
+ import { UElement } from '@iyulab/components/dist/components/UElement.js';
3
3
  import { StyledElement, StyleMap } from '../internals/StyledElement.js';
4
4
  /** 버튼 항목 부분 */
5
5
  type ElementParts = 'host' | 'base' | 'icon' | 'label';
@@ -16,7 +16,7 @@ export interface SidebarButtonConfig {
16
16
  */
17
17
  export declare class SidebarButton extends StyledElement<ElementParts> {
18
18
  static styles: import('lit').CSSResultGroup[];
19
- static dependencies: Record<string, typeof BaseElement>;
19
+ static dependencies: Record<string, typeof UElement>;
20
20
  /** 콤팩트 모드 여부 */
21
21
  compact: boolean;
22
22
  /** 기본 u-icon 경로의 아이콘 이름 */
@@ -1,10 +1,9 @@
1
1
  import { css as o } from "lit";
2
- const r = o`
2
+ const e = o`
3
3
  :host {
4
4
  display: block;
5
5
  width: 100%;
6
6
  color: var(--u-txt-color);
7
- color: var(--u-neutral-800);
8
7
  background-color: transparent;
9
8
  border: none;
10
9
  border-radius: 8px;
@@ -56,5 +55,5 @@ const r = o`
56
55
  }
57
56
  `;
58
57
  export {
59
- r as styles
58
+ e as styles
60
59
  };
@@ -1,5 +1,5 @@
1
1
  import { DirectiveResult } from 'lit/directive.js';
2
- import { BaseElement } from '@iyulab/components/dist/components/BaseElement.js';
2
+ import { UElement } from '@iyulab/components/dist/components/UElement.js';
3
3
  import { StyledElement, StyleMap } from '../internals/StyledElement.js';
4
4
  import { SidebarLinkConfig } from './SidebarLink.js';
5
5
  type ElementParts = 'host' | 'header' | 'icon' | 'label' | 'caret' | 'items';
@@ -18,7 +18,7 @@ export interface SidebarGroupConfig {
18
18
  */
19
19
  export declare class SidebarGroup extends StyledElement<ElementParts> {
20
20
  static styles: import('lit').CSSResultGroup[];
21
- static dependencies: Record<string, typeof BaseElement>;
21
+ static dependencies: Record<string, typeof UElement>;
22
22
  /** 콤팩트 모드 여부 */
23
23
  compact: boolean;
24
24
  /** 선택된 상태 */
@@ -1,10 +1,10 @@
1
1
  import { DirectiveResult } from 'lit/directive.js';
2
- import { BaseElement } from '@iyulab/components/dist/components/BaseElement.js';
2
+ import { UElement } from '@iyulab/components/dist/components/UElement.js';
3
3
  import { StyledElement, StyleMap } from '../internals/StyledElement.js';
4
4
  type ElementParts = 'host' | 'base' | 'icon' | 'label';
5
5
  /** 링크 항목 디폴트 타입 */
6
6
  export interface SidebarLinkConfig {
7
- type?: 'link';
7
+ type: 'link';
8
8
  icon?: string;
9
9
  label: string | DirectiveResult;
10
10
  href: string;
@@ -17,7 +17,7 @@ export interface SidebarLinkConfig {
17
17
  */
18
18
  export declare class SidebarLink extends StyledElement<ElementParts> {
19
19
  static styles: import('lit').CSSResultGroup[];
20
- static dependencies: Record<string, typeof BaseElement>;
20
+ static dependencies: Record<string, typeof UElement>;
21
21
  /** selected 상태 */
22
22
  selected: boolean;
23
23
  /** 콤팩트 모드 여부 */
@@ -1,5 +1,5 @@
1
1
  import { DirectiveResult } from 'lit/directive.js';
2
- import { BaseElement } from '@iyulab/components/dist/components/BaseElement.js';
2
+ import { UElement } from '@iyulab/components/dist/components/UElement.js';
3
3
  import { StyledElement, StyleMap } from '../internals/StyledElement.js';
4
4
  import { SidebarLinkConfig } from './SidebarLink.js';
5
5
  import { SidebarGroupConfig } from './SidebarGroup.js';
@@ -17,7 +17,7 @@ export interface SidebarSectionConfig {
17
17
  */
18
18
  export declare class SidebarSection extends StyledElement<ElementParts> {
19
19
  static styles: import('lit').CSSResultGroup[];
20
- static dependencies: Record<string, typeof BaseElement>;
20
+ static dependencies: Record<string, typeof UElement>;
21
21
  /** 콤팩트 모드 여부 */
22
22
  compact: boolean;
23
23
  /** 네비게이션 아이템 데이터 */
@@ -1,5 +1,5 @@
1
1
  import { PropertyValues } from 'lit';
2
- import { BaseElement } from '@iyulab/components/dist/components/BaseElement.js';
2
+ import { UElement } from '@iyulab/components/dist/components/UElement.js';
3
3
  /** 스타일 값 타입 */
4
4
  export type StyleValue = Record<string, string> | Partial<CSSStyleDeclaration>;
5
5
  /** 스타일 맵 타입 */
@@ -7,9 +7,9 @@ export type StyleMap<T extends string> = Partial<Record<T, StyleValue>>;
7
7
  /**
8
8
  * StyledBaseElement - BaseElement의 확장으로 부분별 스타일링 기능 추가
9
9
  */
10
- export declare class StyledElement<T extends string> extends BaseElement {
10
+ export declare class StyledElement<T extends string> extends UElement {
11
11
  static styles: import('lit').CSSResultGroup;
12
- static dependencies: Record<string, typeof BaseElement>;
12
+ static dependencies: Record<string, typeof UElement>;
13
13
  /** 부분별 스타일 구성 */
14
14
  styles?: StyleMap<T>;
15
15
  protected updated(changedProperties: PropertyValues): void;
@@ -1,5 +1,5 @@
1
- import { property as l } from "lit/decorators.js";
2
- import { BaseElement as c } from "@iyulab/components/dist/components/BaseElement.js";
1
+ import { property as a } from "lit/decorators.js";
2
+ import { UElement as c } from "@iyulab/components/dist/components/UElement.js";
3
3
  var p = Object.defineProperty, y = (n, e, i, r) => {
4
4
  for (var t = void 0, s = n.length - 1, o; s >= 0; s--)
5
5
  (o = n[s]) && (t = o(e, i, t) || t);
@@ -44,14 +44,14 @@ class f extends c {
44
44
  try {
45
45
  e.style[r] = s;
46
46
  } catch {
47
- const o = r.replace(/[A-Z]/g, (a) => "-" + a.toLowerCase());
47
+ const o = r.replace(/[A-Z]/g, (l) => "-" + l.toLowerCase());
48
48
  e.style.setProperty(o, s);
49
49
  }
50
50
  }
51
51
  }
52
52
  }
53
53
  y([
54
- l({ type: Object, attribute: !1 })
54
+ a({ type: Object, attribute: !1 })
55
55
  ], f.prototype, "styles");
56
56
  export {
57
57
  f as StyledElement
@@ -1,6 +1,6 @@
1
1
  import { nothing, PropertyValues } from 'lit';
2
2
  import { RouteContext } from '@iyulab/router';
3
- import { BaseElement } from '@iyulab/components/dist/components/BaseElement.js';
3
+ import { UElement } from '@iyulab/components/dist/components/UElement.js';
4
4
  import { UIcon } from '@iyulab/components/dist/components/icon/UIcon.component.js';
5
5
  import { UButton } from '@iyulab/components/dist/components/button/UButton.component.js';
6
6
  import { UProgressBar } from '@iyulab/components/dist/components/progress-bar/UProgressBar.component.js';
@@ -39,7 +39,7 @@ declare global {
39
39
  */
40
40
  export declare class SidebarLayout extends StyledElement<SidebarParts> {
41
41
  static styles: import('lit').CSSResultGroup[];
42
- static dependencies: Record<string, typeof BaseElement>;
42
+ static dependencies: Record<string, typeof UElement>;
43
43
  progressBarEl: UProgressBar;
44
44
  /** 현재 라우터 컨텍스트 */
45
45
  context: RouteContext | null;
@@ -13,10 +13,10 @@ import { SidebarLink as L } from "../components/SidebarLink.js";
13
13
  import { SidebarButton as _ } from "../components/SidebarButton.js";
14
14
  import { styles as C } from "./SidebarLayout.styles.js";
15
15
  import { IconRegistry as R } from "@iyulab/components/dist/utilities/IconRegistry.js";
16
- var S = Object.defineProperty, z = Object.getOwnPropertyDescriptor, E = Object.getPrototypeOf, x = Reflect.get, n = (e, t, s, r) => {
17
- for (var o = r > 1 ? void 0 : r ? z(t, s) : t, d = e.length - 1, c; d >= 0; d--)
18
- (c = e[d]) && (o = (r ? c(t, s, o) : c(o)) || o);
19
- return r && o && S(t, s, o), o;
16
+ var S = Object.defineProperty, z = Object.getOwnPropertyDescriptor, E = Object.getPrototypeOf, x = Reflect.get, n = (e, t, s, o) => {
17
+ for (var r = o > 1 ? void 0 : o ? z(t, s) : t, d = e.length - 1, c; d >= 0; d--)
18
+ (c = e[d]) && (r = (o ? c(t, s, r) : c(r)) || r);
19
+ return o && r && S(t, s, r), r;
20
20
  }, M = (e, t, s) => x(E(e), s, t);
21
21
  R.register("sidebar-app", (e) => e === "layout-sidebar" ? '<svg viewBox="0 0 16 16"><path d="M0 3a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2zm5-1v12h9a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1zM4 2H2a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h2z"/></svg>' : e === "list" ? '<svg viewBox="0 0 16 16"><path fill-rule="evenodd" d="M1 3a1 1 0 0 1 1-1h12a1 1 0 0 1 0 2H2a1 1 0 0 1-1-1 m0 5a1 1 0 0 1 1-1h12a1 1 0 0 1 0 2H2a1 1 0 0 1-1-1 m0 5a1 1 0 0 1 1-1h12a1 1 0 0 1 0 2H2a1 1 0 0 1-1-1"/></svg>' : e === "x-lg" ? '<svg viewBox="0 0 16 16"><path d="M2.146 2.854a.5.5 0 1 1 .708-.708L8 7.293l5.146-5.147a.5.5 0 0 1 .708.708L8.707 8l5.147 5.146a.5.5 0 0 1-.708.708L8 8.707l-5.146 5.147a.5.5 0 0 1-.708-.708L7.293 8z"/></svg>' : "");
22
22
  let i = class extends w {
@@ -93,7 +93,7 @@ let i = class extends w {
93
93
  ${l(
94
94
  this.config.main ?? [],
95
95
  (e, t) => t,
96
- (e, t) => this.renderItem(e)
96
+ (e) => this.renderItem(e)
97
97
  )}
98
98
  </nav>
99
99
 
@@ -102,7 +102,7 @@ let i = class extends w {
102
102
  ${l(
103
103
  this.config.footer ?? [],
104
104
  (e, t) => t,
105
- (e, t) => this.renderItem(e)
105
+ (e) => this.renderItem(e)
106
106
  )}
107
107
  </div>
108
108
  </aside>
@@ -111,7 +111,7 @@ let i = class extends w {
111
111
  <div class="main" part="main" scrollable>
112
112
  <u-progress-bar part="progress"></u-progress-bar>
113
113
 
114
- <u-outlet></u-outlet>
114
+ <slot></slot>
115
115
  </div>
116
116
 
117
117
  <!-- Backdrop for modal state -->
@@ -161,7 +161,7 @@ let i = class extends w {
161
161
  ${l(
162
162
  e.items,
163
163
  (t, s) => s,
164
- (t, s) => this.renderItem(t)
164
+ (t) => this.renderItem(t)
165
165
  )}
166
166
  </u-sidebar-section>
167
167
  `;
@@ -177,8 +177,8 @@ let i = class extends w {
177
177
  .styles="${e.styles}">
178
178
  ${l(
179
179
  e.items,
180
- (s, r) => r,
181
- (s, r) => this.renderItem(s)
180
+ (s, o) => o,
181
+ (s) => this.renderItem(s)
182
182
  )}
183
183
  </u-sidebar-group>
184
184
  `;
@@ -1,6 +1,6 @@
1
1
  import { InitOptions, Module, Newable, NewableModule } from 'i18next';
2
2
  import { RouteConfig, FallbackRouteConfig } from '@iyulab/router';
3
- import { ThemeInitOptions } from '@iyulab/components/dist/utilities/theme.js';
3
+ import { ThemeInitOptions } from '@iyulab/components/dist/utilities/Theme.js';
4
4
  import { SidebarLayoutConfig } from '../layouts/SidebarLayout.types';
5
5
  /**
6
6
  * i18next의 초기화 옵션과 플러그인 배열을 포함한 다국어 설정
@@ -1,4 +1,4 @@
1
- import { ScreenPosition } from '@iyulab/components/dist/utilities/notifier.js';
1
+ import { ScreenPosition } from '@iyulab/components/dist/utilities/Notifier.js';
2
2
  export interface NotificationOptions {
3
3
  title?: string;
4
4
  duration?: number;
package/package.json CHANGED
@@ -1,11 +1,10 @@
1
1
  {
2
2
  "name": "@iyulab/modern-app",
3
- "description": "web-framework by iyulab based on react, lit-element",
4
- "version": "0.3.0",
3
+ "description": "web-framework by iyulab based on lit-element",
4
+ "version": "0.3.1",
5
5
  "keywords": [
6
6
  "iyulab",
7
7
  "web-framework",
8
- "react",
9
8
  "lit-element"
10
9
  ],
11
10
  "license": "MIT",
@@ -38,13 +37,13 @@
38
37
  "build": "vite build"
39
38
  },
40
39
  "dependencies": {
41
- "@iyulab/components": "^0.2.0",
42
- "@iyulab/router": "^0.6.2",
43
- "lit": "^3.3.2",
44
- "i18next": "^25.8.0"
40
+ "@iyulab/components": "^0.4.0",
41
+ "@iyulab/router": "^0.7.4",
42
+ "i18next": "^25.8.13",
43
+ "lit": "^3.3.2"
45
44
  },
46
45
  "devDependencies": {
47
- "@types/node": "^25.0.9",
46
+ "@types/node": "^25.3.2",
48
47
  "typescript": "^5.9.3",
49
48
  "vite": "^7.3.1",
50
49
  "vite-plugin-dts": "^4.5.4"