create-mendix-widget-gleam 4.0.0 → 4.0.2

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 CHANGED
@@ -27,9 +27,8 @@ my-widget/
27
27
  editor_preview.gleam # Studio Pro 디자인 뷰 미리보기
28
28
  components/
29
29
  hello_world.gleam # Hello World 공유 컴포넌트
30
- widgets/ # .mpk 위젯 파일 (mendraw/widget로 바인딩)
31
30
  package.json # npm 의존성 (React, 외부 라이브러리 등)
32
- gleam.toml # Gleam 프로젝트 설정 (glendix >= 4.0.2 + mendraw >= 1.1.10 의존성 포함)
31
+ gleam.toml # Gleam 프로젝트 설정 (glendix >= 4.0.4 + mendraw >= 1.2.1 의존성 포함)
33
32
  CLAUDE.md # AI 어시스턴트용 프로젝트 컨텍스트
34
33
  ```
35
34
 
@@ -51,7 +50,7 @@ gleam run -m glendix/define # 위젯 프로퍼티 정의 TUI 에디터
51
50
  생성된 프로젝트는 [glendix](https://hexdocs.pm/glendix/) Hex 패키지를 의존성으로 사용한다. glendix가 React 원시 함수와 Mendix Pluggable Widget API 전체에 대한 타입 안전한 Gleam 바인딩을 제공한다:
52
51
 
53
52
  - **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`
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` 등
55
54
  - **JS Interop** (glendix) — `glendix/js/array`, `glendix/js/object`, `glendix/js/json`, `glendix/js/promise`, `glendix/js/dom`, `glendix/js/timer`
56
55
 
57
56
  ## 라이선스
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-mendix-widget-gleam",
3
- "version": "4.0.0",
3
+ "version": "4.0.2",
4
4
  "description": "Scaffold a Mendix Pluggable Widget powered by Gleam",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
package/src/index.mjs CHANGED
@@ -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));
@@ -151,7 +150,6 @@ export async function main(args) {
151
150
  // Build template comments (i18n for template placeholders)
152
151
  const templateComments = {
153
152
  ...getTemplateComments(lang),
154
- widgets_readme: generateWidgetsReadmeContent(lang),
155
153
  };
156
154
 
157
155
  // Scaffold options
@@ -63,7 +63,6 @@ Widget entry point signature: \`pub fn widget(props: JsProps) -> Element\` — i
63
63
  - \`src/${names.pascalCase}.xml\` — Widget property definitions. Adding \`<property>\` triggers automatic type generation by the build tool
64
64
  - \`src/package.xml\` — Mendix package manifest
65
65
  - \`gleam.toml [tools.glendix.bindings]\` — External React component binding configuration
66
- - \`widgets/\` — .mpk widget file bindings (used via \`mendraw/widget\`)
67
66
 
68
67
  ## Build Pipeline
69
68
 
@@ -94,7 +93,7 @@ src/*.gleam → gleam build → build/dev/javascript/**/*.mjs → Bridge JS (aut
94
93
  For detailed glendix API and Gleam syntax, see:
95
94
 
96
95
  - 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
+ - docs/mendraw_guide.md — mendraw usage guide (widget binding generation, Marketplace download, Classic widgets, Synthetic Data, Mendix type API)
98
97
  - docs/gleam_language_tour.md — Gleam syntax reference (types, pattern matching, FFI, use keyword, etc.)
99
98
 
100
99
  ## Mendix Documentation Sources
@@ -122,11 +122,10 @@ 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 mendraw/widget)
126
125
  package.json # npm dependencies (React, external libraries, etc.)
127
126
  \`\`\`
128
127
 
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/).
128
+ React bindings come from [redraw](https://hexdocs.pm/redraw/)/[redraw_dom](https://hexdocs.pm/redraw_dom/), Mendix API bindings from [mendraw](https://hexdocs.pm/mendraw/), and JS Interop from [glendix](https://hexdocs.pm/glendix/).
130
129
 
131
130
  ## Using External React Components
132
131
 
@@ -176,93 +175,6 @@ pub fn tooltip(attrs: List(Attribute)) -> Element {
176
175
 
177
176
  External React components follow the same calling pattern as \`html.div\`.
178
177
 
179
- ## Mendix Marketplace Widget Download
180
-
181
- Interactively search and download widgets (.mpk) from the Mendix Marketplace. After download, binding \`.gleam\` files are generated automatically and ready to use.
182
-
183
- ### Preparation
184
-
185
- Set your Mendix Personal Access Token in a \`.env\` file:
186
-
187
- \`\`\`
188
- MENDIX_PAT=your_personal_access_token
189
- \`\`\`
190
-
191
- > 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\`
192
-
193
- ### Run
194
-
195
- \`\`\`bash
196
- gleam run -m mendraw/marketplace
197
- \`\`\`
198
-
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/\`.
200
-
201
- ## Using .mpk Widget Components
202
-
203
- Place \`.mpk\` files (Mendix widget build artifacts) in the \`widgets/\` directory to render existing Mendix widgets as React components within your own widget.
204
-
205
- ### Step 1: Place the \`.mpk\` files
206
-
207
- \`\`\`
208
- project root/
209
- ├── widgets/
210
- │ ├── Switch.mpk
211
- │ └── Badge.mpk
212
- ├── src/
213
- └── gleam.toml
214
- \`\`\`
215
-
216
- ### Step 2: Generate bindings
217
-
218
- \`\`\`bash
219
- gleam run -m glendix/install
220
- \`\`\`
221
-
222
- This automatically:
223
- - Extracts \`.mjs\`/\`.css\` from \`.mpk\` and generates \`widget_ffi.mjs\`
224
- - Parses \`<property>\` definitions from \`.mpk\` XML and generates binding \`.gleam\` files in \`src/widgets/\` (existing files are skipped)
225
-
226
- ### Step 3: Review auto-generated \`src/widgets/*.gleam\` files
227
-
228
- \`\`\`gleam
229
- // src/widgets/switch.gleam (auto-generated)
230
- import mendraw/mendix.{type JsProps}
231
- import mendraw/interop
232
- import redraw.{type Element}
233
- import redraw/dom/attribute
234
- import mendraw/widget
235
-
236
- /// Render Switch widget - reads properties from props and passes them to the widget
237
- pub fn render(props: JsProps) -> Element {
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
- interop.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
178
  ## Tech Stack
267
179
 
268
180
  - **Gleam** → JavaScript compilation
@@ -378,11 +290,10 @@ src/
378
290
  components/
379
291
  hello_world.gleam # Hello World 공유 컴포넌트
380
292
  ${names.pascalCase}.xml # 위젯 속성 정의
381
- widgets/ # .mpk 위젯 파일 (mendraw/widget로 바인딩)
382
293
  package.json # npm 의존성 (React, 외부 라이브러리 등)
383
294
  \`\`\`
384
295
 
385
- React 바인딩은 [redraw](https://hexdocs.pm/redraw/)/[redraw_dom](https://hexdocs.pm/redraw_dom/)이, Mendix API JS Interop 바인딩은 [mendraw](https://hexdocs.pm/mendraw/)가 제공합니다.
296
+ React 바인딩은 [redraw](https://hexdocs.pm/redraw/)/[redraw_dom](https://hexdocs.pm/redraw_dom/)이, Mendix API 바인딩은 [mendraw](https://hexdocs.pm/mendraw/)가, JS Interop [glendix](https://hexdocs.pm/glendix/)가 제공합니다.
386
297
 
387
298
  ## 외부 React 컴포넌트 사용
388
299
 
@@ -432,93 +343,6 @@ pub fn tooltip(attrs: List(Attribute)) -> Element {
432
343
 
433
344
  \`html.div\`와 동일한 호출 패턴으로 외부 React 컴포넌트를 사용할 수 있다.
434
345
 
435
- ## Mendix Marketplace 위젯 다운로드
436
-
437
- Mendix Marketplace에서 위젯(.mpk)을 인터랙티브하게 검색하고 다운로드할 수 있다. 다운로드 완료 후 바인딩 \`.gleam\` 파일이 자동 생성되어 바로 사용 가능하다.
438
-
439
- ### 사전 준비
440
-
441
- \`.env\` 파일에 Mendix Personal Access Token을 설정한다:
442
-
443
- \`\`\`
444
- MENDIX_PAT=your_personal_access_token
445
- \`\`\`
446
-
447
- > PAT는 [Mendix Developer Settings](https://user-settings.mendix.com/link/developersettings)에서 **Personal Access Tokens** 섹션의 **New Token**을 클릭하여 발급. 필요한 scope: \`mx:marketplace-content:read\`
448
-
449
- ### 실행
450
-
451
- \`\`\`bash
452
- gleam run -m mendraw/marketplace
453
- \`\`\`
454
-
455
- 인터랙티브 TUI에서 위젯을 검색/선택하면 \`widgets/\` 디렉토리에 \`.mpk\`가 다운로드되고, \`src/widgets/\`에 바인딩 \`.gleam\` 파일이 자동 생성된다.
456
-
457
- ## .mpk 위젯 컴포넌트 사용
458
-
459
- \`widgets/\` 디렉토리에 \`.mpk\` 파일(Mendix 위젯 빌드 결과물)을 배치하면, 다른 위젯 안에서 기존 Mendix 위젯을 React 컴포넌트로 렌더링할 수 있다.
460
-
461
- ### 1단계: \`.mpk\` 파일 배치
462
-
463
- \`\`\`
464
- 프로젝트 루트/
465
- ├── widgets/
466
- │ ├── Switch.mpk
467
- │ └── Badge.mpk
468
- ├── src/
469
- └── gleam.toml
470
- \`\`\`
471
-
472
- ### 2단계: 바인딩 생성
473
-
474
- \`\`\`bash
475
- gleam run -m glendix/install
476
- \`\`\`
477
-
478
- 실행 시 다음이 자동 처리된다:
479
- - \`.mpk\`에서 \`.mjs\`/\`.css\`를 추출하고 \`widget_ffi.mjs\`가 생성된다
480
- - \`.mpk\` XML의 \`<property>\` 정의를 파싱하여 \`src/widgets/\`에 바인딩 \`.gleam\` 파일이 자동 생성된다 (이미 존재하면 건너뜀)
481
-
482
- ### 3단계: 자동 생성된 \`src/widgets/*.gleam\` 파일 확인
483
-
484
- \`\`\`gleam
485
- // src/widgets/switch.gleam (자동 생성)
486
- import mendraw/mendix.{type JsProps}
487
- import mendraw/interop
488
- import redraw.{type Element}
489
- import redraw/dom/attribute
490
- import mendraw/widget
491
-
492
- /// Switch 위젯 렌더링 - props에서 속성을 읽어 위젯에 전달
493
- pub fn render(props: JsProps) -> Element {
494
- let boolean_attribute = mendix.get_prop_required(props, "booleanAttribute")
495
- let action = mendix.get_prop_required(props, "action")
496
-
497
- let comp = widget.component("Switch")
498
- interop.component_el(
499
- comp,
500
- [
501
- attribute.attribute("booleanAttribute", boolean_attribute),
502
- attribute.attribute("action", action),
503
- ],
504
- [],
505
- )
506
- }
507
- \`\`\`
508
-
509
- required/optional 속성이 자동 구분되며, 필요에 따라 생성된 파일을 자유롭게 수정할 수 있다.
510
-
511
- ### 4단계: 위젯에서 사용
512
-
513
- \`\`\`gleam
514
- import widgets/switch
515
-
516
- // 컴포넌트 내부에서
517
- switch.render(props)
518
- \`\`\`
519
-
520
- 위젯 이름은 \`.mpk\` 내부 XML의 \`<name>\` 값을, property key는 \`.mpk\` XML의 원본 key를 그대로 사용한다.
521
-
522
346
  ## 기술 스택
523
347
 
524
348
  - **Gleam** → JavaScript 컴파일
@@ -634,11 +458,10 @@ src/
634
458
  components/
635
459
  hello_world.gleam # Hello World共有コンポーネント
636
460
  ${names.pascalCase}.xml # ウィジェットプロパティ定義
637
- widgets/ # .mpkウィジェットファイル(mendraw/widgetでバインディング)
638
461
  package.json # npm依存関係(React、外部ライブラリなど)
639
462
  \`\`\`
640
463
 
641
- Reactバインディングは[redraw](https://hexdocs.pm/redraw/)/[redraw_dom](https://hexdocs.pm/redraw_dom/)が、Mendix APIおよびJS Interopバインディングは[mendraw](https://hexdocs.pm/mendraw/)が提供する。
464
+ Reactバインディングは[redraw](https://hexdocs.pm/redraw/)/[redraw_dom](https://hexdocs.pm/redraw_dom/)が、Mendix APIバインディングは[mendraw](https://hexdocs.pm/mendraw/)が、JS Interopは[glendix](https://hexdocs.pm/glendix/)が提供する。
642
465
 
643
466
  ## 外部Reactコンポーネントの使用
644
467
 
@@ -688,93 +511,6 @@ pub fn tooltip(attrs: List(Attribute)) -> Element {
688
511
 
689
512
  \`html.div\`と同じ呼び出しパターンで外部Reactコンポーネントを使用できる。
690
513
 
691
- ## Mendix Marketplaceウィジェットのダウンロード
692
-
693
- Mendix Marketplaceからウィジェット(.mpk)をインタラクティブに検索・ダウンロードできる。ダウンロード完了後、バインディング\`.gleam\`ファイルが自動生成され、すぐに使用可能になる。
694
-
695
- ### 事前準備
696
-
697
- \`.env\`ファイルにMendix Personal Access Tokenを設定する:
698
-
699
- \`\`\`
700
- MENDIX_PAT=your_personal_access_token
701
- \`\`\`
702
-
703
- > PATは[Mendix Developer Settings](https://user-settings.mendix.com/link/developersettings)の**Personal Access Tokens**セクションで**New Token**をクリックして発行。必要なscope:\`mx:marketplace-content:read\`
704
-
705
- ### 実行
706
-
707
- \`\`\`bash
708
- gleam run -m mendraw/marketplace
709
- \`\`\`
710
-
711
- インタラクティブTUIでウィジェットを検索・選択すると、\`widgets/\`ディレクトリに\`.mpk\`がダウンロードされ、\`src/widgets/\`にバインディング\`.gleam\`ファイルが自動生成される。
712
-
713
- ## .mpkウィジェットコンポーネントの使用
714
-
715
- \`widgets/\`ディレクトリに\`.mpk\`ファイル(Mendixウィジェットビルド成果物)を配置すると、別のウィジェット内から既存のMendixウィジェットをReactコンポーネントとしてレンダリングできる。
716
-
717
- ### ステップ1:\`.mpk\`ファイルの配置
718
-
719
- \`\`\`
720
- プロジェクトルート/
721
- ├── widgets/
722
- │ ├── Switch.mpk
723
- │ └── Badge.mpk
724
- ├── src/
725
- └── gleam.toml
726
- \`\`\`
727
-
728
- ### ステップ2:バインディングの生成
729
-
730
- \`\`\`bash
731
- gleam run -m glendix/install
732
- \`\`\`
733
-
734
- 実行時に以下が自動処理される:
735
- - \`.mpk\`から\`.mjs\`/\`.css\`を抽出し、\`widget_ffi.mjs\`が生成される
736
- - \`.mpk\` XMLの\`<property>\`定義をパースし、\`src/widgets/\`にバインディング\`.gleam\`ファイルが自動生成される(既存ファイルはスキップ)
737
-
738
- ### ステップ3:自動生成された\`src/widgets/*.gleam\`ファイルの確認
739
-
740
- \`\`\`gleam
741
- // src/widgets/switch.gleam(自動生成)
742
- import mendraw/mendix.{type JsProps}
743
- import mendraw/interop
744
- import redraw.{type Element}
745
- import redraw/dom/attribute
746
- import mendraw/widget
747
-
748
- /// Switchウィジェットのレンダリング - propsからプロパティを読み取りウィジェットに渡す
749
- pub fn render(props: JsProps) -> Element {
750
- let boolean_attribute = mendix.get_prop_required(props, "booleanAttribute")
751
- let action = mendix.get_prop_required(props, "action")
752
-
753
- let comp = widget.component("Switch")
754
- interop.component_el(
755
- comp,
756
- [
757
- attribute.attribute("booleanAttribute", boolean_attribute),
758
- attribute.attribute("action", action),
759
- ],
760
- [],
761
- )
762
- }
763
- \`\`\`
764
-
765
- required/optionalプロパティは自動的に区別され、生成されたファイルは自由に編集できる。
766
-
767
- ### ステップ4:ウィジェットで使用
768
-
769
- \`\`\`gleam
770
- import widgets/switch
771
-
772
- // コンポーネント内で
773
- switch.render(props)
774
- \`\`\`
775
-
776
- ウィジェット名は\`.mpk\`内部XMLの\`<name>\`値を、プロパティキーは\`.mpk\` XMLの元のキーをそのまま使用する。
777
-
778
514
  ## 技術スタック
779
515
 
780
516
  - **Gleam** → JavaScriptコンパイル
@@ -1,4 +1,4 @@
1
- # glendix v4.0.2 — Agent Reference Guide
1
+ # glendix v4.0.4 — Agent Reference Guide
2
2
 
3
3
  > 이 문서는 AI 에이전트(LLM)가 glendix 코드를 작성할 때 참조하는 가이드입니다. 각 섹션은 독립적으로 읽을 수 있습니다.
4
4
 
@@ -46,8 +46,8 @@ glendix는 Gleam으로 Mendix Pluggable Widget을 작성하는 FFI 라이브러
46
46
 
47
47
  ```toml
48
48
  [dependencies]
49
- glendix = ">= 4.0.2 and < 5.0.0"
50
- mendraw = ">= 1.1.10 and < 2.0.0"
49
+ glendix = ">= 4.0.4 and < 5.0.0"
50
+ mendraw = ">= 1.2.1 and < 2.0.0"
51
51
  ```
52
52
 
53
53
  Peer dependency (위젯 프로젝트 `package.json`):
@@ -416,7 +416,6 @@ fn view(model: Model) {
416
416
  | 컴포넌트 출처 | 사용 모듈 | 예시 |
417
417
  |--------------|----------|------|
418
418
  | npm 패키지 (React 컴포넌트) | `glendix/binding` + `mendraw/interop` | recharts, @mui |
419
- | `.mpk` Pluggable 위젯 (gleam.toml) | `mendraw/widget` + `mendraw/interop` | Switch, Badge |
420
419
  | `.mpk` Classic (Dojo) 위젯 (gleam.toml) | `mendraw/classic` | CameraWidget |
421
420
 
422
421
  ### 7.2 외부 React 컴포넌트 (binding + interop)
@@ -455,57 +454,6 @@ pub fn tooltip(attrs: List(Attribute)) -> Element {
455
454
  | `interop.component_el_(comp, children)` | 자식만 |
456
455
  | `interop.void_component_el(comp, attrs)` | self-closing (자식 없음) |
457
456
 
458
- ### 7.3 .mpk Pluggable 위젯 (widget + interop)
459
-
460
- `gleam.toml`에 위젯을 등록하고 `gleam run -m glendix/install`로 자동 다운로드합니다:
461
-
462
- ```toml
463
- [tools.mendraw.widgets.Charts]
464
- version = "3.0.0"
465
- # s3_id = "com/..." ← 있으면 인증 없이 직접 다운로드
466
- ```
467
-
468
- `build/widgets/`에 캐시하고 바인딩을 자동 생성합니다.
469
- Marketplace TUI(`gleam run -m mendraw/marketplace`)에서 다운로드하면 gleam.toml에 자동 추가됩니다.
470
-
471
- 자동 생성되는 `src/widgets/*.gleam`:
472
-
473
- ```gleam
474
- import mendraw/interop
475
- import mendraw/mendix
476
- import mendraw/mendix.{type JsProps}
477
- import mendraw/widget
478
- import redraw.{type Element}
479
- import redraw/dom/attribute
480
-
481
- pub fn render(props: JsProps) -> Element {
482
- let boolean_attribute = mendix.get_prop_required(props, "booleanAttribute")
483
- let comp = widget.component("Switch")
484
- interop.component_el(comp, [
485
- attribute.attribute("booleanAttribute", boolean_attribute),
486
- ], [])
487
- }
488
- ```
489
-
490
- **위젯 prop 헬퍼:** 코드에서 직접 값을 생성하여 .mpk 위젯에 전달할 때 사용합니다.
491
-
492
- | 함수 | Mendix 타입 | 용도 |
493
- |------|------------|------|
494
- | `widget.prop(key, value)` | DynamicValue | 읽기 전용 (expression, textTemplate) |
495
- | `widget.editable_prop(key, value, display, set_value)` | EditableValue | 편집 가능한 속성 |
496
- | `widget.action_prop(key, handler)` | ActionValue | 액션 콜백 (onClick 등) |
497
-
498
- ```gleam
499
- import mendraw/widget
500
- import mendraw/interop
501
-
502
- let comp = widget.component("Badge button")
503
- interop.component_el(comp, [
504
- widget.prop("caption", "제목"),
505
- widget.editable_prop("textAttr", model.text, model.text, set_text),
506
- widget.action_prop("onClick", fn() { handle_click() }),
507
- ], [])
508
- ```
509
457
 
510
458
  > Mendix에서 받은 prop (JsProps에서 꺼낸 값)은 이미 올바른 형식이므로 `attribute.attribute(key, value)`로 그대로 전달합니다.
511
459
 
@@ -1140,7 +1088,6 @@ pub fn searchable_list(props: JsProps) -> Element {
1140
1088
  | `html.text("")`로 빈 렌더링 | `html.none()` 사용 |
1141
1089
  | `binding.resolve(m(), "pie_chart")` | JS 원본 이름 유지: `"PieChart"` |
1142
1090
  | 외부 React 컴포넌트용 `.mjs` 직접 작성 | `gleam.toml [tools.glendix.bindings]` + `glendix/binding` 사용 |
1143
- | `.mpk` 위젯용 `.mjs` 직접 작성 | `gleam.toml [tools.mendraw.widgets.*]` + `mendraw/widget` 사용 |
1144
1091
  | `date.month()`에 0-based 값 전달 | glendix가 1↔0 자동 변환 |
1145
1092
  | Editor config에서 Gleam List 사용 | 콤마 구분 String 사용 (Jint 호환) |
1146
1093
  | FFI `.mjs`에 비즈니스 로직 | `.gleam`에 작성. `.mjs`는 JS 런타임 접근만 |
@@ -1155,7 +1102,6 @@ pub fn searchable_list(props: JsProps) -> Element {
1155
1102
  | `Cannot read property of undefined` | 없는 prop 접근 | `get_prop` (Option) 사용, prop 이름 확인 |
1156
1103
  | Hook 순서 에러 | 조건부 Hook 호출 | 항상 동일 순서로 호출 (React Rules) |
1157
1104
  | 바인딩 미생성 | `binding_ffi.mjs` 스텁 상태 | `gleam run -m glendix/install` |
1158
- | 위젯 바인딩 미생성 | `widget_ffi.mjs` 스텁 상태 | `gleam.toml [tools.mendraw.widgets.*]` 설정 후 install |
1159
1105
  | `could not be resolved` | npm 패키지 미설치 | `npm install <패키지명>` |
1160
1106
  | `.env` PAT 오류 | marketplace 인증 실패 | [Developer Settings](https://user-settings.mendix.com/link/developersettings)에서 PAT 재발급 |
1161
1107
 
@@ -33,6 +33,12 @@ Pluggable(React) 위젯과 Classic(Dojo) 위젯을 모두 지원한다.
33
33
  - [mendraw/interop](#mendrawinterop)
34
34
  - [mendraw/classic](#mendrawclassic)
35
35
  - [mendraw/marketplace](#mendrawmarketplace)
36
+ - [외부 API 데이터를 Mendix 위젯에 전달 (Synthetic Data)](#외부-api-데이터를-mendix-위젯에-전달-synthetic-data)
37
+ - [개요](#synthetic-개요)
38
+ - [기본 사용법](#synthetic-기본-사용법)
39
+ - [차트 위젯에 사용하기](#차트-위젯에-사용하기)
40
+ - [DynamicDataGrid에 사용하기](#dynamicdatagrid에-사용하기)
41
+ - [API 레퍼런스 (synthetic)](#api-레퍼런스-synthetic)
36
42
  - [glendix 프로젝트에서 사용하기](#glendix-프로젝트에서-사용하기)
37
43
  - [문제 해결](#문제-해결)
38
44
 
@@ -57,7 +63,7 @@ gleam add mendraw@1
57
63
 
58
64
  ```toml
59
65
  [dependencies]
60
- mendraw = ">= 1.1.10 and < 2.0.0"
66
+ mendraw = ">= 1.0.0 and < 2.0.0"
61
67
  ```
62
68
 
63
69
  mendraw는 `gleam_stdlib`, `gleam_javascript`, `redraw`, `redraw_dom`을 함께 가져온다.
@@ -607,6 +613,207 @@ Mendix Marketplace 위젯 검색·다운로드 TUI. `gleam run -m mendraw/market
607
613
 
608
614
  ---
609
615
 
616
+ ## 외부 API 데이터를 Mendix 위젯에 전달 (Synthetic Data)
617
+
618
+ ### Synthetic 개요
619
+
620
+ Mendix 차트/그리드 위젯은 `ListValue`, `ObjectItem`, `ListAttributeValue` 등 Mendix 런타임에서만 생성되는 opaque 객체를 데이터 소스로 사용한다. `mendraw/synthetic` 모듈은 이 인터페이스를 모사하는 객체를 Gleam에서 직접 생성하여, 외부 API 데이터(CoinGecko, 날씨 API 등)를 Mendix Marketplace 위젯에 직접 전달할 수 있게 한다.
621
+
622
+ 지원하는 위젯 유형:
623
+ - **Charts** (Line, Area, Bar, Column, Pie, Time Series, Heat Map, Bubble, Custom)
624
+ - **Dynamic Data Grid** (3단계 cell/row/column 계층 포함)
625
+
626
+ ### Synthetic 기본 사용법
627
+
628
+ ```gleam
629
+ import mendraw/synthetic
630
+ import gleam/float
631
+
632
+ // 1. ObjectItem 생성 — 데이터 행 수만큼
633
+ let items = synthetic.object_items(3) // synth_0, synth_1, synth_2
634
+
635
+ // 2. ListValue 생성 — ObjectItem 목록을 감싸는 데이터 소스
636
+ let lv = synthetic.list_value(items)
637
+
638
+ // 3. ListAttributeValue 생성 — 각 아이템의 특정 필드값 + 표시 함수 + Mendix 타입
639
+ let prices = [100.0, 200.0, 150.0]
640
+ let price_attr = synthetic.list_attribute(items, prices, float.to_string, "Decimal")
641
+ // price_attr.get(synth_0) → EditableValue { value: BigNumber(100.0), displayValue: "100.0" }
642
+
643
+ // 4. TextTemplate 생성
644
+ let static_name = synthetic.text_template("My Series")
645
+ // chart에서 .value로 직접 접근하거나 .get(item)으로 접근 모두 지원
646
+
647
+ // 5. List-bound TextTemplate — 아이템별 다른 텍스트
648
+ let names = ["Bitcoin", "Ethereum", "Solana"]
649
+ let name_tmpl = synthetic.list_text_template(items, names)
650
+ // name_tmpl.get(synth_0) → { status: "available", value: "Bitcoin" }
651
+ ```
652
+
653
+ **타입 래핑 규칙:**
654
+
655
+ | Mendix 타입 | Gleam 값 | JS 래핑 |
656
+ |---|---|---|
657
+ | `"Decimal"`, `"Integer"`, `"Long"` | `Float` / `Int` | Big.js 호환 객체 (`.toNumber()`, `.toFixed()` 등) |
658
+ | `"DateTime"` | `Float` (밀리초 타임스탬프) | `new Date(timestamp)` |
659
+ | `"String"` | `String` | 그대로 전달 |
660
+
661
+ ### 차트 위젯에 사용하기
662
+
663
+ Mendix 차트 위젯의 `lines`/`series` prop은 시리즈 설정 객체의 JS 배열을 기대한다.
664
+ `chart_series_static()`으로 이 객체를 생성하고, `to_js_array()`로 Gleam List를 JS Array로 변환한다.
665
+
666
+ #### Line Chart / Time Series 예시
667
+
668
+ ```gleam
669
+ import mendraw/synthetic
670
+ import mendraw/interop
671
+ import mendraw/widget
672
+ import redraw/dom/attribute
673
+ import gleam/float
674
+
675
+ let items = synthetic.object_items(100)
676
+ let lv = synthetic.list_value(items)
677
+ let x_attr = synthetic.list_attribute(items, timestamps, float.to_string, "DateTime")
678
+ let y_attr = synthetic.list_attribute(items, prices, float.to_string, "Decimal")
679
+
680
+ // 시리즈 설정 객체 생성
681
+ let series = synthetic.chart_series_static(
682
+ lv, x_attr, y_attr,
683
+ synthetic.text_template("BTC Price"),
684
+ "none", // aggregation: "none" | "count" | "sum" | "avg" ...
685
+ "linear", // interpolation: "linear" | "spline"
686
+ "line", // lineStyle: "line" | "lines+markers"
687
+ "", // lineColor (빈 문자열 = 기본값)
688
+ "", // barColor
689
+ )
690
+
691
+ let comp = widget.component("Line chart")
692
+ interop.component_el(comp, [
693
+ attribute.attribute("lines", synthetic.to_js_array([series])),
694
+ attribute.attribute("showLegend", True),
695
+ attribute.attribute("gridLines", "horizontal"),
696
+ attribute.attribute("widthUnit", "percentage"),
697
+ attribute.attribute("width", 100),
698
+ attribute.attribute("heightUnit", "pixels"),
699
+ attribute.attribute("height", 400),
700
+ ], [])
701
+ ```
702
+
703
+ Time Series 위젯도 동일한 구조이며, `showRangeSlider` prop을 추가하면 범위 슬라이더가 표시된다.
704
+
705
+ #### Pie Chart 예시
706
+
707
+ Pie Chart는 `seriesDataSource`, `seriesName`, `seriesValueAttribute`를 직접 전달한다 (시리즈 배열 없음).
708
+
709
+ ```gleam
710
+ let items = synthetic.object_items(10)
711
+ let lv = synthetic.list_value(items)
712
+ let name_tmpl = synthetic.list_text_template(items, coin_names)
713
+ let value_attr = synthetic.list_attribute(items, market_caps, float.to_string, "Decimal")
714
+
715
+ let comp = widget.component("Pie chart")
716
+ interop.component_el(comp, [
717
+ attribute.attribute("seriesDataSource", lv),
718
+ attribute.attribute("seriesName", name_tmpl),
719
+ attribute.attribute("seriesValueAttribute", value_attr),
720
+ attribute.attribute("showLegend", True),
721
+ ], [])
722
+ ```
723
+
724
+ #### Column / Bar Chart 예시
725
+
726
+ Column/Bar 차트는 Line Chart와 동일한 시리즈 구조를 사용하되, prop 키가 `"series"`이다.
727
+
728
+ ```gleam
729
+ let series = synthetic.chart_series_static(
730
+ lv, x_attr, y_attr,
731
+ synthetic.text_template("Volume"),
732
+ "none", "", "", "", "#3b82f6", // barColor 지정
733
+ )
734
+
735
+ let comp = widget.component("Column chart")
736
+ interop.component_el(comp, [
737
+ attribute.attribute("series", synthetic.to_js_array([series])),
738
+ // ...
739
+ ], [])
740
+ ```
741
+
742
+ ### DynamicDataGrid에 사용하기
743
+
744
+ DynamicDataGrid는 3단계 계층 구조를 사용한다:
745
+ - **Row** — 행 (예: 각 코인)
746
+ - **Column** — 열 (예: Price, Volume, Market Cap)
747
+ - **Cell** — 행×열 교차점의 값 (N rows × M columns = N*M cells)
748
+
749
+ Cell은 `referenceRow`와 `referenceColumn` association으로 자신이 속한 행/열을 참조한다.
750
+
751
+ ```gleam
752
+ import mendraw/synthetic
753
+
754
+ let num_rows = 20 // 코인 수
755
+ let num_cols = 5 // 속성 수
756
+ let num_cells = num_rows * num_cols
757
+
758
+ let row_items = synthetic.object_items(num_rows)
759
+ let col_items = synthetic.object_items(num_cols)
760
+ let cell_items = synthetic.object_items(num_cells)
761
+
762
+ // 데이터 소스
763
+ let cell_source = synthetic.list_value(cell_items)
764
+ let row_source = synthetic.list_value(row_items)
765
+ let col_source = synthetic.list_value(col_items)
766
+
767
+ // Cell→Row, Cell→Column 참조 (각 cell이 어느 행/열에 속하는지)
768
+ let ref_row = synthetic.association(cell_items, cell_to_row_mapping)
769
+ let ref_col = synthetic.association(cell_items, cell_to_col_mapping)
770
+
771
+ // 표시 속성
772
+ let cell_attr = synthetic.list_attribute(cell_items, cell_values, fn(s) { s }, "String")
773
+ let row_attr = synthetic.list_attribute(row_items, row_names, fn(s) { s }, "String")
774
+ let col_attr = synthetic.list_attribute(col_items, column_headers, fn(s) { s }, "String")
775
+
776
+ let comp = widget.component("Dynamic data grid")
777
+ interop.component_el(comp, [
778
+ attribute.attribute("dataSourceCell", cell_source),
779
+ attribute.attribute("dataSourceRow", row_source),
780
+ attribute.attribute("dataSourceColumn", col_source),
781
+ attribute.attribute("referenceRow", ref_row),
782
+ attribute.attribute("referenceColumn", ref_col),
783
+ attribute.attribute("showCellAs", "attribute"),
784
+ attribute.attribute("cellAttribute", cell_attr),
785
+ attribute.attribute("showRowAs", "attribute"),
786
+ attribute.attribute("rowAttribute", row_attr),
787
+ attribute.attribute("showHeaderAs", "attribute"),
788
+ attribute.attribute("headerAttribute", col_attr),
789
+ attribute.attribute("renderAs", "table"),
790
+ ], [])
791
+ ```
792
+
793
+ ### API 레퍼런스 (synthetic)
794
+
795
+ #### 데이터 생성
796
+
797
+ | 함수 | 시그니처 | 설명 |
798
+ |------|----------|------|
799
+ | `object_item` | `(String) -> ObjectItem` | 지정 id로 ObjectItem 생성 |
800
+ | `object_items` | `(Int) -> List(ObjectItem)` | N개 ObjectItem 생성 (`synth_0`, `synth_1`, ...) |
801
+ | `list_value` | `(List(ObjectItem)) -> ListValue` | ObjectItem 목록을 ListValue로 래핑 |
802
+ | `list_attribute` | `(List(ObjectItem), List(a), fn(a) -> String, String) -> ListAttributeValue` | 아이템별 속성값 + 표시함수 + Mendix 타입 |
803
+ | `text_template` | `(String) -> a` | 정적 텍스트 템플릿 (`.value` + `.get()` 양쪽 지원) |
804
+ | `list_text_template` | `(List(ObjectItem), List(String)) -> ListExpressionValue` | 아이템별 텍스트 템플릿 |
805
+ | `list_expression` | `(List(ObjectItem), List(a)) -> ListExpressionValue` | 아이템별 표현식 값 |
806
+ | `association` | `(List(ObjectItem), List(ObjectItem)) -> a` | 소스→타겟 연관 관계 |
807
+
808
+ #### 차트 시리즈
809
+
810
+ | 함수 | 시그니처 | 설명 |
811
+ |------|----------|------|
812
+ | `chart_series_static` | `(ListValue, ListAttributeValue, ListAttributeValue, a, String, String, String, String, String) -> b` | 정적 차트 시리즈 설정 객체 생성 (dataSource, x, y, name, aggregation, interpolation, lineStyle, lineColor, barColor) |
813
+ | `to_js_array` | `(List(a)) -> b` | Gleam List → JS Array 변환 |
814
+
815
+ ---
816
+
610
817
  ## glendix 프로젝트에서 사용하기
611
818
 
612
819
  [glendix](https://github.com/) 프로젝트에서 mendraw를 의존성으로 추가하면,
@@ -661,6 +868,23 @@ install을 실행하지 않고 위젯 모듈을 import하면 이 에러가 발
661
868
  - `classic_ffi.mjs`가 빌드 경로에 정상적으로 생성되었는지 확인
662
869
  - `widget_id`가 정확한지 확인 (예: `"CameraWidget.widget.CameraWidget"`)
663
870
 
871
+ ### Synthetic 데이터 차트에서 `toNumber is not a function` 에러
872
+
873
+ 차트 위젯은 Decimal 값에 Big.js의 `.toNumber()` 메서드를 호출한다.
874
+ `list_attribute`의 `attr_type` 파라미터가 `"Decimal"`, `"Integer"`, `"Long"` 중 하나인지 확인한다.
875
+ 해당 타입으로 지정하면 synthetic 모듈이 자동으로 Big.js 호환 객체로 래핑한다.
876
+
877
+ ### Synthetic 데이터 차트에서 `get is not a function` 에러
878
+
879
+ 차트 위젯이 `staticName` 등 textTemplate 속성에서 `.get(item)` 메서드를 호출한다.
880
+ `synthetic.text_template()`은 `.get()` 메서드를 포함하므로 정상 동작해야 한다.
881
+ 커스텀 JS 객체를 직접 전달하는 경우 `.get(item)` 메서드가 있는지 확인한다.
882
+
883
+ ### Chart 위젯의 shared-charts.mjs 경로 에러
884
+
885
+ `Could not resolve "../../../shared/charts/esm/shared-charts.mjs"` 에러가 발생하면
886
+ `gleam run -m mendraw/install`을 다시 실행한다. mendraw가 자동으로 공유 의존성 파일을 복사하고 import 경로를 재작성한다.
887
+
664
888
  ### Pluggable 위젯과 Classic 위젯을 구분하는 기준
665
889
 
666
890
  mendraw는 `.mpk` 파일 내부의 구조로 자동 판별한다:
@@ -8,8 +8,8 @@ runtime = "node"
8
8
 
9
9
  [dependencies]
10
10
  gleam_stdlib = ">= 0.44.0 and < 2.0.0"
11
- glendix = ">= 4.0.2 and < 5.0.0"
12
- mendraw = ">= 1.1.10 and < 2.0.0"
11
+ glendix = ">= 4.0.4 and < 5.0.0"
12
+ mendraw = ">= 1.2.1 and < 2.0.0"
13
13
  dee = ">= 1.0.0 and < 2.0.0"
14
14
  redraw = ">= 19.2.2 and < 20.0.0"
15
15
  redraw_dom = ">= 19.2.2 and < 20.0.0"
@@ -1,275 +0,0 @@
1
- /**
2
- * widgets/README.md template — 3 language versions
3
- */
4
-
5
- export function generateWidgetsReadmeContent(lang) {
6
- switch (lang) {
7
- case "ko":
8
- return generateKo();
9
- case "ja":
10
- return generateJa();
11
- default:
12
- return generateEn();
13
- }
14
- }
15
-
16
- function generateEn() {
17
- return `# widgets/
18
-
19
- Mendix widget binding directory. Place \`.mpk\` files (Mendix widget build artifacts) in this directory to render existing Mendix widgets as React components from Gleam code.
20
-
21
- ## Usage
22
-
23
- ### 1. Place \`.mpk\` files
24
-
25
- Copy built Mendix widget \`.mpk\` files into this directory:
26
-
27
- \`\`\`
28
- widgets/
29
- ├── Switch.mpk
30
- ├── Badge.mpk
31
- └── README.md
32
- \`\`\`
33
-
34
- ### 2. Generate bindings
35
-
36
- \`\`\`bash
37
- gleam run -m glendix/install
38
- \`\`\`
39
-
40
- This automatically:
41
-
42
- - Extracts \`.mjs\` and \`.css\` from \`.mpk\` and generates \`widget_ffi.mjs\`
43
- - Parses \`<property>\` definitions from \`.mpk\` XML and generates binding \`.gleam\` files in \`src/widgets/\` (existing files are skipped)
44
-
45
- ### 3. Review auto-generated bindings
46
-
47
- For example, placing \`Switch.mpk\` generates \`src/widgets/switch.gleam\`:
48
-
49
- \`\`\`gleam
50
- // src/widgets/switch.gleam (auto-generated)
51
- import mendraw/interop
52
- import mendraw/mendix.{type JsProps}
53
- import mendraw/widget
54
- import redraw.{type Element}
55
- import redraw/dom/attribute
56
-
57
- /// Render Switch widget - reads properties from props and passes them to the widget
58
- pub fn render(props: JsProps) -> Element {
59
- let boolean_attribute = mendix.get_prop_required(props, "booleanAttribute")
60
- let action = mendix.get_prop_required(props, "action")
61
-
62
- let comp = widget.component("Switch")
63
- interop.component_el(
64
- comp,
65
- [
66
- attribute.attribute("booleanAttribute", boolean_attribute),
67
- attribute.attribute("action", action),
68
- ],
69
- [],
70
- )
71
- }
72
- \`\`\`
73
-
74
- - Required/optional properties are distinguished automatically
75
- - If optional properties exist, \`optional_attr\` helper and \`gleam/option\` import are added automatically
76
- - Gleam reserved words (e.g. \`type\`) are automatically suffixed with \`_\`
77
- - Generated files can be freely modified as needed
78
-
79
- ### 4. Use from Gleam
80
-
81
- \`\`\`gleam
82
- import widgets/switch
83
-
84
- // Inside a component
85
- switch.render(props)
86
- \`\`\`
87
-
88
- ## How it works
89
-
90
- - \`mendraw/widget\` module's \`widget.component("Name")\` imports \`.mpk\` widgets as React components
91
- - Props are passed via the generic \`attribute.attribute(key, value)\` function
92
- - Widget names use the \`<name>\` value from the \`.mpk\`'s internal XML, and property keys use the original keys from the \`.mpk\` XML
93
- - Unlike the \`binding\` module, 1 mpk = 1 component, so \`widget.component("Name")\` imports it in one call
94
-
95
- ## Notes
96
-
97
- - After adding/removing \`.mpk\` files, you must run \`gleam run -m glendix/install\` again
98
- - \`widget_ffi.mjs\` is auto-generated — do not edit it directly
99
- - Do not write \`.mjs\` FFI files for \`.mpk\` widgets manually — use the \`widgets/\` directory + \`mendraw/widget\`
100
- `;
101
- }
102
-
103
- function generateKo() {
104
- return `# widgets/
105
-
106
- Mendix 위젯 바인딩 디렉토리. \`.mpk\` 파일(Mendix 위젯 빌드 결과물)을 이 디렉토리에 배치하면, Gleam 코드에서 기존 Mendix 위젯을 React 컴포넌트로 렌더링할 수 있다.
107
-
108
- ## 사용법
109
-
110
- ### 1. \`.mpk\` 파일 배치
111
-
112
- 빌드된 Mendix 위젯의 \`.mpk\` 파일을 이 디렉토리에 복사한다:
113
-
114
- \`\`\`
115
- widgets/
116
- ├── Switch.mpk
117
- ├── Badge.mpk
118
- └── README.md
119
- \`\`\`
120
-
121
- ### 2. 바인딩 생성
122
-
123
- \`\`\`bash
124
- gleam run -m glendix/install
125
- \`\`\`
126
-
127
- 실행 시 다음이 자동 처리된다:
128
-
129
- - \`.mpk\` 내부의 \`.mjs\`와 \`.css\`가 추출되고, \`widget_ffi.mjs\`가 생성된다
130
- - \`.mpk\` XML의 \`<property>\` 정의를 파싱하여 \`src/widgets/\`에 바인딩 \`.gleam\` 파일이 자동 생성된다 (이미 존재하면 건너뜀)
131
-
132
- ### 3. 자동 생성된 바인딩 확인
133
-
134
- 예를 들어 \`Switch.mpk\`를 배치하면 \`src/widgets/switch.gleam\`이 생성된다:
135
-
136
- \`\`\`gleam
137
- // src/widgets/switch.gleam (자동 생성)
138
- import mendraw/interop
139
- import mendraw/mendix.{type JsProps}
140
- import mendraw/widget
141
- import redraw.{type Element}
142
- import redraw/dom/attribute
143
-
144
- /// Switch 위젯 렌더링 - props에서 속성을 읽어 위젯에 전달
145
- pub fn render(props: JsProps) -> Element {
146
- let boolean_attribute = mendix.get_prop_required(props, "booleanAttribute")
147
- let action = mendix.get_prop_required(props, "action")
148
-
149
- let comp = widget.component("Switch")
150
- interop.component_el(
151
- comp,
152
- [
153
- attribute.attribute("booleanAttribute", boolean_attribute),
154
- attribute.attribute("action", action),
155
- ],
156
- [],
157
- )
158
- }
159
- \`\`\`
160
-
161
- - required/optional 속성이 자동 구분된다
162
- - optional 속성이 있으면 \`optional_attr\` 헬퍼와 \`gleam/option\` import가 자동 추가된다
163
- - Gleam 예약어(\`type\` 등)는 접미사 \`_\`로 자동 회피된다
164
- - 생성된 파일은 필요에 따라 자유롭게 수정 가능하다
165
-
166
- ### 4. Gleam에서 사용
167
-
168
- \`\`\`gleam
169
- import widgets/switch
170
-
171
- // 컴포넌트 내부에서
172
- switch.render(props)
173
- \`\`\`
174
-
175
- ## 동작 원리
176
-
177
- - \`mendraw/widget\` 모듈의 \`widget.component("Name")\`으로 \`.mpk\` 위젯을 React 컴포넌트로 가져온다
178
- - Props는 \`attribute.attribute(key, value)\` 범용 함수로 전달한다
179
- - 위젯 이름은 \`.mpk\` 내부 XML의 \`<name>\` 값을, property key는 XML의 원본 key를 그대로 사용한다
180
- - \`binding\` 모듈과 달리 1 mpk = 1 컴포넌트이므로 \`widget.component("Name")\` 한 번에 가져온다
181
-
182
- ## 주의사항
183
-
184
- - \`.mpk\` 파일을 추가/제거한 후에는 반드시 \`gleam run -m glendix/install\`을 다시 실행해야 한다
185
- - \`widget_ffi.mjs\`는 자동 생성 파일이므로 직접 수정하지 않는다
186
- - \`.mpk\` 위젯용 \`.mjs\` FFI 파일을 직접 작성하지 않는다 — \`widgets/\` 디렉토리 + \`mendraw/widget\`을 사용한다
187
- `;
188
- }
189
-
190
- function generateJa() {
191
- return `# widgets/
192
-
193
- Mendixウィジェットバインディングディレクトリ。\`.mpk\`ファイル(Mendixウィジェットビルド成果物)をこのディレクトリに配置すると、Gleamコードから既存のMendixウィジェットをReactコンポーネントとしてレンダリングできる。
194
-
195
- ## 使い方
196
-
197
- ### 1. \`.mpk\`ファイルの配置
198
-
199
- ビルド済みMendixウィジェットの\`.mpk\`ファイルをこのディレクトリにコピーする:
200
-
201
- \`\`\`
202
- widgets/
203
- ├── Switch.mpk
204
- ├── Badge.mpk
205
- └── README.md
206
- \`\`\`
207
-
208
- ### 2. バインディングの生成
209
-
210
- \`\`\`bash
211
- gleam run -m glendix/install
212
- \`\`\`
213
-
214
- 実行時に以下が自動処理される:
215
-
216
- - \`.mpk\`内部の\`.mjs\`と\`.css\`が抽出され、\`widget_ffi.mjs\`が生成される
217
- - \`.mpk\` XMLの\`<property>\`定義をパースし、\`src/widgets/\`にバインディング\`.gleam\`ファイルが自動生成される(既存ファイルはスキップ)
218
-
219
- ### 3. 自動生成されたバインディングの確認
220
-
221
- 例えば\`Switch.mpk\`を配置すると\`src/widgets/switch.gleam\`が生成される:
222
-
223
- \`\`\`gleam
224
- // src/widgets/switch.gleam(自動生成)
225
- import mendraw/interop
226
- import mendraw/mendix.{type JsProps}
227
- import mendraw/widget
228
- import redraw.{type Element}
229
- import redraw/dom/attribute
230
-
231
- /// Switchウィジェットのレンダリング - propsからプロパティを読み取りウィジェットに渡す
232
- pub fn render(props: JsProps) -> Element {
233
- let boolean_attribute = mendix.get_prop_required(props, "booleanAttribute")
234
- let action = mendix.get_prop_required(props, "action")
235
-
236
- let comp = widget.component("Switch")
237
- interop.component_el(
238
- comp,
239
- [
240
- attribute.attribute("booleanAttribute", boolean_attribute),
241
- attribute.attribute("action", action),
242
- ],
243
- [],
244
- )
245
- }
246
- \`\`\`
247
-
248
- - required/optionalプロパティは自動的に区別される
249
- - optionalプロパティがある場合、\`optional_attr\`ヘルパーと\`gleam/option\` importが自動追加される
250
- - Gleam予約語(\`type\`等)はサフィックス\`_\`で自動回避される
251
- - 生成されたファイルは必要に応じて自由に編集できる
252
-
253
- ### 4. Gleamから使用
254
-
255
- \`\`\`gleam
256
- import widgets/switch
257
-
258
- // コンポーネント内で
259
- switch.render(props)
260
- \`\`\`
261
-
262
- ## 仕組み
263
-
264
- - \`mendraw/widget\`モジュールの\`widget.component("Name")\`で\`.mpk\`ウィジェットをReactコンポーネントとしてインポートする
265
- - Propsは\`attribute.attribute(key, value)\`汎用関数で渡す
266
- - ウィジェット名は\`.mpk\`内部XMLの\`<name>\`値を、プロパティキーはXMLの元のキーをそのまま使用する
267
- - \`binding\`モジュールと異なり1 mpk = 1コンポーネントなので、\`widget.component("Name")\`で一度にインポートする
268
-
269
- ## 注意事項
270
-
271
- - \`.mpk\`ファイルを追加/削除した後は必ず\`gleam run -m glendix/install\`を再実行すること
272
- - \`widget_ffi.mjs\`は自動生成ファイルなので直接編集しない
273
- - \`.mpk\`ウィジェット用の\`.mjs\` FFIファイルを直接記述しない — \`widgets/\`ディレクトリ + \`mendraw/widget\`を使用する
274
- `;
275
- }
@@ -1 +0,0 @@
1
- {{I18N:widgets_readme}}