@iyulab/modern-app 0.48.0 → 0.49.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,28 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.49.1] - 2026-10-12
4
+
5
+ ### Fixed
6
+
7
+ - `u-group-box` is no longer a size container itself; the query container for its narrow layout is a box inside its
8
+ shadow root of the same width. In Chromium a card whose content changed in the same commit that disabled a sibling
9
+ `<fieldset>` could stay collapsed to its border (2px tall) until something forced a relayout, and the host's
10
+ `container-type` was the ingredient. Narrow-width rules — the card's own header, and unnamed `@container` queries
11
+ in slotted content — resolve to the same width as before.
12
+
13
+ ## [0.49.0] - 2026-10-09
14
+
15
+ ### Added
16
+
17
+ - `defaultFallback` — the failure screens `app.load()` draws when it gets no `fallback` (403 → `no-access`, 404 →
18
+ `not-found`, anything else → `error`, with matching tab titles). An app that constructs its own `Router` passes it
19
+ as `fallback` to get the same screens instead of copying the mapping, and keeps getting the fixes made to it.
20
+
21
+ ### Documentation
22
+
23
+ - `FallbackRouteConfig` was shown with a string-only `title` and a required `render`; `title` also takes a function
24
+ of the failure, and `render` is optional.
25
+
3
26
  ## [0.48.0] - 2026-10-09
4
27
 
5
28
  ### Changed
package/dist/App.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { ScreenObserver as e } from "./internals/ScreenObserver.js";
2
- import { defaultFallback as t } from "./internals/default-fallback.js";
2
+ import { defaultFallback as t } from "./defaultFallback.js";
3
3
  import n from "i18next";
4
4
  import { Router as r } from "@iyulab/router";
5
5
  import { setDefaultBaseUrl as i } from "@iyulab/components/dist/utilities/icons.js";
@@ -33,7 +33,7 @@ var f, p = {
33
33
  }
34
34
  render() {
35
35
  let e = !!this.title || !!this.description || this.hasActions;
36
- return a`
36
+ return a`<div class="frame">
37
37
  <div class="header ${this.divider ? "divider" : ""} ${e ? "" : "empty"}" part="header">
38
38
  <div class="titles">
39
39
  ${u`<${p[this.headingLevel]} class="title" part="title">${this.title}${this.title && this.meta ? a` <span class="meta" part="meta">${this.meta}</span>` : ""}</${p[this.headingLevel]}>`}
@@ -46,7 +46,7 @@ var f, p = {
46
46
  </div>
47
47
  </div>
48
48
  <div class="body ${this.flush ? "flush" : ""}" part="body"><slot></slot></div>
49
- `;
49
+ </div>`;
50
50
  }
51
51
  };
52
52
  t([c({ type: String }), e("design:type", Object)], m.prototype, "title", void 0), t([c({ type: String }), e("design:type", String)], m.prototype, "meta", void 0), t([c({ type: String }), e("design:type", String)], m.prototype, "description", void 0), t([c({ type: Boolean }), e("design:type", Object)], m.prototype, "divider", void 0), t([c({ type: Boolean }), e("design:type", Object)], m.prototype, "flush", void 0), t([c({
@@ -6,16 +6,23 @@ var t = e`
6
6
 
7
7
 
8
8
 
9
- container-type: inline-size;
10
-
11
-
12
-
13
9
  background-color: var(--u-panel-bg-color, #FFFFFF);
14
10
  border: 1px solid var(--u-border-color, #E0E0E0);
15
11
  border-radius: var(--u-radius-xl, 8px);
16
12
  box-shadow: var(--u-shadow-sm, 0 1px 3px rgba(0, 0, 0, 0.08), 0 1px 1px rgba(0, 0, 0, 0.04));
17
13
  }
18
14
 
15
+
16
+
17
+
18
+
19
+
20
+
21
+
22
+ .frame {
23
+ container-type: inline-size;
24
+ }
25
+
19
26
  .header {
20
27
  display: flex;
21
28
  align-items: center;
@@ -1,5 +1,5 @@
1
1
  import { FallbackRouteConfig, RouteError } from '@iyulab/router';
2
- import { EmptyStateVariant } from '../components/EmptyState.js';
2
+ import { EmptyStateVariant } from './components/EmptyState.js';
3
3
  /**
4
4
  * `app.load()` 에 `fallback` 을 주지 않은 앱의 라우팅 실패 화면 — 앱 프레임워크의 빈 상태 어휘로 그린다.
5
5
  *
@@ -15,4 +15,19 @@ import { EmptyStateVariant } from '../components/EmptyState.js';
15
15
  * - 소비자가 `fallback` 을 주면 그것이 그대로 이긴다(이 모듈은 쓰이지 않는다).
16
16
  */
17
17
  export declare function variantOf(error: Pick<RouteError, 'code'>): EmptyStateVariant;
18
+ /**
19
+ * 라우팅 실패 화면 — `app.load()` 가 `fallback` 없이 쓰는 바로 그것.
20
+ *
21
+ * ★**왜 공개하는가**(#977): 실패를 이 패키지의 말과 모양으로 그리는 정책은 이 패키지 것인데, 종전에는 `App` 경로만
22
+ * 받았다. `Router` 를 직접 구성하는 앱(셸을 자기 라우트 트리의 부모로 그리는 경우 등)은 매핑을 베껴야 했고, 베낀
23
+ * 쪽은 판이 고친 것(0.47.1 의 탭 제목)을 받지 못했다. 이 값을 넘기면 판이 바뀔 때 같이 바뀐다.
24
+ *
25
+ * 상태가 없다 — 로캘은 그릴 때 읽는다. 일부만 바꾸려면 감싼다: `{ ...defaultFallback, render: (ctx) => … }`.
26
+ *
27
+ * @example
28
+ * ```ts
29
+ * import { defaultFallback } from '@iyulab/modern-app';
30
+ * new Router({ root, routes, fallback: defaultFallback });
31
+ * ```
32
+ */
18
33
  export declare const defaultFallback: FallbackRouteConfig;
@@ -1,6 +1,6 @@
1
- import { getLocaleStrings as e } from "./locale.js";
2
- import { EmptyState as t } from "../components/EmptyState.js";
3
- //#region src/internals/default-fallback.ts
1
+ import { getLocaleStrings as e } from "./internals/locale.js";
2
+ import { EmptyState as t } from "./components/EmptyState.js";
3
+ //#region src/defaultFallback.ts
4
4
  function n(e) {
5
5
  switch (String(e.code)) {
6
6
  case "403": return "no-access";
package/dist/index.d.ts CHANGED
@@ -5,6 +5,7 @@ export type * from './types/AuthConfig';
5
5
  export type { SidebarPermissionGuard } from './layouts/SidebarPermission';
6
6
  export type { RouteConfig, RouteContext, FallbackRouteConfig } from '@iyulab/router';
7
7
  export { RouteError, NotFoundError, AccessDeniedError, ContentLoadError, ContentRenderError, OutletMissingError, } from '@iyulab/router';
8
+ export { defaultFallback } from './defaultFallback.js';
8
9
  export type { SidebarIconsConfig, SidebarLayoutConfig, SidebarItem, SidebarLogoConfig, SidebarLinkConfig, SidebarSectionConfig, SidebarGroupConfig, SidebarButtonConfig, SidebarMenuConfig, SidebarMenuItemConfig, SidebarHtmlConfig, SidebarState, } from './layouts/SidebarLayout.types';
9
10
  export type { SidebarLayoutEventMap } from './layouts/SidebarLayout.js';
10
11
  export { filterSidebarItems } from './layouts/filterSidebarItems.js';
package/dist/index.js CHANGED
@@ -1,20 +1,21 @@
1
1
  import { ScreenObserver as e } from "./internals/ScreenObserver.js";
2
2
  import { getDefaultLocale as t, getLocaleStrings as n, modernAppLocale as r } from "./internals/locale.js";
3
3
  import { EmptyState as i } from "./components/EmptyState.js";
4
- import { app as a } from "./App.js";
5
- import { filterSidebarItems as o } from "./layouts/filterSidebarItems.js";
6
- import { PageHeader as s } from "./components/PageHeader.js";
7
- import { GroupBox as c } from "./components/GroupBox.js";
8
- import { InfoSection as l } from "./components/InfoSection.js";
9
- import { InfoField as u, isBlank as d } from "./components/InfoField.js";
10
- import { TimelineItem as f } from "./components/TimelineItem.js";
11
- import { Timeline as p } from "./components/Timeline.js";
12
- import { ActionBar as m } from "./components/ActionBar.js";
13
- import { MasterDetailLayout as h } from "./components/MasterDetailLayout.js";
14
- import { Wizard as g } from "./components/Wizard.js";
15
- import { translate as _ } from "./translate.js";
16
- import { AccessDeniedError as v, ContentLoadError as y, ContentRenderError as b, NotFoundError as x, OutletMissingError as S, RouteError as C } from "@iyulab/router";
4
+ import { defaultFallback as a } from "./defaultFallback.js";
5
+ import { app as o } from "./App.js";
6
+ import { filterSidebarItems as s } from "./layouts/filterSidebarItems.js";
7
+ import { PageHeader as c } from "./components/PageHeader.js";
8
+ import { GroupBox as l } from "./components/GroupBox.js";
9
+ import { InfoSection as u } from "./components/InfoSection.js";
10
+ import { InfoField as d, isBlank as f } from "./components/InfoField.js";
11
+ import { TimelineItem as p } from "./components/TimelineItem.js";
12
+ import { Timeline as m } from "./components/Timeline.js";
13
+ import { ActionBar as h } from "./components/ActionBar.js";
14
+ import { MasterDetailLayout as g } from "./components/MasterDetailLayout.js";
15
+ import { Wizard as _ } from "./components/Wizard.js";
16
+ import { translate as v } from "./translate.js";
17
+ import { AccessDeniedError as y, ContentLoadError as b, ContentRenderError as x, NotFoundError as S, OutletMissingError as C, RouteError as w } from "@iyulab/router";
17
18
  //#region src/index.ts
18
- var w = a;
19
+ var T = o;
19
20
  //#endregion
20
- export { v as AccessDeniedError, m as ActionBar, y as ContentLoadError, b as ContentRenderError, i as EmptyState, c as GroupBox, u as InfoField, l as InfoSection, h as MasterDetailLayout, x as NotFoundError, S as OutletMissingError, s as PageHeader, C as RouteError, e as ScreenObserver, p as Timeline, f as TimelineItem, g as Wizard, a as app, w as default, o as filterSidebarItems, t as getDefaultLocale, n as getLocaleStrings, d as isBlank, r as modernAppLocale, _ as translate };
21
+ export { y as AccessDeniedError, h as ActionBar, b as ContentLoadError, x as ContentRenderError, i as EmptyState, l as GroupBox, d as InfoField, u as InfoSection, g as MasterDetailLayout, S as NotFoundError, C as OutletMissingError, c as PageHeader, w as RouteError, e as ScreenObserver, m as Timeline, p as TimelineItem, _ as Wizard, o as app, T as default, a as defaultFallback, s as filterSidebarItems, t as getDefaultLocale, n as getLocaleStrings, f as isBlank, r as modernAppLocale, v as translate };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@iyulab/modern-app",
3
3
  "description": "web-framework by iyulab based on lit-element",
4
- "version": "0.48.0",
4
+ "version": "0.49.1",
5
5
  "keywords": [
6
6
  "iyulab",
7
7
  "web-framework",
@@ -78,7 +78,7 @@
78
78
  }
79
79
  },
80
80
  "devDependencies": {
81
- "@iyulab/components": ">=2.8.0",
81
+ "@iyulab/components": "^2.19.0",
82
82
  "@lit/react": "^1.0.8",
83
83
  "@types/node": "^26.1.1",
84
84
  "@types/react": "^19.3.0",
@@ -183,10 +183,13 @@ interface RouteContext {
183
183
 
184
184
  ```typescript
185
185
  interface FallbackRouteConfig {
186
- /** Sets `document.title` when the fallback renders. */
187
- title?: string;
186
+ /**
187
+ * Sets `document.title` when the fallback renders. A function is called with each failure — use it when the
188
+ * title depends on the error. Returning nothing (or an empty string) falls back to the error message.
189
+ */
190
+ title?: string | ((context: RouteContext & { error: RouteError }) => string | undefined);
188
191
 
189
- render: (context: RouteContext & { error: RouteError }) => RenderResult | Promise<RenderResult>;
192
+ render?: (context: RouteContext & { error: RouteError }) => unknown;
190
193
  }
191
194
  ```
192
195
 
@@ -198,6 +201,8 @@ exported from `@iyulab/modern-app` — tell a blocked screen from a missing one
198
201
 
199
202
  Without a `fallback`, `app.load()` draws `<u-empty-state>` itself: 403 → `no-access` · 404 → `not-found` ·
200
203
  anything else → `error` (title "Couldn’t open this page", the error message as description).
204
+ That default is exported as `defaultFallback` — an app that constructs its own `Router` passes it
205
+ (`new Router({ root, routes, fallback: defaultFallback })`) to get the same screens and tab titles.
201
206
 
202
207
  ---
203
208