create-mendix-widget-gleam 3.0.2 → 4.0.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.md +8 -9
- package/package.json +1 -1
- package/src/i18n.mjs +12 -15
- package/src/index.mjs +20 -31
- package/src/templates/claude_md.mjs +10 -8
- package/src/templates/readme_md.mjs +60 -69
- package/src/templates/widgets_readme.mjs +15 -15
- package/template/docs/glendix_guide.md +197 -96
- package/template/docs/mendraw_guide.md +671 -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/template/rollup.config.mjs +0 -10
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,13 @@ my-widget/
|
|
|
27
27
|
editor_preview.gleam # Studio Pro 디자인 뷰 미리보기
|
|
28
28
|
components/
|
|
29
29
|
hello_world.gleam # Hello World 공유 컴포넌트
|
|
30
|
-
widgets/ # .mpk 위젯 파일 (
|
|
31
|
-
bindings.json # 외부 React 컴포넌트 바인딩 설정
|
|
30
|
+
widgets/ # .mpk 위젯 파일 (mendraw/widget로 바인딩)
|
|
32
31
|
package.json # npm 의존성 (React, 외부 라이브러리 등)
|
|
33
|
-
gleam.toml # Gleam 프로젝트 설정 (glendix >=
|
|
32
|
+
gleam.toml # Gleam 프로젝트 설정 (glendix >= 4.0.2 + mendraw >= 1.1.10 의존성 포함)
|
|
34
33
|
CLAUDE.md # AI 어시스턴트용 프로젝트 컨텍스트
|
|
35
34
|
```
|
|
36
35
|
|
|
37
|
-
React/Mendix FFI 및 JS Interop 바인딩은 프로젝트에 포함되지 않으며, [glendix](https://hexdocs.pm/glendix/) Hex 패키지로 제공된다.
|
|
36
|
+
React/Mendix FFI 및 JS Interop 바인딩은 프로젝트에 포함되지 않으며, [glendix](https://hexdocs.pm/glendix/) 및 [mendraw](https://hexdocs.pm/mendraw/) Hex 패키지로 제공된다.
|
|
38
37
|
|
|
39
38
|
## 생성 후 시작하기
|
|
40
39
|
|
|
@@ -43,7 +42,7 @@ cd my-widget
|
|
|
43
42
|
gleam run -m glendix/install # 의존성 설치
|
|
44
43
|
gleam run -m glendix/dev # 개발 서버 시작
|
|
45
44
|
gleam run -m glendix/build # 프로덕션 빌드 (.mpk 생성)
|
|
46
|
-
gleam run -m
|
|
45
|
+
gleam run -m mendraw/marketplace # Marketplace 위젯 검색/다운로드
|
|
47
46
|
gleam run -m glendix/define # 위젯 프로퍼티 정의 TUI 에디터
|
|
48
47
|
```
|
|
49
48
|
|
|
@@ -51,9 +50,9 @@ gleam run -m glendix/define # 위젯 프로퍼티 정의 TUI 에디터
|
|
|
51
50
|
|
|
52
51
|
생성된 프로젝트는 [glendix](https://hexdocs.pm/glendix/) Hex 패키지를 의존성으로 사용한다. glendix가 React 원시 함수와 Mendix Pluggable Widget API 전체에 대한 타입 안전한 Gleam 바인딩을 제공한다:
|
|
53
52
|
|
|
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`
|
|
53
|
+
- **React** — `redraw`, `redraw/dom/attribute`, `redraw/hooks`, `redraw/dom/events`, `redraw/dom/html`, `redraw/dom/svg`; bindings via `glendix/binding`
|
|
54
|
+
- **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`, `mendraw/widget` 등
|
|
55
|
+
- **JS Interop** (glendix) — `glendix/js/array`, `glendix/js/object`, `glendix/js/json`, `glendix/js/promise`, `glendix/js/dom`, `glendix/js/timer`
|
|
57
56
|
|
|
58
57
|
## 라이선스
|
|
59
58
|
|
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";
|
|
@@ -28,7 +28,9 @@ const DIM = "\x1b[2m";
|
|
|
28
28
|
const YELLOW = "\x1b[33m";
|
|
29
29
|
const MAGENTA = "\x1b[35m";
|
|
30
30
|
|
|
31
|
-
const VERSION =
|
|
31
|
+
const VERSION = JSON.parse(
|
|
32
|
+
await readFile(join(__dirname, "..", "package.json"), "utf-8"),
|
|
33
|
+
).version;
|
|
32
34
|
|
|
33
35
|
const HELP = `
|
|
34
36
|
${BOLD}create-mendix-widget-gleam${RESET} — Create Gleam + Mendix Pluggable Widget projects
|
|
@@ -66,9 +68,12 @@ const BANNER_LINES = [
|
|
|
66
68
|
|
|
67
69
|
const header = '\n' + BANNER_LINES.map(([g, l]) =>
|
|
68
70
|
`${CYAN}${BOLD}${g}${RESET}${MAGENTA}${l}${RESET}`
|
|
69
|
-
).join('\n') +
|
|
71
|
+
).join('\n') + '\n';
|
|
70
72
|
|
|
71
73
|
export async function main(args) {
|
|
74
|
+
// Ctrl+C 즉시 종료
|
|
75
|
+
process.on("SIGINT", () => process.exit(130));
|
|
76
|
+
|
|
72
77
|
// Flag handling
|
|
73
78
|
if (args.includes("--help") || args.includes("-h")) {
|
|
74
79
|
console.log(HELP);
|
|
@@ -221,35 +226,19 @@ export async function main(args) {
|
|
|
221
226
|
console.error(` ${CYAN}${pmConfig.install}${RESET}\n`);
|
|
222
227
|
}
|
|
223
228
|
|
|
224
|
-
//
|
|
229
|
+
// Run glendix/install
|
|
230
|
+
console.log(`\n${BOLD}${t(lang, "progress.glendixInstalling")}${RESET}\n`);
|
|
225
231
|
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
|
-
}
|
|
232
|
+
execSync("gleam run -m glendix/install", {
|
|
233
|
+
cwd: targetDir,
|
|
234
|
+
stdio: "inherit",
|
|
235
|
+
});
|
|
236
|
+
console.log(`\n${GREEN}✓${RESET} ${t(lang, "progress.glendixInstalled")}`);
|
|
251
237
|
} catch {
|
|
252
|
-
|
|
238
|
+
console.error(
|
|
239
|
+
`\n${YELLOW}${t(lang, "error.glendixInstallFail")}${RESET}`,
|
|
240
|
+
);
|
|
241
|
+
console.error(` ${CYAN}gleam run -m glendix/install${RESET}\n`);
|
|
253
242
|
}
|
|
254
243
|
|
|
255
244
|
// Production build
|
|
@@ -276,7 +265,7 @@ ${BOLD}${t(lang, "done.nextSteps")}${RESET}
|
|
|
276
265
|
${CYAN}cd ${names.kebabCase}${RESET}
|
|
277
266
|
${CYAN}gleam run -m glendix/dev${RESET} ${DIM}${t(lang, "done.devServer")}${RESET}
|
|
278
267
|
${CYAN}gleam run -m glendix/build${RESET} ${DIM}${t(lang, "done.prodBuild")}${RESET}
|
|
279
|
-
${CYAN}gleam run -m
|
|
268
|
+
${CYAN}gleam run -m mendraw/marketplace${RESET} ${DIM}${t(lang, "done.marketplace")}${RESET}
|
|
280
269
|
`);
|
|
281
270
|
|
|
282
271
|
// 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,8 @@ 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 \`
|
|
65
|
+
- \`gleam.toml [tools.glendix.bindings]\` — External React component binding configuration
|
|
66
|
+
- \`widgets/\` — .mpk widget file bindings (used via \`mendraw/widget\`)
|
|
66
67
|
|
|
67
68
|
## Build Pipeline
|
|
68
69
|
|
|
@@ -93,6 +94,7 @@ src/*.gleam → gleam build → build/dev/javascript/**/*.mjs → Bridge JS (aut
|
|
|
93
94
|
For detailed glendix API and Gleam syntax, see:
|
|
94
95
|
|
|
95
96
|
- docs/glendix_guide.md — Complete React/Mendix bindings guide (elements, Hooks, events, Mendix types, practical patterns, troubleshooting)
|
|
97
|
+
- docs/mendraw_guide.md — mendraw usage guide (widget .mpk bindings, Marketplace download, classic widget support)
|
|
96
98
|
- docs/gleam_language_tour.md — Gleam syntax reference (types, pattern matching, FFI, use keyword, etc.)
|
|
97
99
|
|
|
98
100
|
## Mendix Documentation Sources
|
|
@@ -33,11 +33,11 @@ A Mendix Pluggable Widget written in Gleam.
|
|
|
33
33
|
|
|
34
34
|
## Core Principles
|
|
35
35
|
|
|
36
|
-
The Gleam function \`fn(JsProps) -> Element\` has the same signature as a React functional component. React bindings come from the \`redraw\`/\`redraw_dom\` packages, while
|
|
36
|
+
The Gleam function \`fn(JsProps) -> Element\` has the same signature as a React functional component. React bindings come from the \`redraw\`/\`redraw_dom\` packages, while mendraw handles Mendix API access and JS interop, so widget projects only need to focus on business logic.
|
|
37
37
|
|
|
38
38
|
\`\`\`gleam
|
|
39
39
|
// src/${names.snakeCase}.gleam
|
|
40
|
-
import
|
|
40
|
+
import mendraw/mendix.{type JsProps}
|
|
41
41
|
import redraw.{type Element}
|
|
42
42
|
import redraw/dom/attribute
|
|
43
43
|
import redraw/dom/html
|
|
@@ -53,9 +53,9 @@ pub fn widget(props: JsProps) -> Element {
|
|
|
53
53
|
Mendix complex types can also be used type-safely from Gleam:
|
|
54
54
|
|
|
55
55
|
\`\`\`gleam
|
|
56
|
-
import
|
|
57
|
-
import
|
|
58
|
-
import
|
|
56
|
+
import mendraw/mendix.{type JsProps}
|
|
57
|
+
import mendraw/mendix/editable_value
|
|
58
|
+
import mendraw/mendix/action
|
|
59
59
|
import redraw.{type Element}
|
|
60
60
|
|
|
61
61
|
pub fn widget(props: JsProps) -> Element {
|
|
@@ -105,7 +105,7 @@ gleam run -m glendix/start # Link with Mendix test project
|
|
|
105
105
|
gleam run -m glendix/lint # Run ESLint
|
|
106
106
|
gleam run -m glendix/lint_fix # ESLint auto-fix
|
|
107
107
|
gleam run -m glendix/release # Release build
|
|
108
|
-
gleam run -m
|
|
108
|
+
gleam run -m mendraw/marketplace # Search/download Marketplace widgets
|
|
109
109
|
gleam run -m glendix/define # Widget property definition TUI editor
|
|
110
110
|
gleam build --target javascript # Gleam → JS compilation only
|
|
111
111
|
gleam test # Run tests
|
|
@@ -122,12 +122,11 @@ src/
|
|
|
122
122
|
components/
|
|
123
123
|
hello_world.gleam # Shared Hello World component
|
|
124
124
|
${names.pascalCase}.xml # Widget property definitions
|
|
125
|
-
widgets/ # .mpk widget files (bindings via
|
|
126
|
-
bindings.json # External React component binding configuration
|
|
125
|
+
widgets/ # .mpk widget files (bindings via mendraw/widget)
|
|
127
126
|
package.json # npm dependencies (React, external libraries, etc.)
|
|
128
127
|
\`\`\`
|
|
129
128
|
|
|
130
|
-
React bindings come from [redraw](https://hexdocs.pm/redraw/)/[redraw_dom](https://hexdocs.pm/redraw_dom/), while Mendix API and JS Interop bindings are provided by [
|
|
129
|
+
React bindings come from [redraw](https://hexdocs.pm/redraw/)/[redraw_dom](https://hexdocs.pm/redraw_dom/), while Mendix API and JS Interop bindings are provided by [mendraw](https://hexdocs.pm/mendraw/).
|
|
131
130
|
|
|
132
131
|
## Using External React Components
|
|
133
132
|
|
|
@@ -139,16 +138,13 @@ React component libraries distributed as npm packages can be used from pure Glea
|
|
|
139
138
|
${installCmd} recharts
|
|
140
139
|
\`\`\`
|
|
141
140
|
|
|
142
|
-
### Step 2:
|
|
141
|
+
### Step 2: Add bindings to \`gleam.toml\`
|
|
143
142
|
|
|
144
|
-
|
|
143
|
+
Add a \`[tools.glendix.bindings]\` section to your \`gleam.toml\`:
|
|
145
144
|
|
|
146
|
-
\`\`\`
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
"components": ["PieChart", "Pie", "Cell", "Tooltip", "ResponsiveContainer"]
|
|
150
|
-
}
|
|
151
|
-
}
|
|
145
|
+
\`\`\`toml
|
|
146
|
+
[tools.glendix.bindings.recharts]
|
|
147
|
+
components = ["PieChart", "Pie", "Cell", "Tooltip", "ResponsiveContainer"]
|
|
152
148
|
\`\`\`
|
|
153
149
|
|
|
154
150
|
### Step 3: Generate bindings
|
|
@@ -163,7 +159,7 @@ gleam run -m glendix/install
|
|
|
163
159
|
|
|
164
160
|
\`\`\`gleam
|
|
165
161
|
import glendix/binding
|
|
166
|
-
import
|
|
162
|
+
import mendraw/interop
|
|
167
163
|
import redraw.{type Element}
|
|
168
164
|
import redraw/dom/attribute.{type Attribute}
|
|
169
165
|
|
|
@@ -197,7 +193,7 @@ MENDIX_PAT=your_personal_access_token
|
|
|
197
193
|
### Run
|
|
198
194
|
|
|
199
195
|
\`\`\`bash
|
|
200
|
-
gleam run -m
|
|
196
|
+
gleam run -m mendraw/marketplace
|
|
201
197
|
\`\`\`
|
|
202
198
|
|
|
203
199
|
Search and select widgets in the interactive TUI. The \`.mpk\` is downloaded to the \`widgets/\` directory, and binding \`.gleam\` files are auto-generated in \`src/widgets/\`.
|
|
@@ -231,11 +227,11 @@ This automatically:
|
|
|
231
227
|
|
|
232
228
|
\`\`\`gleam
|
|
233
229
|
// src/widgets/switch.gleam (auto-generated)
|
|
234
|
-
import
|
|
235
|
-
import
|
|
230
|
+
import mendraw/mendix.{type JsProps}
|
|
231
|
+
import mendraw/interop
|
|
236
232
|
import redraw.{type Element}
|
|
237
233
|
import redraw/dom/attribute
|
|
238
|
-
import
|
|
234
|
+
import mendraw/widget
|
|
239
235
|
|
|
240
236
|
/// Render Switch widget - reads properties from props and passes them to the widget
|
|
241
237
|
pub fn render(props: JsProps) -> Element {
|
|
@@ -270,7 +266,8 @@ Widget names use the \`<name>\` value from the \`.mpk\`'s internal XML, and prop
|
|
|
270
266
|
## Tech Stack
|
|
271
267
|
|
|
272
268
|
- **Gleam** → JavaScript compilation
|
|
273
|
-
- **[glendix](https://hexdocs.pm/glendix/)** —
|
|
269
|
+
- **[glendix](https://hexdocs.pm/glendix/)** — Build tools + JS Interop Gleam bindings
|
|
270
|
+
- **[mendraw](https://hexdocs.pm/mendraw/)** — Mendix API Gleam bindings
|
|
274
271
|
- **[redraw](https://hexdocs.pm/redraw/)** / **[redraw_dom](https://hexdocs.pm/redraw_dom/)** — React Gleam bindings
|
|
275
272
|
- **Mendix Pluggable Widget** (React 19)
|
|
276
273
|
- **${pm}** — Package manager
|
|
@@ -292,11 +289,11 @@ Gleam 언어로 작성된 Mendix Pluggable Widget.
|
|
|
292
289
|
|
|
293
290
|
## 핵심 원리
|
|
294
291
|
|
|
295
|
-
Gleam 함수 \`fn(JsProps) -> Element\`는 React 함수형 컴포넌트와 동일한 시그니처다. React 바인딩은 \`redraw\`/\`redraw_dom\` 패키지가, Mendix API 접근과 JS interop은
|
|
292
|
+
Gleam 함수 \`fn(JsProps) -> Element\`는 React 함수형 컴포넌트와 동일한 시그니처다. React 바인딩은 \`redraw\`/\`redraw_dom\` 패키지가, Mendix API 접근과 JS interop은 mendraw가 제공하므로, 위젯 프로젝트에서는 비즈니스 로직에만 집중하면 된다.
|
|
296
293
|
|
|
297
294
|
\`\`\`gleam
|
|
298
295
|
// src/${names.snakeCase}.gleam
|
|
299
|
-
import
|
|
296
|
+
import mendraw/mendix.{type JsProps}
|
|
300
297
|
import redraw.{type Element}
|
|
301
298
|
import redraw/dom/attribute
|
|
302
299
|
import redraw/dom/html
|
|
@@ -312,9 +309,9 @@ pub fn widget(props: JsProps) -> Element {
|
|
|
312
309
|
Mendix 복합 타입도 Gleam에서 타입 안전하게 사용할 수 있다:
|
|
313
310
|
|
|
314
311
|
\`\`\`gleam
|
|
315
|
-
import
|
|
316
|
-
import
|
|
317
|
-
import
|
|
312
|
+
import mendraw/mendix.{type JsProps}
|
|
313
|
+
import mendraw/mendix/editable_value
|
|
314
|
+
import mendraw/mendix/action
|
|
318
315
|
import redraw.{type Element}
|
|
319
316
|
|
|
320
317
|
pub fn widget(props: JsProps) -> Element {
|
|
@@ -364,7 +361,7 @@ gleam run -m glendix/start # Mendix 테스트 프로젝트 연동
|
|
|
364
361
|
gleam run -m glendix/lint # ESLint 실행
|
|
365
362
|
gleam run -m glendix/lint_fix # ESLint 자동 수정
|
|
366
363
|
gleam run -m glendix/release # 릴리즈 빌드
|
|
367
|
-
gleam run -m
|
|
364
|
+
gleam run -m mendraw/marketplace # Marketplace 위젯 검색/다운로드
|
|
368
365
|
gleam run -m glendix/define # 위젯 프로퍼티 정의 TUI 에디터
|
|
369
366
|
gleam build --target javascript # Gleam → JS 컴파일만
|
|
370
367
|
gleam test # 테스트 실행
|
|
@@ -381,12 +378,11 @@ src/
|
|
|
381
378
|
components/
|
|
382
379
|
hello_world.gleam # Hello World 공유 컴포넌트
|
|
383
380
|
${names.pascalCase}.xml # 위젯 속성 정의
|
|
384
|
-
widgets/ # .mpk 위젯 파일 (
|
|
385
|
-
bindings.json # 외부 React 컴포넌트 바인딩 설정
|
|
381
|
+
widgets/ # .mpk 위젯 파일 (mendraw/widget로 바인딩)
|
|
386
382
|
package.json # npm 의존성 (React, 외부 라이브러리 등)
|
|
387
383
|
\`\`\`
|
|
388
384
|
|
|
389
|
-
React 바인딩은 [redraw](https://hexdocs.pm/redraw/)/[redraw_dom](https://hexdocs.pm/redraw_dom/)이, Mendix API 및 JS Interop 바인딩은 [
|
|
385
|
+
React 바인딩은 [redraw](https://hexdocs.pm/redraw/)/[redraw_dom](https://hexdocs.pm/redraw_dom/)이, Mendix API 및 JS Interop 바인딩은 [mendraw](https://hexdocs.pm/mendraw/)가 제공합니다.
|
|
390
386
|
|
|
391
387
|
## 외부 React 컴포넌트 사용
|
|
392
388
|
|
|
@@ -398,16 +394,13 @@ npm 패키지로 제공되는 React 컴포넌트 라이브러리를 \`.mjs\` FFI
|
|
|
398
394
|
${installCmd} recharts
|
|
399
395
|
\`\`\`
|
|
400
396
|
|
|
401
|
-
### 2단계: \`
|
|
397
|
+
### 2단계: \`gleam.toml\`에 바인딩 추가
|
|
402
398
|
|
|
403
|
-
|
|
399
|
+
\`gleam.toml\`에 \`[tools.glendix.bindings]\` 섹션을 추가한다:
|
|
404
400
|
|
|
405
|
-
\`\`\`
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
"components": ["PieChart", "Pie", "Cell", "Tooltip", "ResponsiveContainer"]
|
|
409
|
-
}
|
|
410
|
-
}
|
|
401
|
+
\`\`\`toml
|
|
402
|
+
[tools.glendix.bindings.recharts]
|
|
403
|
+
components = ["PieChart", "Pie", "Cell", "Tooltip", "ResponsiveContainer"]
|
|
411
404
|
\`\`\`
|
|
412
405
|
|
|
413
406
|
### 3단계: 바인딩 생성
|
|
@@ -422,7 +415,7 @@ gleam run -m glendix/install
|
|
|
422
415
|
|
|
423
416
|
\`\`\`gleam
|
|
424
417
|
import glendix/binding
|
|
425
|
-
import
|
|
418
|
+
import mendraw/interop
|
|
426
419
|
import redraw.{type Element}
|
|
427
420
|
import redraw/dom/attribute.{type Attribute}
|
|
428
421
|
|
|
@@ -456,7 +449,7 @@ MENDIX_PAT=your_personal_access_token
|
|
|
456
449
|
### 실행
|
|
457
450
|
|
|
458
451
|
\`\`\`bash
|
|
459
|
-
gleam run -m
|
|
452
|
+
gleam run -m mendraw/marketplace
|
|
460
453
|
\`\`\`
|
|
461
454
|
|
|
462
455
|
인터랙티브 TUI에서 위젯을 검색/선택하면 \`widgets/\` 디렉토리에 \`.mpk\`가 다운로드되고, \`src/widgets/\`에 바인딩 \`.gleam\` 파일이 자동 생성된다.
|
|
@@ -490,11 +483,11 @@ gleam run -m glendix/install
|
|
|
490
483
|
|
|
491
484
|
\`\`\`gleam
|
|
492
485
|
// src/widgets/switch.gleam (자동 생성)
|
|
493
|
-
import
|
|
494
|
-
import
|
|
486
|
+
import mendraw/mendix.{type JsProps}
|
|
487
|
+
import mendraw/interop
|
|
495
488
|
import redraw.{type Element}
|
|
496
489
|
import redraw/dom/attribute
|
|
497
|
-
import
|
|
490
|
+
import mendraw/widget
|
|
498
491
|
|
|
499
492
|
/// Switch 위젯 렌더링 - props에서 속성을 읽어 위젯에 전달
|
|
500
493
|
pub fn render(props: JsProps) -> Element {
|
|
@@ -529,7 +522,8 @@ switch.render(props)
|
|
|
529
522
|
## 기술 스택
|
|
530
523
|
|
|
531
524
|
- **Gleam** → JavaScript 컴파일
|
|
532
|
-
- **[glendix](https://hexdocs.pm/glendix/)** —
|
|
525
|
+
- **[glendix](https://hexdocs.pm/glendix/)** — 빌드 도구 + JS Interop Gleam 바인딩
|
|
526
|
+
- **[mendraw](https://hexdocs.pm/mendraw/)** — Mendix API Gleam 바인딩
|
|
533
527
|
- **[redraw](https://hexdocs.pm/redraw/)** / **[redraw_dom](https://hexdocs.pm/redraw_dom/)** — React Gleam 바인딩
|
|
534
528
|
- **Mendix Pluggable Widget** (React 19)
|
|
535
529
|
- **${pm}** — 패키지 매니저
|
|
@@ -551,11 +545,11 @@ Gleam言語で作成されたMendix Pluggable Widget。
|
|
|
551
545
|
|
|
552
546
|
## 基本原理
|
|
553
547
|
|
|
554
|
-
Gleam関数 \`fn(JsProps) -> Element\` はReact関数コンポーネントと同一のシグネチャを持つ。Reactバインディングは\`redraw\`/\`redraw_dom\`パッケージが、Mendix APIアクセスとJS interopは
|
|
548
|
+
Gleam関数 \`fn(JsProps) -> Element\` はReact関数コンポーネントと同一のシグネチャを持つ。Reactバインディングは\`redraw\`/\`redraw_dom\`パッケージが、Mendix APIアクセスとJS interopはmendrawが提供するため、ウィジェットプロジェクトではビジネスロジックにのみ集中すればよい。
|
|
555
549
|
|
|
556
550
|
\`\`\`gleam
|
|
557
551
|
// src/${names.snakeCase}.gleam
|
|
558
|
-
import
|
|
552
|
+
import mendraw/mendix.{type JsProps}
|
|
559
553
|
import redraw.{type Element}
|
|
560
554
|
import redraw/dom/attribute
|
|
561
555
|
import redraw/dom/html
|
|
@@ -571,9 +565,9 @@ pub fn widget(props: JsProps) -> Element {
|
|
|
571
565
|
Mendixの複合型もGleamから型安全に使用できる:
|
|
572
566
|
|
|
573
567
|
\`\`\`gleam
|
|
574
|
-
import
|
|
575
|
-
import
|
|
576
|
-
import
|
|
568
|
+
import mendraw/mendix.{type JsProps}
|
|
569
|
+
import mendraw/mendix/editable_value
|
|
570
|
+
import mendraw/mendix/action
|
|
577
571
|
import redraw.{type Element}
|
|
578
572
|
|
|
579
573
|
pub fn widget(props: JsProps) -> Element {
|
|
@@ -623,7 +617,7 @@ gleam run -m glendix/start # Mendixテストプロジェクト連携
|
|
|
623
617
|
gleam run -m glendix/lint # ESLint実行
|
|
624
618
|
gleam run -m glendix/lint_fix # ESLint自動修正
|
|
625
619
|
gleam run -m glendix/release # リリースビルド
|
|
626
|
-
gleam run -m
|
|
620
|
+
gleam run -m mendraw/marketplace # Marketplaceウィジェット検索/ダウンロード
|
|
627
621
|
gleam run -m glendix/define # ウィジェットプロパティ定義TUIエディター
|
|
628
622
|
gleam build --target javascript # Gleam → JSコンパイルのみ
|
|
629
623
|
gleam test # テスト実行
|
|
@@ -640,12 +634,11 @@ src/
|
|
|
640
634
|
components/
|
|
641
635
|
hello_world.gleam # Hello World共有コンポーネント
|
|
642
636
|
${names.pascalCase}.xml # ウィジェットプロパティ定義
|
|
643
|
-
widgets/ # .mpkウィジェットファイル(
|
|
644
|
-
bindings.json # 外部Reactコンポーネントバインディング設定
|
|
637
|
+
widgets/ # .mpkウィジェットファイル(mendraw/widgetでバインディング)
|
|
645
638
|
package.json # npm依存関係(React、外部ライブラリなど)
|
|
646
639
|
\`\`\`
|
|
647
640
|
|
|
648
|
-
Reactバインディングは[redraw](https://hexdocs.pm/redraw/)/[redraw_dom](https://hexdocs.pm/redraw_dom/)が、Mendix APIおよびJS Interopバインディングは[
|
|
641
|
+
Reactバインディングは[redraw](https://hexdocs.pm/redraw/)/[redraw_dom](https://hexdocs.pm/redraw_dom/)が、Mendix APIおよびJS Interopバインディングは[mendraw](https://hexdocs.pm/mendraw/)が提供する。
|
|
649
642
|
|
|
650
643
|
## 外部Reactコンポーネントの使用
|
|
651
644
|
|
|
@@ -657,16 +650,13 @@ npmパッケージとして提供されるReactコンポーネントライブラ
|
|
|
657
650
|
${installCmd} recharts
|
|
658
651
|
\`\`\`
|
|
659
652
|
|
|
660
|
-
### ステップ2:\`
|
|
653
|
+
### ステップ2:\`gleam.toml\`にバインディングを追加
|
|
661
654
|
|
|
662
|
-
|
|
655
|
+
\`gleam.toml\`に\`[tools.glendix.bindings]\`セクションを追加する:
|
|
663
656
|
|
|
664
|
-
\`\`\`
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
"components": ["PieChart", "Pie", "Cell", "Tooltip", "ResponsiveContainer"]
|
|
668
|
-
}
|
|
669
|
-
}
|
|
657
|
+
\`\`\`toml
|
|
658
|
+
[tools.glendix.bindings.recharts]
|
|
659
|
+
components = ["PieChart", "Pie", "Cell", "Tooltip", "ResponsiveContainer"]
|
|
670
660
|
\`\`\`
|
|
671
661
|
|
|
672
662
|
### ステップ3:バインディングの生成
|
|
@@ -681,7 +671,7 @@ gleam run -m glendix/install
|
|
|
681
671
|
|
|
682
672
|
\`\`\`gleam
|
|
683
673
|
import glendix/binding
|
|
684
|
-
import
|
|
674
|
+
import mendraw/interop
|
|
685
675
|
import redraw.{type Element}
|
|
686
676
|
import redraw/dom/attribute.{type Attribute}
|
|
687
677
|
|
|
@@ -715,7 +705,7 @@ MENDIX_PAT=your_personal_access_token
|
|
|
715
705
|
### 実行
|
|
716
706
|
|
|
717
707
|
\`\`\`bash
|
|
718
|
-
gleam run -m
|
|
708
|
+
gleam run -m mendraw/marketplace
|
|
719
709
|
\`\`\`
|
|
720
710
|
|
|
721
711
|
インタラクティブTUIでウィジェットを検索・選択すると、\`widgets/\`ディレクトリに\`.mpk\`がダウンロードされ、\`src/widgets/\`にバインディング\`.gleam\`ファイルが自動生成される。
|
|
@@ -749,11 +739,11 @@ gleam run -m glendix/install
|
|
|
749
739
|
|
|
750
740
|
\`\`\`gleam
|
|
751
741
|
// src/widgets/switch.gleam(自動生成)
|
|
752
|
-
import
|
|
753
|
-
import
|
|
742
|
+
import mendraw/mendix.{type JsProps}
|
|
743
|
+
import mendraw/interop
|
|
754
744
|
import redraw.{type Element}
|
|
755
745
|
import redraw/dom/attribute
|
|
756
|
-
import
|
|
746
|
+
import mendraw/widget
|
|
757
747
|
|
|
758
748
|
/// Switchウィジェットのレンダリング - propsからプロパティを読み取りウィジェットに渡す
|
|
759
749
|
pub fn render(props: JsProps) -> Element {
|
|
@@ -788,7 +778,8 @@ switch.render(props)
|
|
|
788
778
|
## 技術スタック
|
|
789
779
|
|
|
790
780
|
- **Gleam** → JavaScriptコンパイル
|
|
791
|
-
- **[glendix](https://hexdocs.pm/glendix/)** —
|
|
781
|
+
- **[glendix](https://hexdocs.pm/glendix/)** — ビルドツール + JS Interop Gleamバインディング
|
|
782
|
+
- **[mendraw](https://hexdocs.pm/mendraw/)** — Mendix API Gleamバインディング
|
|
792
783
|
- **[redraw](https://hexdocs.pm/redraw/)** / **[redraw_dom](https://hexdocs.pm/redraw_dom/)** — React Gleamバインディング
|
|
793
784
|
- **Mendix Pluggable Widget**(React 19)
|
|
794
785
|
- **${pm}** — パッケージマネージャー
|