@jbpark/live-editor 1.13.0 → 1.14.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/README.ko.md +15 -16
- package/README.md +17 -16
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -1
- package/dist/style.css +491 -706
- package/package.json +2 -4
package/README.ko.md
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
실시간 프리뷰와 드래그 앤 드롭을 지원하는 인터랙티브 UI 에디터입니다. 캔버스에서의 편집 내용은 AST 변환을 통해 실제 소스 코드에 정확히 반영되며, 결과는 DOM/CSS 격리를 위해 iframe 안에서 렌더링됩니다. React 19와 TypeScript로 구현되었습니다. iframe은 보안 샌드박스가 아닙니다 — [보안 참고사항](#-보안-참고사항)을 확인하세요.
|
|
6
6
|
|
|
7
|
+
📖 **문서 & 라이브 데모:** https://live-editor-lab.vercel.app
|
|
8
|
+
|
|
7
9
|
## 📁 프로젝트 구조
|
|
8
10
|
|
|
9
11
|
```text
|
|
@@ -17,14 +19,13 @@ live-editor/
|
|
|
17
19
|
│ │ ├─ Frame/ # iframe/shadow DOM 프리뷰 격리
|
|
18
20
|
│ │ └─ Preview/ # 격리된 프리뷰 런타임
|
|
19
21
|
│ ├─ pages/
|
|
20
|
-
│ │
|
|
21
|
-
│ │ ├─ Editor/ # 전체 에디터 앱 (에디터 + DnD 전환)
|
|
22
|
-
│ │ ├─ Playground/ # 데이터 바인딩 설정 테스트 페이지
|
|
23
|
-
│ │ └─ Preview/ # 전체화면 프리뷰 페이지
|
|
22
|
+
│ │ └─ Editor/ # 로컬 개발용 에디터 (에디터 + DnD 전환)
|
|
24
23
|
│ ├─ utils/ast/ # AST 조작 및 코드 생성
|
|
25
24
|
│ ├─ constants/ # 상수 및 설정
|
|
26
25
|
│ ├─ types/ # TypeScript 타입 정의
|
|
27
|
-
│ └─ main.tsx #
|
|
26
|
+
│ └─ main.tsx # 로컬 개발 앱 엔트리
|
|
27
|
+
├─ demos/ # 문서용 독립 iframe 데모
|
|
28
|
+
├─ website/ # Docusaurus 문서 사이트
|
|
28
29
|
└─ package.json
|
|
29
30
|
```
|
|
30
31
|
|
|
@@ -36,7 +37,6 @@ live-editor/
|
|
|
36
37
|
- **스마트 Items 에디터**: 배열 아이템을 추가/이동/삭제하고, 일반 속성과 중첩된 JSX 컴포넌트를 편집합니다. 순서 변경 시에도 안정적인 컴포넌트 ID를 유지합니다.
|
|
37
38
|
- **프리뷰 런타임**: 컴파일된 결과를 DOM/CSS 격리를 위해 iframe 안에서 렌더링합니다 (보안 샌드박스는 아닙니다 — [보안 참고사항](#-보안-참고사항) 참고).
|
|
38
39
|
- **강력한 드래그 앤 드롭**: `@dnd-kit` 기반으로 부드러운 정렬과 배치를 지원합니다.
|
|
39
|
-
- **저장 & 미리보기**: 작성한 코드를 localStorage에 저장하고 전용 전체화면 미리보기 페이지(`/preview`)에서 확인할 수 있습니다.
|
|
40
40
|
|
|
41
41
|
## 🔒 보안 참고사항
|
|
42
42
|
|
|
@@ -46,34 +46,33 @@ live-editor/
|
|
|
46
46
|
|
|
47
47
|
## 🧰 기술 스택
|
|
48
48
|
|
|
49
|
-
- **Core**: React 19, TypeScript
|
|
50
|
-
- **Routing**: `react-router-dom` (SPA 네비게이션)
|
|
49
|
+
- **Core**: React 19, TypeScript 6, Vite 8
|
|
51
50
|
- **DnD**: `@dnd-kit/core`, `@dnd-kit/sortable`, `@dnd-kit/modifiers`
|
|
52
51
|
- **Editor**: `@uiw/react-codemirror` (VSCode 테마)
|
|
53
|
-
- **UI/스타일**:
|
|
52
|
+
- **UI/스타일**: `@jbpark/ui-kit`, `lucide-react`, Tailwind CSS 4
|
|
54
53
|
- **변환**: Babel(standalone) 기반 브라우저 내 변환
|
|
55
54
|
|
|
56
55
|
## ⚙️ 요구 사항
|
|
57
56
|
|
|
58
57
|
- Peer dependencies: `react >=19`, `react-dom >=19`
|
|
59
58
|
- Node.js: 20.x 이상
|
|
60
|
-
- **pnpm**:
|
|
59
|
+
- **pnpm**: 10.x 이상 ([Corepack](https://nodejs.org/api/corepack.html)으로 관리)
|
|
61
60
|
|
|
62
61
|
## 🚀 시작하기
|
|
63
62
|
|
|
64
63
|
### pnpm 설정 (권장)
|
|
65
64
|
|
|
66
|
-
본 프로젝트는 **pnpm@
|
|
65
|
+
본 프로젝트는 **pnpm@10**을 [Corepack](https://nodejs.org/api/corepack.html)으로 관리합니다. Corepack을 활성화하고 지정된 버전을 적용하세요:
|
|
67
66
|
|
|
68
67
|
```bash
|
|
69
68
|
corepack enable
|
|
70
|
-
corepack prepare pnpm@
|
|
69
|
+
corepack prepare pnpm@10.29.3 --activate
|
|
71
70
|
```
|
|
72
71
|
|
|
73
72
|
또는 수동으로 설치:
|
|
74
73
|
|
|
75
74
|
```bash
|
|
76
|
-
npm install -g pnpm@
|
|
75
|
+
npm install -g pnpm@10
|
|
77
76
|
```
|
|
78
77
|
|
|
79
78
|
### 설치
|
|
@@ -88,6 +87,8 @@ pnpm install
|
|
|
88
87
|
pnpm run dev
|
|
89
88
|
```
|
|
90
89
|
|
|
90
|
+
루트 경로에서 로컬 에디터가 실행됩니다. 공개 문서와 기능별 데모는 `website/`에 있습니다.
|
|
91
|
+
|
|
91
92
|
### 빌드
|
|
92
93
|
|
|
93
94
|
```bash
|
|
@@ -121,9 +122,7 @@ CI 워크플로우:
|
|
|
121
122
|
- `version.yml`: changeset이 쌓이면 "Version Packages" PR을 열거나 갱신
|
|
122
123
|
- `publish.yml`: `main` 머지 시 버전이 미태그 상태면 빌드/(공개 패키지면 배포)/태그/GitHub Release 생성
|
|
123
124
|
- `release.yml`: 기존 태그에 대한 GitHub Release를 수동(`workflow_dispatch`)으로 재생성하는 백업 유틸리티
|
|
124
|
-
-
|
|
125
|
-
|
|
126
|
-
참고: GitHub Pages 사용 시 저장소 설정에서 Pages Source를 "GitHub Actions"로 지정하세요. 저장소 서브경로로 배포한다면 `vite.config.ts`의 `base` 값을 경로에 맞게 설정해야 합니다.
|
|
125
|
+
- Docusaurus 문서 사이트는 `website/`에서 빌드되며 Vercel로 배포됩니다(`vercel.json` 참고).
|
|
127
126
|
|
|
128
127
|
## 📄 라이선스
|
|
129
128
|
|
package/README.md
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
An interactive editor for building UIs with real-time preview and drag‑and‑drop. Canvas edits are synced back to source code via AST transforms, and the result renders inside an iframe for DOM/CSS isolation. Built with React 19 and TypeScript. See [Security Notes](#-security-notes) — the iframe is not a security sandbox.
|
|
6
6
|
|
|
7
|
+
📖 **Documentation & live demos:** https://live-editor-lab.vercel.app
|
|
8
|
+
|
|
7
9
|
## 📁 Project Structure
|
|
8
10
|
|
|
9
11
|
```text
|
|
@@ -17,14 +19,13 @@ live-editor/
|
|
|
17
19
|
│ │ ├─ Frame/ # iframe/shadow-DOM preview isolation
|
|
18
20
|
│ │ └─ Preview/ # Isolated preview runtime
|
|
19
21
|
│ ├─ pages/
|
|
20
|
-
│ │
|
|
21
|
-
│ │ ├─ Editor/ # Full editor app (editor + DnD toggle)
|
|
22
|
-
│ │ ├─ Playground/ # Data-binding config test page
|
|
23
|
-
│ │ └─ Preview/ # Full-screen preview page
|
|
22
|
+
│ │ └─ Editor/ # Local development editor (editor + DnD toggle)
|
|
24
23
|
│ ├─ utils/ast/ # AST manipulation & code generation
|
|
25
24
|
│ ├─ constants/ # Constants and configurations
|
|
26
25
|
│ ├─ types/ # TypeScript type definitions
|
|
27
|
-
│ └─ main.tsx #
|
|
26
|
+
│ └─ main.tsx # Local development app entry
|
|
27
|
+
├─ demos/ # Standalone iframe demos for the documentation
|
|
28
|
+
├─ website/ # Docusaurus documentation site
|
|
28
29
|
└─ package.json
|
|
29
30
|
```
|
|
30
31
|
|
|
@@ -36,7 +37,6 @@ live-editor/
|
|
|
36
37
|
- **Smart Items editor**: Manage array items with add/move/delete operations, edit properties and nested JSX components with stable component identity across reorders.
|
|
37
38
|
- **Preview runtime**: Renders compiled output inside an iframe for DOM/CSS isolation (not a security sandbox — see [Security Notes](#-security-notes)).
|
|
38
39
|
- **Robust drag-and-drop**: Powered by `@dnd-kit` for smooth sorting and positioning.
|
|
39
|
-
- **Save & Preview**: Save your code to localStorage and view it in a dedicated full-screen preview page (`/preview`).
|
|
40
40
|
|
|
41
41
|
## 🔒 Security Notes
|
|
42
42
|
|
|
@@ -46,34 +46,33 @@ live-editor/
|
|
|
46
46
|
|
|
47
47
|
## 🧰 Tech Stack
|
|
48
48
|
|
|
49
|
-
- **Core**: React 19, TypeScript
|
|
50
|
-
- **Routing**: `react-router-dom` for SPA navigation
|
|
49
|
+
- **Core**: React 19, TypeScript 6, Vite 8
|
|
51
50
|
- **DnD**: `@dnd-kit/core`, `@dnd-kit/sortable`, `@dnd-kit/modifiers`
|
|
52
51
|
- **Editor**: `@uiw/react-codemirror` with VSCode theme
|
|
53
|
-
- **UI/Styling**:
|
|
52
|
+
- **UI/Styling**: `@jbpark/ui-kit`, `lucide-react`, Tailwind CSS 4
|
|
54
53
|
- **Transform**: Babel (standalone) for in-browser transforms
|
|
55
54
|
|
|
56
55
|
## ⚙️ Requirements
|
|
57
56
|
|
|
58
57
|
- Peer deps: `react >=19`, `react-dom >=19`
|
|
59
58
|
- Node.js: 20.x or higher
|
|
60
|
-
- **pnpm**:
|
|
59
|
+
- **pnpm**: 10.x or higher (managed via [Corepack](https://nodejs.org/api/corepack.html))
|
|
61
60
|
|
|
62
61
|
## 🚀 Getting Started
|
|
63
62
|
|
|
64
63
|
### pnpm Setup (Recommended)
|
|
65
64
|
|
|
66
|
-
This project uses **pnpm@
|
|
65
|
+
This project uses **pnpm@10** with [Corepack](https://nodejs.org/api/corepack.html) for reproducibility. Enable Corepack and activate the specified pnpm version:
|
|
67
66
|
|
|
68
67
|
```bash
|
|
69
68
|
corepack enable
|
|
70
|
-
corepack prepare pnpm@
|
|
69
|
+
corepack prepare pnpm@10.29.3 --activate
|
|
71
70
|
```
|
|
72
71
|
|
|
73
72
|
Or, if you prefer a manual install:
|
|
74
73
|
|
|
75
74
|
```bash
|
|
76
|
-
npm install -g pnpm@
|
|
75
|
+
npm install -g pnpm@10
|
|
77
76
|
```
|
|
78
77
|
|
|
79
78
|
### Install
|
|
@@ -88,6 +87,9 @@ pnpm install
|
|
|
88
87
|
pnpm run dev
|
|
89
88
|
```
|
|
90
89
|
|
|
90
|
+
This starts the local editor at the root route. The public documentation and
|
|
91
|
+
feature demos live in `website/`.
|
|
92
|
+
|
|
91
93
|
### Build
|
|
92
94
|
|
|
93
95
|
```bash
|
|
@@ -121,9 +123,8 @@ CI workflows:
|
|
|
121
123
|
- `version.yml`: Opens/updates the "Version Packages" PR once changesets accumulate.
|
|
122
124
|
- `publish.yml`: Builds/(publishes if public)/tags/creates the GitHub Release on merge to `main` when the version is untagged.
|
|
123
125
|
- `release.yml`: Manual `workflow_dispatch` fallback to (re)create a GitHub Release for an existing tag.
|
|
124
|
-
-
|
|
125
|
-
|
|
126
|
-
Note: For GitHub Pages, set the repository Pages source to “GitHub Actions”. If deploying under a repo subpath, configure `base` in `vite.config.ts` accordingly.
|
|
126
|
+
- The Docusaurus documentation site is built from `website/` and deployed via
|
|
127
|
+
Vercel (see `vercel.json`).
|
|
127
128
|
|
|
128
129
|
## 📄 License
|
|
129
130
|
|
package/dist/index.js
CHANGED
|
@@ -100,6 +100,20 @@ const UNIT_MAP = {
|
|
|
100
100
|
const UNITS_PATTERN = Object.keys(UNIT_MAP).sort((a, b) => b.length - a.length).join("|");
|
|
101
101
|
const VIEWPORT_UNIT_RE = new RegExp(`(?<![\\w.-])(-?(?:\\d+\\.?\\d*|\\.\\d+))(${UNITS_PATTERN})(?![a-zA-Z0-9_-])`, "gi");
|
|
102
102
|
const convertViewportUnits = (css) => css.replace(VIEWPORT_UNIT_RE, (_match, number, unit) => number + UNIT_MAP[unit.toLowerCase()]);
|
|
103
|
+
const rewriteInlineViewportUnits = (root) => {
|
|
104
|
+
root.querySelectorAll("[style*=\"vh\" i], [style*=\"vmin\" i], [style*=\"vmax\" i]").forEach((el) => {
|
|
105
|
+
const current = el.getAttribute("style");
|
|
106
|
+
if (current == null) return;
|
|
107
|
+
const converted = convertViewportUnits(current);
|
|
108
|
+
if (converted !== current) el.setAttribute("style", converted);
|
|
109
|
+
});
|
|
110
|
+
root.querySelectorAll("style").forEach((styleEl) => {
|
|
111
|
+
const current = styleEl.textContent;
|
|
112
|
+
if (!current) return;
|
|
113
|
+
const converted = convertViewportUnits(current);
|
|
114
|
+
if (converted !== current) styleEl.textContent = converted;
|
|
115
|
+
});
|
|
116
|
+
};
|
|
103
117
|
//#endregion
|
|
104
118
|
//#region src/components/frame/iframe.tsx
|
|
105
119
|
const EMPTY_STRING_ARRAY = [];
|
|
@@ -289,6 +303,7 @@ const IFrame = ({ title = "Live Preview", sandbox, style = {}, scripts = EMPTY_S
|
|
|
289
303
|
let contentHeight = 0;
|
|
290
304
|
withMeasurementOverrides(doc, () => {
|
|
291
305
|
ensureContainerStyle(doc, probeHeight);
|
|
306
|
+
rewriteInlineViewportUnits(mountNode);
|
|
292
307
|
contentHeight = mountNode.scrollHeight;
|
|
293
308
|
mountNode.querySelectorAll("*").forEach((el) => {
|
|
294
309
|
const style = win.getComputedStyle(el);
|