create-mendix-widget-gleam 3.0.2 → 4.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,328 @@
1
+ # mendraw 사용 가이드
2
+
3
+ Mendix 위젯 Gleam/[redraw](https://hexdocs.pm/redraw/) 바인딩 라이브러리.
4
+ Classic(Dojo) 위젯 지원과 Marketplace 검색/다운로드 기능을 제공한다.
5
+
6
+ ---
7
+
8
+ ## 목차
9
+
10
+ - [사전 준비](#사전-준비)
11
+ - [설치](#설치)
12
+ - [Marketplace에서 위젯 다운로드](#marketplace에서-위젯-다운로드)
13
+ - [Classic (Dojo) 위젯](#classic-dojo-위젯)
14
+ - [Classic 위젯 직접 렌더링](#classic-위젯-직접-렌더링)
15
+ - [JsProps 다루기](#jsprops-다루기)
16
+ - [Prop 접근자](#prop-접근자)
17
+ - [ValueStatus](#valuestatus)
18
+ - [Option 변환](#option-변환)
19
+ - [API 레퍼런스](#api-레퍼런스)
20
+ - [mendraw/mendix](#mendrawmendix)
21
+ - [mendraw/interop](#mendrawinterop)
22
+ - [mendraw/classic](#mendrawclassic)
23
+ - [mendraw/marketplace](#mendrawmarketplace)
24
+ - [glendix 프로젝트에서 사용하기](#glendix-프로젝트에서-사용하기)
25
+ - [문제 해결](#문제-해결)
26
+
27
+ ---
28
+
29
+ ## 사전 준비
30
+
31
+ - [Gleam](https://gleam.run/) v1.15 이상
32
+ - [Erlang/OTP](https://www.erlang.org/) 28 이상
33
+ - Gleam 프로젝트의 타겟이 `javascript`여야 한다 (`gleam.toml`의 `target = "javascript"`)
34
+ - [redraw](https://hexdocs.pm/redraw/) 기반 UI 프로젝트
35
+
36
+ ---
37
+
38
+ ## 설치
39
+
40
+ ```sh
41
+ gleam add mendraw@1
42
+ ```
43
+
44
+ `gleam.toml`에 다음 의존성이 추가된다:
45
+
46
+ ```toml
47
+ [dependencies]
48
+ mendraw = ">= 1.1.11 and < 2.0.0"
49
+ ```
50
+
51
+ mendraw는 `gleam_stdlib`, `gleam_javascript`, `redraw`, `redraw_dom`을 함께 가져온다.
52
+ 이미 프로젝트에 이들이 있다면 버전 호환성만 확인하면 된다.
53
+
54
+ ---
55
+
56
+ ## Marketplace에서 위젯 다운로드
57
+
58
+ Mendix Marketplace에서 위젯을 검색하고 다운로드할 수 있는 TUI를 제공한다.
59
+
60
+ ### 사전 설정
61
+
62
+ `.env` 파일에 Mendix Personal Access Token을 설정한다:
63
+
64
+ ```
65
+ MENDIX_PAT=your_personal_access_token
66
+ ```
67
+
68
+ PAT는 Mendix Portal → Settings → Personal Access Tokens에서 발급한다.
69
+ 필요한 scope: `mx:marketplace-content:read`
70
+
71
+ ### 실행
72
+
73
+ ```sh
74
+ gleam run -m mendraw/marketplace
75
+ ```
76
+
77
+ ### TUI 모드 (터미널)
78
+
79
+ 터미널에서 실행하면 인터랙티브 TUI가 표시된다:
80
+
81
+ | 키 | 동작 |
82
+ |---|---|
83
+ | `↑` `↓` | 위젯 목록 이동 |
84
+ | `←` `→` | 페이지 이동 |
85
+ | `Space` | 위젯 선택/해제 (복수 선택) |
86
+ | `Enter` | 선택한 위젯 다운로드 → 버전 선택 화면 |
87
+ | `Esc` | 검색/선택 초기화 |
88
+ | 문자 입력 | 이름/퍼블리셔 검색 |
89
+ | `q` | 종료 |
90
+
91
+ 버전 선택 화면에서:
92
+
93
+ | 키 | 동작 |
94
+ |---|---|
95
+ | `↑` `↓` | 버전 이동 |
96
+ | `Enter` | 선택한 버전 다운로드 |
97
+ | `Esc` | 목록으로 돌아가기 |
98
+
99
+ ### 프롬프트 모드 (비-TTY)
100
+
101
+ 파이프 등 비-TTY 환경에서는 텍스트 프롬프트 모드로 동작한다:
102
+
103
+ ```
104
+ > 0 ← 0번 위젯 다운로드
105
+ > 0,3,5 ← 여러 위젯 동시 선택
106
+ > switch ← "switch" 검색
107
+ > n ← 다음 페이지
108
+ > p ← 이전 페이지
109
+ > r ← 검색 초기화
110
+ > q ← 종료
111
+ ```
112
+
113
+ ### 다운로드 후
114
+
115
+ 다운로드한 위젯은 `gleam.toml`의 `[tools.mendraw.widgets.*]`에 자동 추가된다.
116
+
117
+ > **참고**: 첫 다운로드 시 chrobot_extra 사이드카를 통한 Mendix 로그인이 필요할 수 있다.
118
+ > 로그인 세션은 `.marketplace-cache/session.json`에 캐시된다.
119
+ > 사이드카가 처음 실행될 때 자동으로 설정된다 (Erlang/OTP가 필요).
120
+
121
+ ---
122
+
123
+ ## Classic (Dojo) 위젯
124
+
125
+ ### Classic 위젯 직접 렌더링
126
+
127
+ ```gleam
128
+ import mendraw/classic
129
+
130
+ // 기본 렌더링
131
+ classic.render("CameraWidget.widget.CameraWidget", [
132
+ #("mfToExecute", classic.to_dynamic(mf_value)),
133
+ #("preferRearCamera", classic.to_dynamic(True)),
134
+ ])
135
+
136
+ // CSS 클래스 지정
137
+ classic.render_with_class(
138
+ "CameraWidget.widget.CameraWidget",
139
+ [#("mfToExecute", classic.to_dynamic(mf_value))],
140
+ "my-camera-wrapper",
141
+ )
142
+ ```
143
+
144
+ `widget_id`는 Classic 위젯의 정규화된 ID이다 (예: `"CameraWidget.widget.CameraWidget"`).
145
+
146
+ ---
147
+
148
+ ## JsProps 다루기
149
+
150
+ Mendix 런타임이 위젯에 전달하는 props 객체를 `JsProps` 타입으로 다룬다.
151
+
152
+ ### Prop 접근자
153
+
154
+ ```gleam
155
+ import mendraw/mendix.{type JsProps}
156
+ import gleam/option.{type Option, None, Some}
157
+
158
+ fn handle_props(props: JsProps) {
159
+ // 필수 속성 — 항상 존재한다고 가정
160
+ let name: String = mendix.get_prop_required(props, "name")
161
+
162
+ // 선택 속성 — 없으면 None
163
+ let caption: Option(String) = mendix.get_prop(props, "caption")
164
+
165
+ // 문자열 속성 — 없으면 빈 문자열 ""
166
+ let label: String = mendix.get_string_prop(props, "label")
167
+
168
+ // 속성 존재 여부 확인
169
+ let has_icon: Bool = mendix.has_prop(props, "icon")
170
+ }
171
+ ```
172
+
173
+ | 함수 | 반환 타입 | 없을 때 |
174
+ |------|----------|---------|
175
+ | `get_prop_required(props, key)` | `a` | 런타임 에러 |
176
+ | `get_prop(props, key)` | `Option(a)` | `None` |
177
+ | `get_string_prop(props, key)` | `String` | `""` |
178
+ | `has_prop(props, key)` | `Bool` | `False` |
179
+
180
+ ### ValueStatus
181
+
182
+ Mendix의 `DynamicValue`, `EditableValue` 등은 `status` 속성을 가진다.
183
+ 데이터 로딩 상태를 확인할 때 사용한다:
184
+
185
+ ```gleam
186
+ import mendraw/mendix
187
+
188
+ let value = mendix.get_prop_required(props, "textAttr")
189
+
190
+ case mendix.get_status(value) {
191
+ mendix.Available -> // 값 사용 가능
192
+ use_value(value)
193
+ mendix.Loading -> // 로딩 중
194
+ show_spinner()
195
+ mendix.Unavailable -> // 사용 불가
196
+ show_placeholder()
197
+ }
198
+ ```
199
+
200
+ ### Option 변환
201
+
202
+ JS/Gleam 경계에서 `undefined`/`null`을 안전하게 처리한다:
203
+
204
+ ```gleam
205
+ import mendraw/mendix
206
+
207
+ // JS undefined/null → Gleam None, 값이 있으면 Some(값)
208
+ let maybe_value = mendix.to_option(js_value)
209
+
210
+ // Gleam Option → JS 값 (None → undefined)
211
+ let js_value = mendix.from_option(gleam_option)
212
+ ```
213
+
214
+ ---
215
+
216
+ ## API 레퍼런스
217
+
218
+ ### mendraw/mendix
219
+
220
+ Mendix Pluggable Widget API의 핵심 타입과 props 접근자.
221
+
222
+ #### 타입
223
+
224
+ | 타입 | 설명 |
225
+ |------|------|
226
+ | `JsProps` | Mendix가 위젯에 전달하는 props 객체 (opaque) |
227
+ | `ValueStatus` | `Available \| Unavailable \| Loading` |
228
+ | `ObjectItem` | Mendix 데이터 객체 (opaque) |
229
+
230
+ #### 함수
231
+
232
+ | 함수 | 시그니처 | 설명 |
233
+ |------|----------|------|
234
+ | `get_prop` | `(JsProps, String) -> Option(a)` | 선택 속성 추출 (없으면 `None`) |
235
+ | `get_prop_required` | `(JsProps, String) -> a` | 필수 속성 추출 |
236
+ | `get_string_prop` | `(JsProps, String) -> String` | 문자열 속성 (없으면 `""`) |
237
+ | `has_prop` | `(JsProps, String) -> Bool` | 속성 존재 여부 |
238
+ | `get_status` | `(a) -> ValueStatus` | 값 객체의 로딩 상태 |
239
+ | `object_id` | `(ObjectItem) -> String` | 데이터 객체 ID |
240
+ | `to_value_status` | `(String) -> ValueStatus` | 문자열 → `ValueStatus` 변환 |
241
+ | `to_option` | `(a) -> Option(a)` | JS undefined/null → `None` |
242
+ | `from_option` | `(Option(a)) -> a` | Gleam `Option` → JS 값 (`None` → undefined) |
243
+
244
+ ### mendraw/interop
245
+
246
+ 외부 JS React 컴포넌트를 redraw Element로 변환하는 브릿지.
247
+
248
+ | 함수 | 시그니처 | 설명 |
249
+ |------|----------|------|
250
+ | `component_el` | `(JsComponent, List(Attribute), List(Element)) -> Element` | 속성 + 자식으로 렌더링 |
251
+ | `component_el_` | `(JsComponent, List(Element)) -> Element` | 자식만으로 렌더링 |
252
+ | `void_component_el` | `(JsComponent, List(Attribute)) -> Element` | self-closing 렌더링 |
253
+
254
+ #### 타입
255
+
256
+ | 타입 | 설명 |
257
+ |------|------|
258
+ | `JsComponent` | 외부 React 컴포넌트 참조 (opaque) |
259
+
260
+ ### mendraw/classic
261
+
262
+ Classic (Dojo) 위젯을 React 내부에서 렌더링.
263
+
264
+ | 함수 | 시그니처 | 설명 |
265
+ |------|----------|------|
266
+ | `render` | `(String, List(#(String, Dynamic))) -> Element` | Classic 위젯 렌더링 |
267
+ | `render_with_class` | `(String, List(#(String, Dynamic)), String) -> Element` | CSS 클래스 지정 렌더링 |
268
+ | `to_dynamic` | `(a) -> Dynamic` | 값을 `Dynamic`으로 변환 |
269
+
270
+ ### mendraw/cmd
271
+
272
+ 위젯 바인딩 생성 + TOML 위젯 관리 API.
273
+
274
+ | 함수 | 시그니처 | 설명 |
275
+ |------|----------|------|
276
+ | `file_exists` | `(String) -> Bool` | 파일 존재 여부 |
277
+ | `resolve_toml_widgets` | `() -> Nil` | gleam.toml [tools.mendraw.widgets.*] 다운로드 |
278
+ | `write_widget_toml` | `(String, String, Option(Int), Option(String)) -> Nil` | gleam.toml에 위젯 항목 쓰기 |
279
+
280
+ ### mendraw/marketplace
281
+
282
+ Mendix Marketplace 위젯 검색·다운로드 TUI. `gleam run -m mendraw/marketplace`로 실행한다.
283
+
284
+ #### 주요 기능
285
+
286
+ | 기능 | 설명 |
287
+ |------|------|
288
+ | 위젯 검색 | 이름/퍼블리셔로 실시간 필터링 |
289
+ | 백그라운드 로딩 | 전체 위젯 목록을 백그라운드에서 점진적으로 로드 |
290
+ | 버전 선택 | Content API + chrobot_extra 사이드카(XAS)로 버전별 다운로드 정보 조회 |
291
+ | 자동 TOML 기록 | 다운로드 시 gleam.toml에 위젯 항목 자동 추가 |
292
+
293
+ #### 의존성
294
+
295
+ - `etch` — 터미널 raw mode, 커서 제어, ANSI 스타일링
296
+ - `chrobot_extra` — Mendix 로그인 세션 관리, 버전 다운로드 정보 추출 (HTTP 사이드카, Erlang 타겟)
297
+ - `curl` — Content API 호출 (시스템 명령)
298
+
299
+ ---
300
+
301
+ ## glendix 프로젝트에서 사용하기
302
+
303
+ [glendix](https://github.com/) 프로젝트에서 mendraw를 의존성으로 추가하면,
304
+ 위젯 TOML 해석을 mendraw에 위임할 수 있다:
305
+
306
+ ```gleam
307
+ // glendix의 install.gleam
308
+ import mendraw/cmd as mendraw_cmd
309
+
310
+ pub fn main() {
311
+ cmd.exec(cmd.detect_install_command())
312
+ cmd.generate_bindings()
313
+ mendraw_cmd.resolve_toml_widgets()
314
+ }
315
+ ```
316
+
317
+ ---
318
+
319
+ ## 문제 해결
320
+
321
+ ### Classic 위젯이 렌더링되지 않는다
322
+
323
+ - Classic 위젯은 DOM 컨테이너를 생성하고 imperative하게 마운트한다
324
+ - `classic_ffi.mjs`가 빌드 경로에 정상적으로 생성되었는지 확인
325
+ - `widget_id`가 정확한지 확인 (예: `"CameraWidget.widget.CameraWidget"`)
326
+
327
+
328
+ 사용자가 별도로 지정할 필요 없다.
@@ -8,7 +8,9 @@ runtime = "node"
8
8
 
9
9
  [dependencies]
10
10
  gleam_stdlib = ">= 0.44.0 and < 2.0.0"
11
- glendix = ">= 3.0.2 and < 4.0.0"
11
+ glendix = ">= 4.0.3 and < 5.0.0"
12
+ mendraw = ">= 1.1.11 and < 2.0.0"
13
+ dee = ">= 1.0.0 and < 2.0.0"
12
14
  redraw = ">= 19.2.2 and < 20.0.0"
13
15
  redraw_dom = ">= 19.2.2 and < 20.0.0"
14
16
  lustre = ">= 5.6.0 and < 6.0.0"
@@ -19,12 +19,7 @@
19
19
  "prerelease": "echo skipping lint"
20
20
  },
21
21
  "devDependencies": {
22
- "@mendix/pluggable-widgets-tools": "^11.8.0",
23
- "playwright": "^1.58.2"
24
- },
25
- "dependencies": {
26
- "classnames": "^2.5.1",
27
- "big.js": "^6.0.0"
22
+ "@mendix/pluggable-widgets-tools": "^11.8.0"
28
23
  },
29
24
  "resolutions": {
30
25
  "react": "19.0.0",
@@ -2,7 +2,7 @@
2
2
  {{I18N:widget_main_2}}
3
3
 
4
4
  import components/hello_world
5
- import glendix/mendix.{type JsProps}
5
+ import mendraw/mendix.{type JsProps}
6
6
  import redraw.{type Element}
7
7
 
8
8
  {{I18N:widget_main_doc}}
@@ -2,7 +2,7 @@
2
2
  {{I18N:editor_config_2}}
3
3
 
4
4
  import glendix/editor_config.{type Properties}
5
- import glendix/mendix.{type JsProps}
5
+ import mendraw/mendix.{type JsProps}
6
6
 
7
7
  {{I18N:editor_config_doc}}
8
8
  pub fn get_properties(
@@ -2,7 +2,7 @@
2
2
  {{I18N:editor_preview_2}}
3
3
 
4
4
  import components/hello_world
5
- import glendix/mendix.{type JsProps}
5
+ import mendraw/mendix.{type JsProps}
6
6
  import redraw.{type Element}
7
7
 
8
8
  {{I18N:editor_preview_doc}}
@@ -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 glendix/interop
52
- import glendix/mendix.{type JsProps}
53
- import glendix/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
- - \`glendix/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 + \`glendix/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 glendix/interop
139
- import glendix/mendix.{type JsProps}
140
- import glendix/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
- - \`glendix/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/\` 디렉토리 + \`glendix/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 glendix/interop
226
- import glendix/mendix.{type JsProps}
227
- import glendix/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
- - \`glendix/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/\`ディレクトリ + \`glendix/widget\`を使用する
274
- `;
275
- }
@@ -1,10 +0,0 @@
1
- export default args => {
2
- const configs = args.configDefaultConfig;
3
- return configs.map(config => ({
4
- ...config,
5
- onwarn(warning, warn) {
6
- if (warning.code === "CIRCULAR_DEPENDENCY") return;
7
- config.onwarn(warning, warn);
8
- }
9
- }));
10
- };
@@ -1 +0,0 @@
1
- {{I18N:widgets_readme}}