create-mendix-widget-gleam 2.0.12 → 2.0.13

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.
@@ -0,0 +1,785 @@
1
+ /**
2
+ * README.md template — 3 language versions
3
+ */
4
+
5
+ export function generateReadmeContent(lang, names, pm, pmConfig) {
6
+ const installCmd =
7
+ pm === "npm"
8
+ ? "npm install"
9
+ : pm === "yarn"
10
+ ? "yarn add"
11
+ : pm === "pnpm"
12
+ ? "pnpm add"
13
+ : "bun add";
14
+
15
+ switch (lang) {
16
+ case "ko":
17
+ return generateKo(names, pm, installCmd);
18
+ case "ja":
19
+ return generateJa(names, pm, installCmd);
20
+ default:
21
+ return generateEn(names, pm, installCmd);
22
+ }
23
+ }
24
+
25
+ // ---------------------------------------------------------------------------
26
+ // English
27
+ // ---------------------------------------------------------------------------
28
+
29
+ function generateEn(names, pm, installCmd) {
30
+ return `# ${names.pascalCase}
31
+
32
+ A Mendix Pluggable Widget written in Gleam.
33
+
34
+ ## Core Principles
35
+
36
+ The Gleam function \`fn(JsProps) -> ReactElement\` has the same signature as a React functional component. glendix provides type-safe access to React primitives and Mendix runtime type accessors, so widget projects only need to focus on business logic.
37
+
38
+ \`\`\`gleam
39
+ // src/${names.snakeCase}.gleam
40
+ import glendix/mendix
41
+ import glendix/react.{type JsProps, type ReactElement}
42
+ import glendix/react/attribute
43
+ import glendix/react/html
44
+
45
+ pub fn widget(props: JsProps) -> ReactElement {
46
+ let sample_text = mendix.get_string_prop(props, "sampleText")
47
+ html.div([attribute.class("widget-hello-world")], [
48
+ react.text("Hello " <> sample_text),
49
+ ])
50
+ }
51
+ \`\`\`
52
+
53
+ Mendix complex types can also be used type-safely from Gleam:
54
+
55
+ \`\`\`gleam
56
+ import glendix/mendix
57
+ import glendix/mendix/editable_value
58
+ import glendix/mendix/action
59
+
60
+ pub fn widget(props: JsProps) -> ReactElement {
61
+ // Access EditableValue
62
+ let name_attr: EditableValue = mendix.get_prop_required(props, "name")
63
+ let display = editable_value.display_value(name_attr)
64
+
65
+ // Execute ActionValue
66
+ let on_save: Option(ActionValue) = mendix.get_prop(props, "onSave")
67
+ action.execute_action(on_save)
68
+ // ...
69
+ }
70
+ \`\`\`
71
+
72
+ ## Getting Started
73
+
74
+ ### Prerequisites
75
+
76
+ - [Gleam](https://gleam.run/getting-started/installing/) (latest version)
77
+ - [Node.js](https://nodejs.org/) (v18+)
78
+ - ${pm}
79
+
80
+ ### Installation
81
+
82
+ \`\`\`bash
83
+ gleam run -m glendix/install
84
+ \`\`\`
85
+
86
+ ### Development
87
+
88
+ \`\`\`bash
89
+ gleam run -m glendix/dev
90
+ \`\`\`
91
+
92
+ ### Build
93
+
94
+ \`\`\`bash
95
+ gleam run -m glendix/build
96
+ \`\`\`
97
+
98
+ Build artifacts (\`.mpk\`) are generated in the \`dist/\` directory.
99
+
100
+ ### Other Commands
101
+
102
+ \`\`\`bash
103
+ gleam run -m glendix/start # Link with Mendix test project
104
+ gleam run -m glendix/lint # Run ESLint
105
+ gleam run -m glendix/lint_fix # ESLint auto-fix
106
+ gleam run -m glendix/release # Release build
107
+ gleam run -m glendix/marketplace # Search/download Marketplace widgets
108
+ gleam build --target javascript # Gleam → JS compilation only
109
+ gleam test # Run tests
110
+ gleam format # Format code
111
+ \`\`\`
112
+
113
+ ## Project Structure
114
+
115
+ \`\`\`
116
+ src/
117
+ ${names.snakeCase}.gleam # Main widget module
118
+ editor_config.gleam # Studio Pro property panel
119
+ editor_preview.gleam # Studio Pro design view preview
120
+ components/
121
+ hello_world.gleam # Shared Hello World component
122
+ ${names.pascalCase}.xml # Widget property definitions
123
+ widgets/ # .mpk widget files (bindings via glendix/widget)
124
+ bindings.json # External React component binding configuration
125
+ package.json # npm dependencies (React, external libraries, etc.)
126
+ \`\`\`
127
+
128
+ React/Mendix FFI bindings are provided by the [glendix](https://hexdocs.pm/glendix/) Hex package.
129
+
130
+ ## Using External React Components
131
+
132
+ React component libraries distributed as npm packages can be used from pure Gleam without writing any \`.mjs\` FFI files.
133
+
134
+ ### Step 1: Install the npm package
135
+
136
+ \`\`\`bash
137
+ ${installCmd} recharts
138
+ \`\`\`
139
+
140
+ ### Step 2: Write \`bindings.json\`
141
+
142
+ Create \`bindings.json\` at the project root and register the components:
143
+
144
+ \`\`\`json
145
+ {
146
+ "recharts": {
147
+ "components": ["PieChart", "Pie", "Cell", "Tooltip", "ResponsiveContainer"]
148
+ }
149
+ }
150
+ \`\`\`
151
+
152
+ ### Step 3: Generate bindings
153
+
154
+ \`\`\`bash
155
+ gleam run -m glendix/install
156
+ \`\`\`
157
+
158
+ \`binding_ffi.mjs\` is generated automatically. It is also regenerated on subsequent builds via \`gleam run -m glendix/build\`.
159
+
160
+ ### Step 4: Use from Gleam
161
+
162
+ \`\`\`gleam
163
+ import glendix/binding
164
+ import glendix/react.{type ReactElement}
165
+ import glendix/react/attribute.{type Attribute}
166
+
167
+ fn m() { binding.module("recharts") }
168
+
169
+ pub fn pie_chart(attrs: List(Attribute), children: List(ReactElement)) -> ReactElement {
170
+ react.component_el(binding.resolve(m(), "PieChart"), attrs, children)
171
+ }
172
+
173
+ pub fn tooltip(attrs: List(Attribute)) -> ReactElement {
174
+ react.void_component_el(binding.resolve(m(), "Tooltip"), attrs)
175
+ }
176
+ \`\`\`
177
+
178
+ External React components follow the same calling pattern as \`html.div\`.
179
+
180
+ ## Mendix Marketplace Widget Download
181
+
182
+ Interactively search and download widgets (.mpk) from the Mendix Marketplace. After download, binding \`.gleam\` files are generated automatically and ready to use.
183
+
184
+ ### Preparation
185
+
186
+ Set your Mendix Personal Access Token in a \`.env\` file:
187
+
188
+ \`\`\`
189
+ MENDIX_PAT=your_personal_access_token
190
+ \`\`\`
191
+
192
+ > Generate a PAT from [Mendix Developer Settings](https://user-settings.mendix.com/link/developersettings) — click **New Token** under **Personal Access Tokens**. Required scope: \`mx:marketplace-content:read\`
193
+
194
+ ### Run
195
+
196
+ \`\`\`bash
197
+ gleam run -m glendix/marketplace
198
+ \`\`\`
199
+
200
+ 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/\`.
201
+
202
+ ## Using .mpk Widget Components
203
+
204
+ Place \`.mpk\` files (Mendix widget build artifacts) in the \`widgets/\` directory to render existing Mendix widgets as React components within your own widget.
205
+
206
+ ### Step 1: Place the \`.mpk\` files
207
+
208
+ \`\`\`
209
+ project root/
210
+ ├── widgets/
211
+ │ ├── Switch.mpk
212
+ │ └── Badge.mpk
213
+ ├── src/
214
+ └── gleam.toml
215
+ \`\`\`
216
+
217
+ ### Step 2: Generate bindings
218
+
219
+ \`\`\`bash
220
+ gleam run -m glendix/install
221
+ \`\`\`
222
+
223
+ This automatically:
224
+ - Extracts \`.mjs\`/\`.css\` from \`.mpk\` and generates \`widget_ffi.mjs\`
225
+ - Parses \`<property>\` definitions from \`.mpk\` XML and generates binding \`.gleam\` files in \`src/widgets/\` (existing files are skipped)
226
+
227
+ ### Step 3: Review auto-generated \`src/widgets/*.gleam\` files
228
+
229
+ \`\`\`gleam
230
+ // src/widgets/switch.gleam (auto-generated)
231
+ import glendix/mendix
232
+ import glendix/react.{type JsProps, type ReactElement}
233
+ import glendix/react/attribute
234
+ import glendix/widget
235
+
236
+ /// Render Switch widget - reads properties from props and passes them to the widget
237
+ pub fn render(props: JsProps) -> ReactElement {
238
+ let boolean_attribute = mendix.get_prop_required(props, "booleanAttribute")
239
+ let action = mendix.get_prop_required(props, "action")
240
+
241
+ let comp = widget.component("Switch")
242
+ react.component_el(
243
+ comp,
244
+ [
245
+ attribute.attribute("booleanAttribute", boolean_attribute),
246
+ attribute.attribute("action", action),
247
+ ],
248
+ [],
249
+ )
250
+ }
251
+ \`\`\`
252
+
253
+ Required/optional properties are distinguished automatically. You can freely modify the generated files as needed.
254
+
255
+ ### Step 4: Use in your widget
256
+
257
+ \`\`\`gleam
258
+ import widgets/switch
259
+
260
+ // Inside a component
261
+ switch.render(props)
262
+ \`\`\`
263
+
264
+ Widget names use the \`<name>\` value from the \`.mpk\`'s internal XML, and property keys use the original keys from the \`.mpk\` XML.
265
+
266
+ ## Tech Stack
267
+
268
+ - **Gleam** → JavaScript compilation
269
+ - **[glendix](https://hexdocs.pm/glendix/)** — React + Mendix API Gleam bindings
270
+ - **Mendix Pluggable Widget** (React 19)
271
+ - **${pm}** — Package manager
272
+
273
+ ## License
274
+
275
+ Apache-2.0
276
+ `;
277
+ }
278
+
279
+ // ---------------------------------------------------------------------------
280
+ // Korean
281
+ // ---------------------------------------------------------------------------
282
+
283
+ function generateKo(names, pm, installCmd) {
284
+ return `# ${names.pascalCase}
285
+
286
+ Gleam 언어로 작성된 Mendix Pluggable Widget.
287
+
288
+ ## 핵심 원리
289
+
290
+ Gleam 함수 \`fn(JsProps) -> ReactElement\`는 React 함수형 컴포넌트와 동일한 시그니처다. glendix가 React 원시 함수와 Mendix 런타임 타입 접근자를 타입 안전하게 제공하므로, 위젯 프로젝트에서는 비즈니스 로직에만 집중하면 된다.
291
+
292
+ \`\`\`gleam
293
+ // src/${names.snakeCase}.gleam
294
+ import glendix/mendix
295
+ import glendix/react.{type JsProps, type ReactElement}
296
+ import glendix/react/attribute
297
+ import glendix/react/html
298
+
299
+ pub fn widget(props: JsProps) -> ReactElement {
300
+ let sample_text = mendix.get_string_prop(props, "sampleText")
301
+ html.div([attribute.class("widget-hello-world")], [
302
+ react.text("Hello " <> sample_text),
303
+ ])
304
+ }
305
+ \`\`\`
306
+
307
+ Mendix 복합 타입도 Gleam에서 타입 안전하게 사용할 수 있다:
308
+
309
+ \`\`\`gleam
310
+ import glendix/mendix
311
+ import glendix/mendix/editable_value
312
+ import glendix/mendix/action
313
+
314
+ pub fn widget(props: JsProps) -> ReactElement {
315
+ // EditableValue 접근
316
+ let name_attr: EditableValue = mendix.get_prop_required(props, "name")
317
+ let display = editable_value.display_value(name_attr)
318
+
319
+ // ActionValue 실행
320
+ let on_save: Option(ActionValue) = mendix.get_prop(props, "onSave")
321
+ action.execute_action(on_save)
322
+ // ...
323
+ }
324
+ \`\`\`
325
+
326
+ ## 시작하기
327
+
328
+ ### 사전 요구사항
329
+
330
+ - [Gleam](https://gleam.run/getting-started/installing/) (최신 버전)
331
+ - [Node.js](https://nodejs.org/) (v18+)
332
+ - ${pm}
333
+
334
+ ### 설치
335
+
336
+ \`\`\`bash
337
+ gleam run -m glendix/install
338
+ \`\`\`
339
+
340
+ ### 개발
341
+
342
+ \`\`\`bash
343
+ gleam run -m glendix/dev
344
+ \`\`\`
345
+
346
+ ### 빌드
347
+
348
+ \`\`\`bash
349
+ gleam run -m glendix/build
350
+ \`\`\`
351
+
352
+ 빌드 결과물(\`.mpk\`)은 \`dist/\` 디렉토리에 생성됩니다.
353
+
354
+ ### 기타 명령어
355
+
356
+ \`\`\`bash
357
+ gleam run -m glendix/start # Mendix 테스트 프로젝트 연동
358
+ gleam run -m glendix/lint # ESLint 실행
359
+ gleam run -m glendix/lint_fix # ESLint 자동 수정
360
+ gleam run -m glendix/release # 릴리즈 빌드
361
+ gleam run -m glendix/marketplace # Marketplace 위젯 검색/다운로드
362
+ gleam build --target javascript # Gleam → JS 컴파일만
363
+ gleam test # 테스트 실행
364
+ gleam format # 코드 포맷팅
365
+ \`\`\`
366
+
367
+ ## 프로젝트 구조
368
+
369
+ \`\`\`
370
+ src/
371
+ ${names.snakeCase}.gleam # 메인 위젯 모듈
372
+ editor_config.gleam # Studio Pro 속성 패널
373
+ editor_preview.gleam # Studio Pro 디자인 뷰 미리보기
374
+ components/
375
+ hello_world.gleam # Hello World 공유 컴포넌트
376
+ ${names.pascalCase}.xml # 위젯 속성 정의
377
+ widgets/ # .mpk 위젯 파일 (glendix/widget로 바인딩)
378
+ bindings.json # 외부 React 컴포넌트 바인딩 설정
379
+ package.json # npm 의존성 (React, 외부 라이브러리 등)
380
+ \`\`\`
381
+
382
+ React/Mendix FFI 바인딩은 [glendix](https://hexdocs.pm/glendix/) Hex 패키지로 제공됩니다.
383
+
384
+ ## 외부 React 컴포넌트 사용
385
+
386
+ npm 패키지로 제공되는 React 컴포넌트 라이브러리를 \`.mjs\` FFI 파일 작성 없이 순수 Gleam에서 사용할 수 있다.
387
+
388
+ ### 1단계: npm 패키지 설치
389
+
390
+ \`\`\`bash
391
+ ${installCmd} recharts
392
+ \`\`\`
393
+
394
+ ### 2단계: \`bindings.json\` 작성
395
+
396
+ 프로젝트 루트에 \`bindings.json\`을 생성하고, 사용할 컴포넌트를 등록한다:
397
+
398
+ \`\`\`json
399
+ {
400
+ "recharts": {
401
+ "components": ["PieChart", "Pie", "Cell", "Tooltip", "ResponsiveContainer"]
402
+ }
403
+ }
404
+ \`\`\`
405
+
406
+ ### 3단계: 바인딩 생성
407
+
408
+ \`\`\`bash
409
+ gleam run -m glendix/install
410
+ \`\`\`
411
+
412
+ \`binding_ffi.mjs\`가 자동 생성된다. 이후 \`gleam run -m glendix/build\` 등 빌드 시에도 자동 갱신된다.
413
+
414
+ ### 4단계: Gleam에서 사용
415
+
416
+ \`\`\`gleam
417
+ import glendix/binding
418
+ import glendix/react.{type ReactElement}
419
+ import glendix/react/attribute.{type Attribute}
420
+
421
+ fn m() { binding.module("recharts") }
422
+
423
+ pub fn pie_chart(attrs: List(Attribute), children: List(ReactElement)) -> ReactElement {
424
+ react.component_el(binding.resolve(m(), "PieChart"), attrs, children)
425
+ }
426
+
427
+ pub fn tooltip(attrs: List(Attribute)) -> ReactElement {
428
+ react.void_component_el(binding.resolve(m(), "Tooltip"), attrs)
429
+ }
430
+ \`\`\`
431
+
432
+ \`html.div\`와 동일한 호출 패턴으로 외부 React 컴포넌트를 사용할 수 있다.
433
+
434
+ ## Mendix Marketplace 위젯 다운로드
435
+
436
+ Mendix Marketplace에서 위젯(.mpk)을 인터랙티브하게 검색하고 다운로드할 수 있다. 다운로드 완료 후 바인딩 \`.gleam\` 파일이 자동 생성되어 바로 사용 가능하다.
437
+
438
+ ### 사전 준비
439
+
440
+ \`.env\` 파일에 Mendix Personal Access Token을 설정한다:
441
+
442
+ \`\`\`
443
+ MENDIX_PAT=your_personal_access_token
444
+ \`\`\`
445
+
446
+ > PAT는 [Mendix Developer Settings](https://user-settings.mendix.com/link/developersettings)에서 **Personal Access Tokens** 섹션의 **New Token**을 클릭하여 발급. 필요한 scope: \`mx:marketplace-content:read\`
447
+
448
+ ### 실행
449
+
450
+ \`\`\`bash
451
+ gleam run -m glendix/marketplace
452
+ \`\`\`
453
+
454
+ 인터랙티브 TUI에서 위젯을 검색/선택하면 \`widgets/\` 디렉토리에 \`.mpk\`가 다운로드되고, \`src/widgets/\`에 바인딩 \`.gleam\` 파일이 자동 생성된다.
455
+
456
+ ## .mpk 위젯 컴포넌트 사용
457
+
458
+ \`widgets/\` 디렉토리에 \`.mpk\` 파일(Mendix 위젯 빌드 결과물)을 배치하면, 다른 위젯 안에서 기존 Mendix 위젯을 React 컴포넌트로 렌더링할 수 있다.
459
+
460
+ ### 1단계: \`.mpk\` 파일 배치
461
+
462
+ \`\`\`
463
+ 프로젝트 루트/
464
+ ├── widgets/
465
+ │ ├── Switch.mpk
466
+ │ └── Badge.mpk
467
+ ├── src/
468
+ └── gleam.toml
469
+ \`\`\`
470
+
471
+ ### 2단계: 바인딩 생성
472
+
473
+ \`\`\`bash
474
+ gleam run -m glendix/install
475
+ \`\`\`
476
+
477
+ 실행 시 다음이 자동 처리된다:
478
+ - \`.mpk\`에서 \`.mjs\`/\`.css\`를 추출하고 \`widget_ffi.mjs\`가 생성된다
479
+ - \`.mpk\` XML의 \`<property>\` 정의를 파싱하여 \`src/widgets/\`에 바인딩 \`.gleam\` 파일이 자동 생성된다 (이미 존재하면 건너뜀)
480
+
481
+ ### 3단계: 자동 생성된 \`src/widgets/*.gleam\` 파일 확인
482
+
483
+ \`\`\`gleam
484
+ // src/widgets/switch.gleam (자동 생성)
485
+ import glendix/mendix
486
+ import glendix/react.{type JsProps, type ReactElement}
487
+ import glendix/react/attribute
488
+ import glendix/widget
489
+
490
+ /// Switch 위젯 렌더링 - props에서 속성을 읽어 위젯에 전달
491
+ pub fn render(props: JsProps) -> ReactElement {
492
+ let boolean_attribute = mendix.get_prop_required(props, "booleanAttribute")
493
+ let action = mendix.get_prop_required(props, "action")
494
+
495
+ let comp = widget.component("Switch")
496
+ react.component_el(
497
+ comp,
498
+ [
499
+ attribute.attribute("booleanAttribute", boolean_attribute),
500
+ attribute.attribute("action", action),
501
+ ],
502
+ [],
503
+ )
504
+ }
505
+ \`\`\`
506
+
507
+ required/optional 속성이 자동 구분되며, 필요에 따라 생성된 파일을 자유롭게 수정할 수 있다.
508
+
509
+ ### 4단계: 위젯에서 사용
510
+
511
+ \`\`\`gleam
512
+ import widgets/switch
513
+
514
+ // 컴포넌트 내부에서
515
+ switch.render(props)
516
+ \`\`\`
517
+
518
+ 위젯 이름은 \`.mpk\` 내부 XML의 \`<name>\` 값을, property key는 \`.mpk\` XML의 원본 key를 그대로 사용한다.
519
+
520
+ ## 기술 스택
521
+
522
+ - **Gleam** → JavaScript 컴파일
523
+ - **[glendix](https://hexdocs.pm/glendix/)** — React + Mendix API Gleam 바인딩
524
+ - **Mendix Pluggable Widget** (React 19)
525
+ - **${pm}** — 패키지 매니저
526
+
527
+ ## 라이센스
528
+
529
+ Apache-2.0
530
+ `;
531
+ }
532
+
533
+ // ---------------------------------------------------------------------------
534
+ // Japanese
535
+ // ---------------------------------------------------------------------------
536
+
537
+ function generateJa(names, pm, installCmd) {
538
+ return `# ${names.pascalCase}
539
+
540
+ Gleam言語で作成されたMendix Pluggable Widget。
541
+
542
+ ## 基本原理
543
+
544
+ Gleam関数 \`fn(JsProps) -> ReactElement\` はReact関数コンポーネントと同一のシグネチャを持つ。glendixがReactプリミティブ関数とMendixランタイム型アクセサを型安全に提供するため、ウィジェットプロジェクトではビジネスロジックにのみ集中すればよい。
545
+
546
+ \`\`\`gleam
547
+ // src/${names.snakeCase}.gleam
548
+ import glendix/mendix
549
+ import glendix/react.{type JsProps, type ReactElement}
550
+ import glendix/react/attribute
551
+ import glendix/react/html
552
+
553
+ pub fn widget(props: JsProps) -> ReactElement {
554
+ let sample_text = mendix.get_string_prop(props, "sampleText")
555
+ html.div([attribute.class("widget-hello-world")], [
556
+ react.text("Hello " <> sample_text),
557
+ ])
558
+ }
559
+ \`\`\`
560
+
561
+ Mendixの複合型もGleamから型安全に使用できる:
562
+
563
+ \`\`\`gleam
564
+ import glendix/mendix
565
+ import glendix/mendix/editable_value
566
+ import glendix/mendix/action
567
+
568
+ pub fn widget(props: JsProps) -> ReactElement {
569
+ // EditableValueへのアクセス
570
+ let name_attr: EditableValue = mendix.get_prop_required(props, "name")
571
+ let display = editable_value.display_value(name_attr)
572
+
573
+ // ActionValueの実行
574
+ let on_save: Option(ActionValue) = mendix.get_prop(props, "onSave")
575
+ action.execute_action(on_save)
576
+ // ...
577
+ }
578
+ \`\`\`
579
+
580
+ ## はじめに
581
+
582
+ ### 前提条件
583
+
584
+ - [Gleam](https://gleam.run/getting-started/installing/)(最新バージョン)
585
+ - [Node.js](https://nodejs.org/)(v18以上)
586
+ - ${pm}
587
+
588
+ ### インストール
589
+
590
+ \`\`\`bash
591
+ gleam run -m glendix/install
592
+ \`\`\`
593
+
594
+ ### 開発
595
+
596
+ \`\`\`bash
597
+ gleam run -m glendix/dev
598
+ \`\`\`
599
+
600
+ ### ビルド
601
+
602
+ \`\`\`bash
603
+ gleam run -m glendix/build
604
+ \`\`\`
605
+
606
+ ビルド成果物(\`.mpk\`)は\`dist/\`ディレクトリに生成される。
607
+
608
+ ### その他のコマンド
609
+
610
+ \`\`\`bash
611
+ gleam run -m glendix/start # Mendixテストプロジェクト連携
612
+ gleam run -m glendix/lint # ESLint実行
613
+ gleam run -m glendix/lint_fix # ESLint自動修正
614
+ gleam run -m glendix/release # リリースビルド
615
+ gleam run -m glendix/marketplace # Marketplaceウィジェット検索/ダウンロード
616
+ gleam build --target javascript # Gleam → JSコンパイルのみ
617
+ gleam test # テスト実行
618
+ gleam format # コードフォーマット
619
+ \`\`\`
620
+
621
+ ## プロジェクト構成
622
+
623
+ \`\`\`
624
+ src/
625
+ ${names.snakeCase}.gleam # メインウィジェットモジュール
626
+ editor_config.gleam # Studio Proプロパティパネル
627
+ editor_preview.gleam # Studio Proデザインビュープレビュー
628
+ components/
629
+ hello_world.gleam # Hello World共有コンポーネント
630
+ ${names.pascalCase}.xml # ウィジェットプロパティ定義
631
+ widgets/ # .mpkウィジェットファイル(glendix/widgetでバインディング)
632
+ bindings.json # 外部Reactコンポーネントバインディング設定
633
+ package.json # npm依存関係(React、外部ライブラリなど)
634
+ \`\`\`
635
+
636
+ React/Mendix FFIバインディングは[glendix](https://hexdocs.pm/glendix/) Hexパッケージとして提供される。
637
+
638
+ ## 外部Reactコンポーネントの使用
639
+
640
+ npmパッケージとして提供されるReactコンポーネントライブラリを、\`.mjs\` FFIファイルを書くことなく純粋なGleamから使用できる。
641
+
642
+ ### ステップ1:npmパッケージのインストール
643
+
644
+ \`\`\`bash
645
+ ${installCmd} recharts
646
+ \`\`\`
647
+
648
+ ### ステップ2:\`bindings.json\`の作成
649
+
650
+ プロジェクトルートに\`bindings.json\`を作成し、使用するコンポーネントを登録する:
651
+
652
+ \`\`\`json
653
+ {
654
+ "recharts": {
655
+ "components": ["PieChart", "Pie", "Cell", "Tooltip", "ResponsiveContainer"]
656
+ }
657
+ }
658
+ \`\`\`
659
+
660
+ ### ステップ3:バインディングの生成
661
+
662
+ \`\`\`bash
663
+ gleam run -m glendix/install
664
+ \`\`\`
665
+
666
+ \`binding_ffi.mjs\`が自動生成される。以降の\`gleam run -m glendix/build\`等のビルド時にも自動更新される。
667
+
668
+ ### ステップ4:Gleamから使用
669
+
670
+ \`\`\`gleam
671
+ import glendix/binding
672
+ import glendix/react.{type ReactElement}
673
+ import glendix/react/attribute.{type Attribute}
674
+
675
+ fn m() { binding.module("recharts") }
676
+
677
+ pub fn pie_chart(attrs: List(Attribute), children: List(ReactElement)) -> ReactElement {
678
+ react.component_el(binding.resolve(m(), "PieChart"), attrs, children)
679
+ }
680
+
681
+ pub fn tooltip(attrs: List(Attribute)) -> ReactElement {
682
+ react.void_component_el(binding.resolve(m(), "Tooltip"), attrs)
683
+ }
684
+ \`\`\`
685
+
686
+ \`html.div\`と同じ呼び出しパターンで外部Reactコンポーネントを使用できる。
687
+
688
+ ## Mendix Marketplaceウィジェットのダウンロード
689
+
690
+ Mendix Marketplaceからウィジェット(.mpk)をインタラクティブに検索・ダウンロードできる。ダウンロード完了後、バインディング\`.gleam\`ファイルが自動生成され、すぐに使用可能になる。
691
+
692
+ ### 事前準備
693
+
694
+ \`.env\`ファイルにMendix Personal Access Tokenを設定する:
695
+
696
+ \`\`\`
697
+ MENDIX_PAT=your_personal_access_token
698
+ \`\`\`
699
+
700
+ > PATは[Mendix Developer Settings](https://user-settings.mendix.com/link/developersettings)の**Personal Access Tokens**セクションで**New Token**をクリックして発行。必要なscope:\`mx:marketplace-content:read\`
701
+
702
+ ### 実行
703
+
704
+ \`\`\`bash
705
+ gleam run -m glendix/marketplace
706
+ \`\`\`
707
+
708
+ インタラクティブTUIでウィジェットを検索・選択すると、\`widgets/\`ディレクトリに\`.mpk\`がダウンロードされ、\`src/widgets/\`にバインディング\`.gleam\`ファイルが自動生成される。
709
+
710
+ ## .mpkウィジェットコンポーネントの使用
711
+
712
+ \`widgets/\`ディレクトリに\`.mpk\`ファイル(Mendixウィジェットビルド成果物)を配置すると、別のウィジェット内から既存のMendixウィジェットをReactコンポーネントとしてレンダリングできる。
713
+
714
+ ### ステップ1:\`.mpk\`ファイルの配置
715
+
716
+ \`\`\`
717
+ プロジェクトルート/
718
+ ├── widgets/
719
+ │ ├── Switch.mpk
720
+ │ └── Badge.mpk
721
+ ├── src/
722
+ └── gleam.toml
723
+ \`\`\`
724
+
725
+ ### ステップ2:バインディングの生成
726
+
727
+ \`\`\`bash
728
+ gleam run -m glendix/install
729
+ \`\`\`
730
+
731
+ 実行時に以下が自動処理される:
732
+ - \`.mpk\`から\`.mjs\`/\`.css\`を抽出し、\`widget_ffi.mjs\`が生成される
733
+ - \`.mpk\` XMLの\`<property>\`定義をパースし、\`src/widgets/\`にバインディング\`.gleam\`ファイルが自動生成される(既存ファイルはスキップ)
734
+
735
+ ### ステップ3:自動生成された\`src/widgets/*.gleam\`ファイルの確認
736
+
737
+ \`\`\`gleam
738
+ // src/widgets/switch.gleam(自動生成)
739
+ import glendix/mendix
740
+ import glendix/react.{type JsProps, type ReactElement}
741
+ import glendix/react/attribute
742
+ import glendix/widget
743
+
744
+ /// Switchウィジェットのレンダリング - propsからプロパティを読み取りウィジェットに渡す
745
+ pub fn render(props: JsProps) -> ReactElement {
746
+ let boolean_attribute = mendix.get_prop_required(props, "booleanAttribute")
747
+ let action = mendix.get_prop_required(props, "action")
748
+
749
+ let comp = widget.component("Switch")
750
+ react.component_el(
751
+ comp,
752
+ [
753
+ attribute.attribute("booleanAttribute", boolean_attribute),
754
+ attribute.attribute("action", action),
755
+ ],
756
+ [],
757
+ )
758
+ }
759
+ \`\`\`
760
+
761
+ required/optionalプロパティは自動的に区別され、生成されたファイルは自由に編集できる。
762
+
763
+ ### ステップ4:ウィジェットで使用
764
+
765
+ \`\`\`gleam
766
+ import widgets/switch
767
+
768
+ // コンポーネント内で
769
+ switch.render(props)
770
+ \`\`\`
771
+
772
+ ウィジェット名は\`.mpk\`内部XMLの\`<name>\`値を、プロパティキーは\`.mpk\` XMLの元のキーをそのまま使用する。
773
+
774
+ ## 技術スタック
775
+
776
+ - **Gleam** → JavaScriptコンパイル
777
+ - **[glendix](https://hexdocs.pm/glendix/)** — React + Mendix API Gleamバインディング
778
+ - **Mendix Pluggable Widget**(React 19)
779
+ - **${pm}** — パッケージマネージャー
780
+
781
+ ## ライセンス
782
+
783
+ Apache-2.0
784
+ `;
785
+ }