create-mendix-widget-gleam 3.0.2 → 4.0.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/README.md +7 -9
- package/package.json +1 -1
- package/src/i18n.mjs +12 -15
- package/src/index.mjs +20 -33
- package/src/templates/claude_md.mjs +9 -8
- package/src/templates/readme_md.mjs +45 -318
- package/template/docs/glendix_guide.md +178 -131
- package/template/docs/mendraw_guide.md +328 -0
- package/template/gleam.toml +3 -1
- package/template/package.json +1 -6
- package/template/src/__widget_name__.gleam +1 -1
- package/template/src/editor_config.gleam +1 -1
- package/template/src/editor_preview.gleam +1 -1
- package/src/templates/widgets_readme.mjs +0 -275
- package/template/rollup.config.mjs +0 -10
- package/template/widgets/README.md +0 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Gleam 언어로 Mendix Pluggable Widget 프로젝트를 스케폴딩하는 CLI 도구.
|
|
4
4
|
|
|
5
|
-
JSX 없이, **Gleam + [glendix](https://hexdocs.pm/glendix/)**로 React 컴포넌트를 작성하여 Mendix Studio Pro에서 동작하는 위젯을 만든다.
|
|
5
|
+
JSX 없이, **Gleam + [glendix](https://hexdocs.pm/glendix/)/[mendraw](https://hexdocs.pm/mendraw/)**로 React 컴포넌트를 작성하여 Mendix Studio Pro에서 동작하는 위젯을 만든다.
|
|
6
6
|
|
|
7
7
|
## 사용법
|
|
8
8
|
|
|
@@ -27,14 +27,12 @@ my-widget/
|
|
|
27
27
|
editor_preview.gleam # Studio Pro 디자인 뷰 미리보기
|
|
28
28
|
components/
|
|
29
29
|
hello_world.gleam # Hello World 공유 컴포넌트
|
|
30
|
-
widgets/ # .mpk 위젯 파일 (glendix/widget로 바인딩)
|
|
31
|
-
bindings.json # 외부 React 컴포넌트 바인딩 설정
|
|
32
30
|
package.json # npm 의존성 (React, 외부 라이브러리 등)
|
|
33
|
-
gleam.toml # Gleam 프로젝트 설정 (glendix >=
|
|
31
|
+
gleam.toml # Gleam 프로젝트 설정 (glendix >= 4.0.3 + mendraw >= 1.1.11 의존성 포함)
|
|
34
32
|
CLAUDE.md # AI 어시스턴트용 프로젝트 컨텍스트
|
|
35
33
|
```
|
|
36
34
|
|
|
37
|
-
React/Mendix FFI 및 JS Interop 바인딩은 프로젝트에 포함되지 않으며, [glendix](https://hexdocs.pm/glendix/) Hex 패키지로 제공된다.
|
|
35
|
+
React/Mendix FFI 및 JS Interop 바인딩은 프로젝트에 포함되지 않으며, [glendix](https://hexdocs.pm/glendix/) 및 [mendraw](https://hexdocs.pm/mendraw/) Hex 패키지로 제공된다.
|
|
38
36
|
|
|
39
37
|
## 생성 후 시작하기
|
|
40
38
|
|
|
@@ -43,7 +41,7 @@ cd my-widget
|
|
|
43
41
|
gleam run -m glendix/install # 의존성 설치
|
|
44
42
|
gleam run -m glendix/dev # 개발 서버 시작
|
|
45
43
|
gleam run -m glendix/build # 프로덕션 빌드 (.mpk 생성)
|
|
46
|
-
gleam run -m
|
|
44
|
+
gleam run -m mendraw/marketplace # Marketplace 위젯 검색/다운로드
|
|
47
45
|
gleam run -m glendix/define # 위젯 프로퍼티 정의 TUI 에디터
|
|
48
46
|
```
|
|
49
47
|
|
|
@@ -51,9 +49,9 @@ gleam run -m glendix/define # 위젯 프로퍼티 정의 TUI 에디터
|
|
|
51
49
|
|
|
52
50
|
생성된 프로젝트는 [glendix](https://hexdocs.pm/glendix/) Hex 패키지를 의존성으로 사용한다. glendix가 React 원시 함수와 Mendix Pluggable Widget API 전체에 대한 타입 안전한 Gleam 바인딩을 제공한다:
|
|
53
51
|
|
|
54
|
-
- **React** — `
|
|
55
|
-
- **Mendix** — `mendix`, `mendix/editable_value`, `mendix/action`, `mendix/list_value`, `mendix/selection`, `mendix/reference`, `mendix/reference_set`, `mendix/date`, `mendix/
|
|
56
|
-
- **JS Interop** — `js/array`, `js/object`, `js/json`, `js/promise`, `js/dom`, `js/timer`
|
|
52
|
+
- **React** — `redraw`, `redraw/dom/attribute`, `redraw/hooks`, `redraw/dom/events`, `redraw/dom/html`, `redraw/dom/svg`; bindings via `glendix/binding`
|
|
53
|
+
- **Mendix** (mendraw) — `mendraw/mendix`, `mendraw/mendix/editable_value`, `mendraw/mendix/action`, `mendraw/mendix/list_value`, `mendraw/mendix/selection`, `mendraw/mendix/reference`, `mendraw/mendix/reference_set`, `mendraw/mendix/date`, `mendraw/mendix/decimal`, `mendraw/mendix/filter` 등
|
|
54
|
+
- **JS Interop** (glendix) — `glendix/js/array`, `glendix/js/object`, `glendix/js/json`, `glendix/js/promise`, `glendix/js/dom`, `glendix/js/timer`
|
|
57
55
|
|
|
58
56
|
## 라이선스
|
|
59
57
|
|
package/package.json
CHANGED
package/src/i18n.mjs
CHANGED
|
@@ -48,11 +48,10 @@ const messages = {
|
|
|
48
48
|
"progress.depsInstalled": "Dependencies installed",
|
|
49
49
|
"error.depsInstallFail":
|
|
50
50
|
"⚠ Dependency installation failed. Run manually in the project directory:",
|
|
51
|
-
"progress.
|
|
52
|
-
"progress.
|
|
53
|
-
"
|
|
54
|
-
|
|
55
|
-
"⚠ Playwright browser installation failed. Run manually in the project directory:",
|
|
51
|
+
"progress.glendixInstalling": "Running glendix/install...",
|
|
52
|
+
"progress.glendixInstalled": "glendix/install complete",
|
|
53
|
+
"error.glendixInstallFail":
|
|
54
|
+
"⚠ glendix/install failed. Run manually:",
|
|
56
55
|
"progress.buildingWidget": "Building widget...",
|
|
57
56
|
"progress.widgetBuilt": "Widget build complete",
|
|
58
57
|
"error.buildFail":
|
|
@@ -119,11 +118,10 @@ const messages = {
|
|
|
119
118
|
"progress.depsInstalled": "의존성 설치 완료",
|
|
120
119
|
"error.depsInstallFail":
|
|
121
120
|
"⚠ 의존성 설치 실패. 프로젝트 디렉토리에서 직접 실행하세요:",
|
|
122
|
-
"progress.
|
|
123
|
-
"progress.
|
|
124
|
-
"
|
|
125
|
-
|
|
126
|
-
"⚠ Playwright 브라우저 설치 실패. 프로젝트 디렉토리에서 직접 실행하세요:",
|
|
121
|
+
"progress.glendixInstalling": "glendix/install 실행 중...",
|
|
122
|
+
"progress.glendixInstalled": "glendix/install 완료",
|
|
123
|
+
"error.glendixInstallFail":
|
|
124
|
+
"⚠ glendix/install 실패. 직접 실행하세요:",
|
|
127
125
|
"progress.buildingWidget": "위젯 빌드 중...",
|
|
128
126
|
"progress.widgetBuilt": "위젯 빌드 완료",
|
|
129
127
|
"error.buildFail":
|
|
@@ -190,11 +188,10 @@ const messages = {
|
|
|
190
188
|
"progress.depsInstalled": "依存関係インストール完了",
|
|
191
189
|
"error.depsInstallFail":
|
|
192
190
|
"⚠ 依存関係インストール失敗。プロジェクトディレクトリで直接実行してください:",
|
|
193
|
-
"progress.
|
|
194
|
-
"progress.
|
|
195
|
-
"
|
|
196
|
-
|
|
197
|
-
"⚠ Playwrightブラウザインストール失敗。プロジェクトディレクトリで直接実行してください:",
|
|
191
|
+
"progress.glendixInstalling": "glendix/installを実行中...",
|
|
192
|
+
"progress.glendixInstalled": "glendix/install完了",
|
|
193
|
+
"error.glendixInstallFail":
|
|
194
|
+
"⚠ glendix/install失敗。直接実行してください:",
|
|
198
195
|
"progress.buildingWidget": "ウィジェットビルド中...",
|
|
199
196
|
"progress.widgetBuilt": "ウィジェットビルド完了",
|
|
200
197
|
"error.buildFail":
|
package/src/index.mjs
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import { resolve, dirname, join } from "node:path";
|
|
6
6
|
import { fileURLToPath } from "node:url";
|
|
7
|
-
import { mkdir, writeFile } from "node:fs/promises";
|
|
7
|
+
import { mkdir, writeFile, readFile } from "node:fs/promises";
|
|
8
8
|
import { execSync } from "node:child_process";
|
|
9
9
|
import { collect_options } from "../tui/build/dev/javascript/tui/tui.mjs";
|
|
10
10
|
import { collectOptions } from "./prompts.mjs";
|
|
@@ -14,7 +14,6 @@ import { scaffold } from "./scaffold.mjs";
|
|
|
14
14
|
import { t, getTemplateComments, getLangLabel } from "./i18n.mjs";
|
|
15
15
|
import { generateClaudeMdContent } from "./templates/claude_md.mjs";
|
|
16
16
|
import { generateReadmeContent } from "./templates/readme_md.mjs";
|
|
17
|
-
import { generateWidgetsReadmeContent } from "./templates/widgets_readme.mjs";
|
|
18
17
|
import { generateLicenseContent } from "./licenses.mjs";
|
|
19
18
|
|
|
20
19
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
@@ -28,7 +27,9 @@ const DIM = "\x1b[2m";
|
|
|
28
27
|
const YELLOW = "\x1b[33m";
|
|
29
28
|
const MAGENTA = "\x1b[35m";
|
|
30
29
|
|
|
31
|
-
const VERSION =
|
|
30
|
+
const VERSION = JSON.parse(
|
|
31
|
+
await readFile(join(__dirname, "..", "package.json"), "utf-8"),
|
|
32
|
+
).version;
|
|
32
33
|
|
|
33
34
|
const HELP = `
|
|
34
35
|
${BOLD}create-mendix-widget-gleam${RESET} — Create Gleam + Mendix Pluggable Widget projects
|
|
@@ -66,9 +67,12 @@ const BANNER_LINES = [
|
|
|
66
67
|
|
|
67
68
|
const header = '\n' + BANNER_LINES.map(([g, l]) =>
|
|
68
69
|
`${CYAN}${BOLD}${g}${RESET}${MAGENTA}${l}${RESET}`
|
|
69
|
-
).join('\n') +
|
|
70
|
+
).join('\n') + '\n';
|
|
70
71
|
|
|
71
72
|
export async function main(args) {
|
|
73
|
+
// Ctrl+C 즉시 종료
|
|
74
|
+
process.on("SIGINT", () => process.exit(130));
|
|
75
|
+
|
|
72
76
|
// Flag handling
|
|
73
77
|
if (args.includes("--help") || args.includes("-h")) {
|
|
74
78
|
console.log(HELP);
|
|
@@ -146,7 +150,6 @@ export async function main(args) {
|
|
|
146
150
|
// Build template comments (i18n for template placeholders)
|
|
147
151
|
const templateComments = {
|
|
148
152
|
...getTemplateComments(lang),
|
|
149
|
-
widgets_readme: generateWidgetsReadmeContent(lang),
|
|
150
153
|
};
|
|
151
154
|
|
|
152
155
|
// Scaffold options
|
|
@@ -221,35 +224,19 @@ export async function main(args) {
|
|
|
221
224
|
console.error(` ${CYAN}${pmConfig.install}${RESET}\n`);
|
|
222
225
|
}
|
|
223
226
|
|
|
224
|
-
//
|
|
227
|
+
// Run glendix/install
|
|
228
|
+
console.log(`\n${BOLD}${t(lang, "progress.glendixInstalling")}${RESET}\n`);
|
|
225
229
|
try {
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
if (!chromiumExists) {
|
|
233
|
-
console.log(`\n${BOLD}${t(lang, "progress.playwrightInstalling")}${RESET}\n`);
|
|
234
|
-
try {
|
|
235
|
-
execSync("npx playwright install chromium", {
|
|
236
|
-
cwd: targetDir,
|
|
237
|
-
stdio: "inherit",
|
|
238
|
-
});
|
|
239
|
-
console.log(`\n${GREEN}✓${RESET} ${t(lang, "progress.playwrightInstalled")}`);
|
|
240
|
-
} catch {
|
|
241
|
-
console.error(
|
|
242
|
-
`\n${YELLOW}${t(lang, "error.playwrightFail")}${RESET}`,
|
|
243
|
-
);
|
|
244
|
-
console.error(
|
|
245
|
-
` ${CYAN}npx playwright install chromium${RESET}\n`,
|
|
246
|
-
);
|
|
247
|
-
}
|
|
248
|
-
} else {
|
|
249
|
-
console.log(`${GREEN}✓${RESET} ${t(lang, "progress.playwrightExists")}`);
|
|
250
|
-
}
|
|
230
|
+
execSync("gleam run -m glendix/install", {
|
|
231
|
+
cwd: targetDir,
|
|
232
|
+
stdio: "inherit",
|
|
233
|
+
});
|
|
234
|
+
console.log(`\n${GREEN}✓${RESET} ${t(lang, "progress.glendixInstalled")}`);
|
|
251
235
|
} catch {
|
|
252
|
-
|
|
236
|
+
console.error(
|
|
237
|
+
`\n${YELLOW}${t(lang, "error.glendixInstallFail")}${RESET}`,
|
|
238
|
+
);
|
|
239
|
+
console.error(` ${CYAN}gleam run -m glendix/install${RESET}\n`);
|
|
253
240
|
}
|
|
254
241
|
|
|
255
242
|
// Production build
|
|
@@ -276,7 +263,7 @@ ${BOLD}${t(lang, "done.nextSteps")}${RESET}
|
|
|
276
263
|
${CYAN}cd ${names.kebabCase}${RESET}
|
|
277
264
|
${CYAN}gleam run -m glendix/dev${RESET} ${DIM}${t(lang, "done.devServer")}${RESET}
|
|
278
265
|
${CYAN}gleam run -m glendix/build${RESET} ${DIM}${t(lang, "done.prodBuild")}${RESET}
|
|
279
|
-
${CYAN}gleam run -m
|
|
266
|
+
${CYAN}gleam run -m mendraw/marketplace${RESET} ${DIM}${t(lang, "done.marketplace")}${RESET}
|
|
280
267
|
`);
|
|
281
268
|
|
|
282
269
|
// etch TUI 이벤트 서버의 stdin 리스너가 이벤트 루프를 유지하므로 명시적 종료
|
|
@@ -15,24 +15,25 @@ export function generateClaudeMdContent(lang, names, pm, pmConfig, organization)
|
|
|
15
15
|
|
|
16
16
|
return `# ${names.pascalCase}
|
|
17
17
|
|
|
18
|
-
A project for developing Mendix Pluggable Widgets with Gleam. Widgets are implemented using only Gleam + [glendix](https://hexdocs.pm/glendix/) bindings, without JSX.
|
|
18
|
+
A project for developing Mendix Pluggable Widgets with Gleam. Widgets are implemented using only Gleam + [glendix](https://hexdocs.pm/glendix/)/[mendraw](https://hexdocs.pm/mendraw/) bindings, without JSX.
|
|
19
19
|
|
|
20
20
|
## Commands
|
|
21
21
|
|
|
22
22
|
\`\`\`bash
|
|
23
|
-
gleam run -m glendix/install # Install dependencies (Gleam deps + npm +
|
|
23
|
+
gleam run -m glendix/install # Install dependencies (Gleam deps + npm + TOML widget download + binding generation)
|
|
24
24
|
gleam run -m glendix/build # Production build (.mpk output)
|
|
25
25
|
gleam run -m glendix/dev # Dev server (HMR, port 3000)
|
|
26
26
|
gleam run -m glendix/start # Link with Mendix test project
|
|
27
27
|
gleam run -m glendix/release # Release build
|
|
28
28
|
gleam run -m glendix/lint # Run ESLint
|
|
29
29
|
gleam run -m glendix/lint_fix # ESLint auto-fix
|
|
30
|
-
gleam run -m
|
|
30
|
+
gleam run -m mendraw/marketplace # Search/download Marketplace widgets
|
|
31
|
+
gleam run -m mendraw/install # Generate widget bindings
|
|
31
32
|
gleam test # Run tests
|
|
32
33
|
gleam format # Format code
|
|
33
34
|
\`\`\`
|
|
34
35
|
|
|
35
|
-
If you add external React packages to
|
|
36
|
+
If you add external React packages to \`gleam.toml [tools.glendix.bindings]\`, install the npm package manually before running \`glendix/install\`.
|
|
36
37
|
|
|
37
38
|
## Hard Rules
|
|
38
39
|
|
|
@@ -41,7 +42,7 @@ IMPORTANT: Breaking these rules will break the build or compromise the architect
|
|
|
41
42
|
- **Do not write JSX/JS files directly.** All widget logic and UI must be written in Gleam
|
|
42
43
|
- **Do not write FFI files (.mjs) in the widget project.** React/Mendix FFI is provided by the glendix package
|
|
43
44
|
- **Do not manually manage bridge JS files (src/*.js).** glendix auto-generates/deletes them at build time
|
|
44
|
-
- **React bindings use \`redraw\`/\`redraw_dom\` packages.** glendix
|
|
45
|
+
- **React bindings use \`redraw\`/\`redraw_dom\` packages.** glendix does not provide React bindings directly
|
|
45
46
|
- The Gleam compilation output path (\`build/dev/javascript/{gleam.toml name}/\`) must match the Rollup input path
|
|
46
47
|
- Mendix widget names allow only alphabetic characters (a-zA-Z)
|
|
47
48
|
|
|
@@ -53,7 +54,7 @@ IMPORTANT: Breaking these rules will break the build or compromise the architect
|
|
|
53
54
|
|
|
54
55
|
## Architecture
|
|
55
56
|
|
|
56
|
-
Widget entry point signature: \`pub fn widget(props: JsProps) -> Element\` — identical to a React functional component. \`JsProps\` from \`
|
|
57
|
+
Widget entry point signature: \`pub fn widget(props: JsProps) -> Element\` — identical to a React functional component. \`JsProps\` from \`mendraw/mendix\`, \`Element\` from \`redraw\`.
|
|
57
58
|
|
|
58
59
|
- \`src/${names.snakeCase}.gleam\` — Main widget (called by Mendix runtime)
|
|
59
60
|
- \`src/editor_config.gleam\` — Studio Pro property panel configuration
|
|
@@ -61,8 +62,7 @@ Widget entry point signature: \`pub fn widget(props: JsProps) -> Element\` — i
|
|
|
61
62
|
- \`src/components/\` — Shared components
|
|
62
63
|
- \`src/${names.pascalCase}.xml\` — Widget property definitions. Adding \`<property>\` triggers automatic type generation by the build tool
|
|
63
64
|
- \`src/package.xml\` — Mendix package manifest
|
|
64
|
-
- \`bindings
|
|
65
|
-
- \`widgets/\` — .mpk widget file bindings (used via \`glendix/widget\`)
|
|
65
|
+
- \`gleam.toml [tools.glendix.bindings]\` — External React component binding configuration
|
|
66
66
|
|
|
67
67
|
## Build Pipeline
|
|
68
68
|
|
|
@@ -93,6 +93,7 @@ src/*.gleam → gleam build → build/dev/javascript/**/*.mjs → Bridge JS (aut
|
|
|
93
93
|
For detailed glendix API and Gleam syntax, see:
|
|
94
94
|
|
|
95
95
|
- docs/glendix_guide.md — Complete React/Mendix bindings guide (elements, Hooks, events, Mendix types, practical patterns, troubleshooting)
|
|
96
|
+
- docs/mendraw_guide.md — mendraw usage guide (Marketplace download, classic widget support)
|
|
96
97
|
- docs/gleam_language_tour.md — Gleam syntax reference (types, pattern matching, FFI, use keyword, etc.)
|
|
97
98
|
|
|
98
99
|
## Mendix Documentation Sources
|