@iyulab/modern-app 0.15.0 → 0.17.0
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 +27 -0
- package/README.md +32 -0
- package/dist/components/InfoField.js +1 -1
- package/dist/layouts/SidebarLayout.styles.js +10 -1
- package/dist/layouts/SidebarLayout.types.d.ts +4 -0
- package/dist/react.d.ts +25 -0
- package/dist/react.js +18 -0
- package/package.json +25 -2
- package/skills/modern-app/references/components/master-detail-layout.md +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.17.0] - 2026-08-11
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **`/react` subpath**, wrapping `SidebarLayout` and `Wizard` with `@lit/react`'s
|
|
8
|
+
`createComponent`. `Wizard` is the only component that dispatches a custom event
|
|
9
|
+
(`step-change`) — a raw custom element in JSX maps an `onStepChange` prop to a listener
|
|
10
|
+
for a literal `"StepChange"` DOM event, which `Wizard` never fires, so the event never
|
|
11
|
+
reaches a consumer without this wrapper. Both components also carry object/array
|
|
12
|
+
properties (`config`, `steps`) that a raw custom element handles correctly under React 19
|
|
13
|
+
(which assigns matching properties directly) but not under React 18 (where non-primitive
|
|
14
|
+
JSX attributes stringify) — the wrapper keeps that working on both. Every component in
|
|
15
|
+
this package (not just these two) also inherits an object-typed `styles` property from its
|
|
16
|
+
base class for part-level style overrides; on React 18 that still needs a ref without a
|
|
17
|
+
wrapper.
|
|
18
|
+
|
|
19
|
+
## [0.16.0] - 2026-08-11
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
|
|
23
|
+
- **`SidebarLayout`'s main content area now ships a default padding**
|
|
24
|
+
(`var(--u-space-3xl, 32px)`) instead of none. Every consumer previously had to add this
|
|
25
|
+
themselves to keep route content off the viewport/sidebar edge. Full-bleed layouts (e.g. a
|
|
26
|
+
dashboard whose table should reach the panel edge) can still opt back to `0` via
|
|
27
|
+
`styles.main`. This is a visible rendering change for any consumer that never set
|
|
28
|
+
`styles.main` — hence the minor bump rather than a patch.
|
|
29
|
+
|
|
3
30
|
## [0.15.0] - 2026-08-11
|
|
4
31
|
|
|
5
32
|
### Added
|
package/README.md
CHANGED
|
@@ -173,6 +173,38 @@ await app.load({
|
|
|
173
173
|
- `hasPermission` 미지정 시 필터링하지 않는다(모든 항목 표시 — 하위호환).
|
|
174
174
|
- 순수 헬퍼 `filterSidebarItems(items, hasPermission)` 를 직접 재사용할 수도 있다.
|
|
175
175
|
|
|
176
|
+
## React
|
|
177
|
+
|
|
178
|
+
A `@lit/react`-based wrapper for `SidebarLayout` and `Wizard` is available under `/react`.
|
|
179
|
+
Every other exported component works as a plain custom element in JSX; these two specifically
|
|
180
|
+
need the wrapper because `Wizard` dispatches a `step-change` custom event (a raw element maps
|
|
181
|
+
`onStepChange` to a literal `"StepChange"` DOM event it never fires) and both carry object/array
|
|
182
|
+
properties that a raw element only handles correctly under React 19.
|
|
183
|
+
|
|
184
|
+
`@lit/react` and `react` are optional peer dependencies — install them to use this subpath:
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
npm install @iyulab/modern-app @lit/react react
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
```tsx
|
|
191
|
+
import { SidebarLayout, Wizard, type SidebarItem, type WizardStep } from '@iyulab/modern-app/react';
|
|
192
|
+
|
|
193
|
+
const main: SidebarItem[] = [{ type: 'link', label: 'Home', href: '/' }];
|
|
194
|
+
const steps: WizardStep[] = [{ id: 'info', label: 'Info' }, { id: 'review', label: 'Review' }];
|
|
195
|
+
|
|
196
|
+
export function App() {
|
|
197
|
+
return (
|
|
198
|
+
<SidebarLayout config={{ type: 'sidebar', title: 'My App', main }}>
|
|
199
|
+
<Wizard steps={steps} active={0} onStepChange={(e) => console.log(e.detail)}>
|
|
200
|
+
<section>Info panel</section>
|
|
201
|
+
<section>Review panel</section>
|
|
202
|
+
</Wizard>
|
|
203
|
+
</SidebarLayout>
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
176
208
|
## Documentation
|
|
177
209
|
|
|
178
210
|
| Guide | Description |
|
|
@@ -4,7 +4,7 @@ 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";
|
|
6
6
|
import { customElement as a, property as o } from "lit/decorators.js";
|
|
7
|
-
import { formatCurrency as s, formatDate as c, formatNumber as l } from "@iyulab/components";
|
|
7
|
+
import { formatCurrency as s, formatDate as c, formatNumber as l } from "@iyulab/components/dist/utilities/format.js";
|
|
8
8
|
//#region src/components/InfoField.ts
|
|
9
9
|
function u(e) {
|
|
10
10
|
return e === "up" ? "positive" : e === "down" ? "negative" : "neutral";
|
|
@@ -165,10 +165,19 @@ var t = e`
|
|
|
165
165
|
display: none;
|
|
166
166
|
}
|
|
167
167
|
|
|
168
|
-
/* Main Content
|
|
168
|
+
/* Main Content
|
|
169
|
+
* ★기본 패딩을 준다 — 라우트 콘텐츠가 뷰포트/사이드바 경계에 그대로 맞닿아 모든
|
|
170
|
+
* 소비자가 같은 배선을 재구현하던 문제였다. 값은 이 라이브러리의 spacing 스케일
|
|
171
|
+
* 상단 근처(3xl)에서 골랐다 — LOB 화면의 표준 여백으로 쓰기에 과하지 않은 최대값.
|
|
172
|
+
* ⚠«패딩 박스» 기준 절대배치는 이 padding 의 영향을 받지 않는다 — 바로 아래
|
|
173
|
+
* u-progress-bar 가 top/left/right:0 으로 여전히 테두리에 꽉 차게 붙는 이유다
|
|
174
|
+
* (CSS 2.1 §10.6.4: 절대배치 자손의 containing block 은 가장 가까운 positioned
|
|
175
|
+
* 조상의 «패딩 박스»이고, 그 경계는 조상 자신의 padding 값에 밀리지 않는다).
|
|
176
|
+
* 풀블리드를 원하는 소비자는 layout.styles.main = { padding: '0' } 로 되돌린다. */
|
|
169
177
|
.main {
|
|
170
178
|
position: relative;
|
|
171
179
|
flex: 1;
|
|
180
|
+
padding: var(--u-space-3xl, 32px);
|
|
172
181
|
background: var(--u-bg-color, #FFFFFF);
|
|
173
182
|
overflow: auto;
|
|
174
183
|
outline: none;
|
|
@@ -6,6 +6,10 @@ import { SidebarGroupConfig } from '../components/SidebarGroup';
|
|
|
6
6
|
import { SidebarButtonConfig } from '../components/SidebarButton';
|
|
7
7
|
import { SidebarPermissionGuard } from './SidebarPermission';
|
|
8
8
|
export type { SidebarPermissionGuard } from './SidebarPermission';
|
|
9
|
+
export type { SidebarLinkConfig } from '../components/SidebarLink';
|
|
10
|
+
export type { SidebarSectionConfig } from '../components/SidebarSection';
|
|
11
|
+
export type { SidebarGroupConfig } from '../components/SidebarGroup';
|
|
12
|
+
export type { SidebarButtonConfig } from '../components/SidebarButton';
|
|
9
13
|
/** 사이드바 레이아웃 컴포넌트의 요소(part) 타입 */
|
|
10
14
|
export type SidebarParts = 'host' | 'mobile-header' | 'sidebar' | 'sidebar-header' | 'sidebar-main' | 'sidebar-footer' | 'main' | 'progress';
|
|
11
15
|
/** 사이드바 상태 타입 */
|
package/dist/react.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
import { EventName } from '@lit/react';
|
|
3
|
+
import { SidebarLayout as SidebarLayoutElement } from './layouts/SidebarLayout.js';
|
|
4
|
+
import { Wizard as WizardElement, WizardStepChangeDetail } from './components/Wizard.js';
|
|
5
|
+
/**
|
|
6
|
+
* React wrapper for `<u-sidebar-layout>`. `config` is an `@property({ type: Object })` —
|
|
7
|
+
* a raw custom element handles that correctly under React 19 (property assignment) but not
|
|
8
|
+
* React 18 (JSX attributes stringify), so this wrapper keeps `config` working on both.
|
|
9
|
+
*/
|
|
10
|
+
export declare const SidebarLayout: import('@lit/react').ReactWebComponent<SidebarLayoutElement, {}>;
|
|
11
|
+
export type SidebarLayoutProps = React.ComponentProps<typeof SidebarLayout>;
|
|
12
|
+
/**
|
|
13
|
+
* React wrapper for `<u-wizard>`. `Wizard` dispatches a `step-change` custom event, but a raw
|
|
14
|
+
* custom element in JSX maps `onStepChange` to a listener for a literal `"StepChange"` DOM
|
|
15
|
+
* event — one `Wizard` never fires — so the event never reaches a consumer without this
|
|
16
|
+
* wrapper's `events` mapping. `steps` is also an `@property({ type: Array })`, which the
|
|
17
|
+
* wrapper keeps working on React 18 the same way it does for `SidebarLayout`'s `config`.
|
|
18
|
+
*/
|
|
19
|
+
export declare const Wizard: import('@lit/react').ReactWebComponent<WizardElement, {
|
|
20
|
+
onStepChange: EventName<CustomEvent<WizardStepChangeDetail>>;
|
|
21
|
+
}>;
|
|
22
|
+
export type WizardProps = React.ComponentProps<typeof Wizard>;
|
|
23
|
+
export type { SidebarLayoutElement, WizardElement };
|
|
24
|
+
export type { SidebarLayoutConfig, SidebarItem, SidebarLogoConfig, SidebarLinkConfig, SidebarSectionConfig, SidebarGroupConfig, SidebarButtonConfig, SidebarHtmlConfig, } from './layouts/SidebarLayout.types.js';
|
|
25
|
+
export type { WizardStep, WizardStepState, WizardStepChangeDetail } from './components/Wizard.js';
|
package/dist/react.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Wizard as e } from "./components/Wizard.js";
|
|
2
|
+
import { SidebarLayout as t } from "./layouts/SidebarLayout.js";
|
|
3
|
+
import n from "react";
|
|
4
|
+
import { createComponent as r } from "@lit/react";
|
|
5
|
+
//#region src/react.ts
|
|
6
|
+
var i = r({
|
|
7
|
+
react: n,
|
|
8
|
+
tagName: "u-sidebar-layout",
|
|
9
|
+
elementClass: t,
|
|
10
|
+
events: {}
|
|
11
|
+
}), a = r({
|
|
12
|
+
react: n,
|
|
13
|
+
tagName: "u-wizard",
|
|
14
|
+
elementClass: e,
|
|
15
|
+
events: { onStepChange: "step-change" }
|
|
16
|
+
});
|
|
17
|
+
//#endregion
|
|
18
|
+
export { i as SidebarLayout, a as Wizard };
|
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.
|
|
4
|
+
"version": "0.17.0",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"iyulab",
|
|
7
7
|
"web-framework",
|
|
@@ -32,13 +32,19 @@
|
|
|
32
32
|
"./dist/index.js",
|
|
33
33
|
"./src/index.ts",
|
|
34
34
|
"./dist/layouts/*.js",
|
|
35
|
-
"./src/layouts/*.ts"
|
|
35
|
+
"./src/layouts/*.ts",
|
|
36
|
+
"./dist/react.js",
|
|
37
|
+
"./src/react.ts"
|
|
36
38
|
],
|
|
37
39
|
"exports": {
|
|
38
40
|
".": {
|
|
39
41
|
"types": "./dist/index.d.ts",
|
|
40
42
|
"import": "./dist/index.js"
|
|
41
43
|
},
|
|
44
|
+
"./react": {
|
|
45
|
+
"types": "./dist/react.d.ts",
|
|
46
|
+
"import": "./dist/react.js"
|
|
47
|
+
},
|
|
42
48
|
"./dist/*": {
|
|
43
49
|
"types": "./dist/*.d.ts",
|
|
44
50
|
"import": "./dist/*"
|
|
@@ -58,10 +64,27 @@
|
|
|
58
64
|
"i18next": "^26.3.6",
|
|
59
65
|
"lit": "^3.3.3"
|
|
60
66
|
},
|
|
67
|
+
"peerDependencies": {
|
|
68
|
+
"@lit/react": ">=1.0.8",
|
|
69
|
+
"react": ">=18.0.0"
|
|
70
|
+
},
|
|
71
|
+
"peerDependenciesMeta": {
|
|
72
|
+
"@lit/react": {
|
|
73
|
+
"optional": true
|
|
74
|
+
},
|
|
75
|
+
"react": {
|
|
76
|
+
"optional": true
|
|
77
|
+
}
|
|
78
|
+
},
|
|
61
79
|
"devDependencies": {
|
|
80
|
+
"@lit/react": "^1.0.8",
|
|
62
81
|
"@types/node": "^26.1.1",
|
|
82
|
+
"@types/react": "^19.2.14",
|
|
83
|
+
"@types/react-dom": "^19.2.3",
|
|
63
84
|
"@vitest/browser-playwright": "^4.1.10",
|
|
64
85
|
"happy-dom": "^20.10.6",
|
|
86
|
+
"react": "^19.2.7",
|
|
87
|
+
"react-dom": "^19.2.7",
|
|
65
88
|
"typescript": "^5.9.3",
|
|
66
89
|
"vite": "^8.1.4",
|
|
67
90
|
"vite-plugin-dts": "^5.0.3",
|
|
@@ -44,11 +44,11 @@ configurable breakpoint means measuring the host's own width in JavaScript and r
|
|
|
44
44
|
|
|
45
45
|
## Properties
|
|
46
46
|
|
|
47
|
-
| Property |
|
|
48
|
-
|
|
49
|
-
| `masterSize` | `
|
|
50
|
-
| `overlayBreakpoint` | `
|
|
51
|
-
| `locale` | `
|
|
47
|
+
| Property | Type | Default | Reflect | Description |
|
|
48
|
+
|----------|------|---------|---------|-------------|
|
|
49
|
+
| `masterSize` | `string` | `'22rem'` | | Fixed width of the master pane, a CSS length (`master-size`) |
|
|
50
|
+
| `overlayBreakpoint` | `number` | `760` | | Below this self width in px, detail becomes a full overlay (`overlay-breakpoint`) |
|
|
51
|
+
| `locale` | `string` | `''` | | Language tag for the close button's accessible label |
|
|
52
52
|
|
|
53
53
|
## Events
|
|
54
54
|
|