@iyulab/modern-app 0.18.11 → 0.18.16

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,78 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.18.16] - 2026-09-03
4
+
5
+ ### Fixed
6
+
7
+ - **`ThemeInitOptions.store`'s type documented a `'sessionStorage'` value that has
8
+ never existed.** The field's real type is re-exported unchanged from
9
+ `@iyulab/components`' `BrowserStorageOptions`, which only supports
10
+ `'localStorage' | 'cookie'` — confirmed against `BrowserStorage.ts` and its test
11
+ suite, which uses `'sessionStorage'` specifically as the invalid-type negative
12
+ case. All three docs (`docs/theme.md`, `docs/configuration.md`,
13
+ `skills/modern-app/references/api.md`) listed it as valid.
14
+
15
+ ## [0.18.15] - 2026-09-02
16
+
17
+ ### Fixed
18
+
19
+ - **`NotificationOptions.position` documented only 4 of the 9 valid values in
20
+ four places** (`docs/notifications.md`, `docs/configuration.md`,
21
+ `skills/modern-app/references/api.md`, `skills/modern-app/SKILL.md`).
22
+ The field's actual type is `ToastPosition` (`@iyulab/components`, re-exported
23
+ unchanged) and `App.ts` passes `options` straight through to `Toast.*()` with
24
+ no restriction — `app.success(msg, { position: 'middle-center' })` genuinely
25
+ works today. Docs narrowed it to `'top-right' | 'top-left' | 'bottom-right'
26
+ | 'bottom-left'`, silently hiding `top-center`, `middle-left`,
27
+ `middle-center`, `middle-right`, and `bottom-center`.
28
+
29
+ ## [0.18.14] - 2026-09-02
30
+
31
+ ### Fixed
32
+
33
+ - **`SidebarLayoutConfig`'s `mainAriaLabel` and `hasPermission` fields were
34
+ undocumented in all three reference docs** (`docs/layout.md`,
35
+ `docs/configuration.md`, `skills/modern-app/references/layout.md`). Both
36
+ are real, shipped features — `mainAriaLabel` sets the main nav landmark's
37
+ `aria-label`, `hasPermission` filters sidebar items by permission — and
38
+ the README already has a working usage example for `hasPermission`, but
39
+ a consumer reading only the type reference had no way to discover either
40
+ field. Added to all three snippets.
41
+
42
+ ## [0.18.13] - 2026-09-02
43
+
44
+ ### Fixed
45
+
46
+ - **`RouteContext`'s documented field list had drifted independently of
47
+ `RouteConfig`'s.** `0.18.12` fixed `RouteConfig`'s snippet in two of three
48
+ docs but left `RouteContext` untouched everywhere, and `configuration.md`'s
49
+ `RouteConfig` snippet was missed entirely. `docs/configuration.md` and
50
+ `docs/routing.md` were both missing `origin`, `path`, and `hash`
51
+ (`routing.md` also missing `metadata`, despite `RouteConfig.metadata`'s own
52
+ doc comment on the line above pointing to it); `skills/modern-app/references/api.md`
53
+ was missing `origin`, `path`, `query`, `hash`, and `metadata` — a consumer
54
+ reading only that doc had no way to discover `ctx.query` exists at all.
55
+ `configuration.md`'s `RouteConfig` snippet gained `id`, `ignoreCase`, and
56
+ `children`, matching the other two docs. `FallbackRouteConfig`'s `render`
57
+ callback is now typed `RouteContext & { error: RouteError }` — what
58
+ `Router.ts` actually passes — instead of plain `RouteContext` or an
59
+ untyped prose note.
60
+
61
+ ## [0.18.12] - 2026-09-01
62
+
63
+ ### Fixed
64
+
65
+ - **Routing docs never mentioned nested routes (`RouteConfig.children`).**
66
+ `@iyulab/router`'s `RouteConfig` supports it and its own README documents
67
+ it, but `modern-app`'s `docs/routing.md` and `skills/modern-app/references/api.md`
68
+ only reproduced a partial `RouteConfig` snippet that omitted `children`,
69
+ `id`, `ignoreCase`, and `enter`, and narrowed `path` to `string` only. A
70
+ consumer reading only `modern-app`'s docs had no way to discover the
71
+ feature and would flatten routes that share a layout into a single list.
72
+ Both docs now cover the full shape and link to `@iyulab/router`'s README
73
+ as the source of truth, and `docs/routing.md` gained a "Nested routes"
74
+ section with an example.
75
+
3
76
  ## [0.18.11] - 2026-09-01
4
77
 
5
78
  ### Changed
@@ -1,4 +1,4 @@
1
- //#region \0@oxc-project+runtime@0.147.0/helpers/esm/decorate.js
1
+ //#region \0@oxc-project+runtime@0.148.0/helpers/esm/decorate.js
2
2
  function e(e, t, n, r) {
3
3
  var i = arguments.length, a = i < 3 ? t : r === null ? r = Object.getOwnPropertyDescriptor(t, n) : r, o;
4
4
  if (typeof Reflect == "object" && typeof Reflect.decorate == "function") a = Reflect.decorate(e, t, n, r);
@@ -1,4 +1,4 @@
1
- //#region \0@oxc-project+runtime@0.147.0/helpers/esm/decorateMetadata.js
1
+ //#region \0@oxc-project+runtime@0.148.0/helpers/esm/decorateMetadata.js
2
2
  function e(e, t) {
3
3
  if (typeof Reflect == "object" && typeof Reflect.metadata == "function") return Reflect.metadata(e, t);
4
4
  }
@@ -1,5 +1,5 @@
1
- import e from "../_virtual/_@oxc-project_runtime@0.147.0/helpers/esm/decorateMetadata.js";
2
- import t from "../_virtual/_@oxc-project_runtime@0.147.0/helpers/esm/decorate.js";
1
+ import e from "../_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorateMetadata.js";
2
+ import t from "../_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorate.js";
3
3
  import { StyledElement as n } from "../internals/StyledElement.js";
4
4
  import { slotHasContent as r } from "../internals/slotted.js";
5
5
  import { styles as i } from "./ActionBar.styles.js";
@@ -1,5 +1,5 @@
1
- import e from "../_virtual/_@oxc-project_runtime@0.147.0/helpers/esm/decorateMetadata.js";
2
- import t from "../_virtual/_@oxc-project_runtime@0.147.0/helpers/esm/decorate.js";
1
+ import e from "../_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorateMetadata.js";
2
+ import t from "../_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorate.js";
3
3
  import { StyledElement as n } from "../internals/StyledElement.js";
4
4
  import { getLocaleStrings as r } from "../internals/locale.js";
5
5
  import { slotHasContent as i } from "../internals/slotted.js";
@@ -1,5 +1,5 @@
1
- import e from "../_virtual/_@oxc-project_runtime@0.147.0/helpers/esm/decorateMetadata.js";
2
- import t from "../_virtual/_@oxc-project_runtime@0.147.0/helpers/esm/decorate.js";
1
+ import e from "../_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorateMetadata.js";
2
+ import t from "../_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorate.js";
3
3
  import { StyledElement as n } from "../internals/StyledElement.js";
4
4
  import { slotHasContent as r } from "../internals/slotted.js";
5
5
  import { styles as i } from "./GroupBox.styles.js";
@@ -1,5 +1,5 @@
1
- import e from "../_virtual/_@oxc-project_runtime@0.147.0/helpers/esm/decorateMetadata.js";
2
- import t from "../_virtual/_@oxc-project_runtime@0.147.0/helpers/esm/decorate.js";
1
+ import e from "../_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorateMetadata.js";
2
+ import t from "../_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorate.js";
3
3
  import { StyledElement as n } from "../internals/StyledElement.js";
4
4
  import { styles as r } from "./InfoField.styles.js";
5
5
  import { html as i } from "lit";
@@ -1,5 +1,5 @@
1
- import e from "../_virtual/_@oxc-project_runtime@0.147.0/helpers/esm/decorateMetadata.js";
2
- import t from "../_virtual/_@oxc-project_runtime@0.147.0/helpers/esm/decorate.js";
1
+ import e from "../_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorateMetadata.js";
2
+ import t from "../_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorate.js";
3
3
  import { StyledElement as n } from "../internals/StyledElement.js";
4
4
  import { styles as r } from "./InfoSection.styles.js";
5
5
  import { html as i } from "lit";
@@ -1,5 +1,5 @@
1
- import e from "../_virtual/_@oxc-project_runtime@0.147.0/helpers/esm/decorateMetadata.js";
2
- import t from "../_virtual/_@oxc-project_runtime@0.147.0/helpers/esm/decorate.js";
1
+ import e from "../_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorateMetadata.js";
2
+ import t from "../_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorate.js";
3
3
  import { StyledElement as n } from "../internals/StyledElement.js";
4
4
  import { getLocaleStrings as r } from "../internals/locale.js";
5
5
  import { slotHasContent as i } from "../internals/slotted.js";
@@ -1,5 +1,5 @@
1
- import e from "../_virtual/_@oxc-project_runtime@0.147.0/helpers/esm/decorateMetadata.js";
2
- import t from "../_virtual/_@oxc-project_runtime@0.147.0/helpers/esm/decorate.js";
1
+ import e from "../_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorateMetadata.js";
2
+ import t from "../_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorate.js";
3
3
  import { StyledElement as n } from "../internals/StyledElement.js";
4
4
  import { getLocaleStrings as r } from "../internals/locale.js";
5
5
  import { slotHasContent as i } from "../internals/slotted.js";
@@ -1,5 +1,5 @@
1
- import e from "../_virtual/_@oxc-project_runtime@0.147.0/helpers/esm/decorateMetadata.js";
2
- import t from "../_virtual/_@oxc-project_runtime@0.147.0/helpers/esm/decorate.js";
1
+ import e from "../_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorateMetadata.js";
2
+ import t from "../_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorate.js";
3
3
  import { StyledElement as n } from "../internals/StyledElement.js";
4
4
  import { DEFAULT_NAV_ICON as r } from "../internals/nav-icon.js";
5
5
  import { styles as i } from "./SidebarButton.styles.js";
@@ -1,5 +1,5 @@
1
- import e from "../_virtual/_@oxc-project_runtime@0.147.0/helpers/esm/decorateMetadata.js";
2
- import t from "../_virtual/_@oxc-project_runtime@0.147.0/helpers/esm/decorate.js";
1
+ import e from "../_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorateMetadata.js";
2
+ import t from "../_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorate.js";
3
3
  import { StyledElement as n } from "../internals/StyledElement.js";
4
4
  import { DEFAULT_NAV_ICON as r } from "../internals/nav-icon.js";
5
5
  import { SidebarLink as i } from "./SidebarLink.js";
@@ -1,5 +1,5 @@
1
- import e from "../_virtual/_@oxc-project_runtime@0.147.0/helpers/esm/decorateMetadata.js";
2
- import t from "../_virtual/_@oxc-project_runtime@0.147.0/helpers/esm/decorate.js";
1
+ import e from "../_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorateMetadata.js";
2
+ import t from "../_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorate.js";
3
3
  import { StyledElement as n } from "../internals/StyledElement.js";
4
4
  import { DEFAULT_NAV_ICON as r } from "../internals/nav-icon.js";
5
5
  import { styles as i } from "./SidebarLink.styles.js";
@@ -1,5 +1,5 @@
1
- import e from "../_virtual/_@oxc-project_runtime@0.147.0/helpers/esm/decorateMetadata.js";
2
- import t from "../_virtual/_@oxc-project_runtime@0.147.0/helpers/esm/decorate.js";
1
+ import e from "../_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorateMetadata.js";
2
+ import t from "../_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorate.js";
3
3
  import { StyledElement as n } from "../internals/StyledElement.js";
4
4
  import { styles as r } from "./SidebarSection.styles.js";
5
5
  import { html as i } from "lit";
@@ -1,5 +1,5 @@
1
- import e from "../_virtual/_@oxc-project_runtime@0.147.0/helpers/esm/decorateMetadata.js";
2
- import t from "../_virtual/_@oxc-project_runtime@0.147.0/helpers/esm/decorate.js";
1
+ import e from "../_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorateMetadata.js";
2
+ import t from "../_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorate.js";
3
3
  import { StyledElement as n } from "../internals/StyledElement.js";
4
4
  import { getLocaleStrings as r } from "../internals/locale.js";
5
5
  import { styles as i } from "./Wizard.styles.js";
@@ -1,5 +1,5 @@
1
- import e from "../_virtual/_@oxc-project_runtime@0.147.0/helpers/esm/decorateMetadata.js";
2
- import t from "../_virtual/_@oxc-project_runtime@0.147.0/helpers/esm/decorate.js";
1
+ import e from "../_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorateMetadata.js";
2
+ import t from "../_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorate.js";
3
3
  import { property as n } from "lit/decorators.js";
4
4
  import { UElement as r } from "@iyulab/components/dist/components/UElement.js";
5
5
  //#region src/internals/StyledElement.ts
@@ -1,7 +1,7 @@
1
1
  import { app as e } from "../App.js";
2
2
  import { filterSidebarItems as t } from "./filterSidebarItems.js";
3
- import n from "../_virtual/_@oxc-project_runtime@0.147.0/helpers/esm/decorateMetadata.js";
4
- import r from "../_virtual/_@oxc-project_runtime@0.147.0/helpers/esm/decorate.js";
3
+ import n from "../_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorateMetadata.js";
4
+ import r from "../_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorate.js";
5
5
  import { StyledElement as i } from "../internals/StyledElement.js";
6
6
  import { getLocaleStrings as a } from "../internals/locale.js";
7
7
  import "../components/SidebarSection.js";
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.18.11",
4
+ "version": "0.18.16",
5
5
  "keywords": [
6
6
  "iyulab",
7
7
  "web-framework",
@@ -105,7 +105,7 @@ await app.warning('Check your input');
105
105
  await app.error('Something went wrong');
106
106
  ```
107
107
 
108
- `position` values: `'top-right'` | `'top-left'` | `'bottom-right'` | `'bottom-left'`
108
+ `position` values: `'top-left'` | `'top-center'` | `'top-right'` | `'middle-left'` | `'middle-center'` | `'middle-right'` | `'bottom-left'` | `'bottom-center'` | `'bottom-right'`
109
109
  `duration` default: `3000` ms
110
110
 
111
111
  ---
@@ -57,11 +57,10 @@ interface ThemeInitOptions {
57
57
  * Persist the user's preference.
58
58
  * Set to `false` to disable persistence.
59
59
  * Default: localStorage with no prefix.
60
+ * `type: 'cookie'` also accepts path/domain/expires/sameSite/partitioned — see
61
+ * `@iyulab/components`'s `BrowserStorage` reference. No `'sessionStorage'` backend exists.
60
62
  */
61
- store?: false | {
62
- type: 'cookie' | 'localStorage' | 'sessionStorage';
63
- prefix?: string;
64
- };
63
+ store?: false | { type: 'localStorage'; prefix?: string } | { type: 'cookie'; prefix?: string };
65
64
 
66
65
  /** Apply built-in CSS custom properties. Default: true */
67
66
  useBuiltIn?: boolean;
@@ -72,13 +71,18 @@ interface ThemeInitOptions {
72
71
 
73
72
  ## `RouteConfig`
74
73
 
74
+ `RouteConfig` is re-exported unchanged from `@iyulab/router` — see its README for the full
75
+ reference. Supports `children: RouteConfig[]` for nested routes (a matched parent renders
76
+ its own `<u-outlet>` to host the matched child) — see `docs/routing.md`'s "Nested routes"
77
+ section for an example.
78
+
75
79
  ```typescript
76
80
  interface RouteConfig {
77
81
  /** Matches the root path (equivalent to `path: ''`). */
78
82
  index?: boolean;
79
83
 
80
- /** Path string. Supports `:param` segments. */
81
- path?: string;
84
+ /** Path string or `URLPattern`. Supports `:param` segments. */
85
+ path?: string | URLPattern;
82
86
 
83
87
  /** Sets `document.title` when the route activates. */
84
88
  title?: string;
@@ -86,6 +90,26 @@ interface RouteConfig {
86
90
  /** Force a re-render even if the path did not change. */
87
91
  force?: boolean;
88
92
 
93
+ /** Case-insensitive path matching. Defaults to `false`. */
94
+ ignoreCase?: boolean;
95
+
96
+ /** Identifier used internally by the router (auto-generated if omitted). */
97
+ id?: string;
98
+
99
+ /** Metadata merged parent → child, exposed on `RouteContext.metadata`. */
100
+ metadata?: Record<string, unknown>;
101
+
102
+ /**
103
+ * Guard called before this route activates.
104
+ * - Return a `string` to redirect.
105
+ * - Return `false` to cancel navigation.
106
+ * - Return `true` (or nothing) to proceed.
107
+ */
108
+ enter?: (context: RouteContext) => Promise<string | boolean> | string | boolean;
109
+
110
+ /** Child routes, matched relative to this route's path. */
111
+ children?: RouteConfig[];
112
+
89
113
  /** Render function. May be async. */
90
114
  render: (context: RouteContext) => RenderResult | Promise<RenderResult>;
91
115
  }
@@ -100,14 +124,29 @@ interface RouteContext {
100
124
  /** Full URL string. */
101
125
  href: string;
102
126
 
103
- /** Pathname portion of the URL. */
104
- pathname: string;
127
+ /** Domain name portion of the URL (e.g. `https://example.com`). */
128
+ origin: string;
105
129
 
106
130
  /** Configured basepath. */
107
131
  basepath: string;
108
132
 
133
+ /** Full path including query string and hash. */
134
+ path: string;
135
+
136
+ /** Pathname portion of the URL. */
137
+ pathname: string;
138
+
109
139
  /** Named URL parameters extracted from the path pattern. */
110
- params: Record<string, string>;
140
+ params: Record<string, string | undefined>;
141
+
142
+ /** Parsed query string. `query.get('key')` returns `string | null`. */
143
+ query: URLSearchParams;
144
+
145
+ /** Hash portion of the URL, if present. */
146
+ hash?: string;
147
+
148
+ /** Metadata merged parent → child from the matched route chain. */
149
+ metadata: Record<string, unknown>;
111
150
 
112
151
  /**
113
152
  * Report loading progress (0–100).
@@ -123,12 +162,12 @@ interface RouteContext {
123
162
 
124
163
  ```typescript
125
164
  interface FallbackRouteConfig {
126
- render: (context: RouteContext) => RenderResult | Promise<RenderResult>;
165
+ render: (context: RouteContext & { error: RouteError }) => RenderResult | Promise<RenderResult>;
127
166
  }
128
167
  ```
129
168
 
130
- The fallback `RouteContext` will include an `error` property when triggered by
131
- a routing error.
169
+ `RouteError` is importable from `@iyulab/router` (`code`/`original`/`timestamp` alongside the
170
+ inherited `message`) — always populated when the fallback fires.
132
171
 
133
172
  ---
134
173
 
@@ -149,7 +188,9 @@ type I18nInitOptions = i18next.InitOptions & {
149
188
  interface NotificationOptions {
150
189
  title?: string;
151
190
  duration?: number; // milliseconds, default 3000
152
- position?: 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left';
191
+ position?: 'top-left' | 'top-center' | 'top-right'
192
+ | 'middle-left' | 'middle-center' | 'middle-right'
193
+ | 'bottom-left' | 'bottom-center' | 'bottom-right';
153
194
  }
154
195
  ```
155
196
 
@@ -18,6 +18,12 @@ interface SidebarLayoutConfig {
18
18
  /** Footer (bottom-pinned) items. */
19
19
  footer?: SidebarItem[];
20
20
 
21
+ /** Accessible name for the main nav landmark (`<nav class="sidebar-main">`), reflected as `aria-label`. Unset by default. */
22
+ mainAriaLabel?: string;
23
+
24
+ /** Permission filter — hides items (and emptied section/groups) whose requirement fails. Unset shows everything. See "권한 기반 메뉴 필터" below. */
25
+ hasPermission?: (code: string) => boolean;
26
+
21
27
  /** Per-part style overrides (CSS custom properties / inline styles). */
22
28
  styles?: StyleMap<SidebarParts>;
23
29
  }