create-mendix-widget-gleam 3.0.2 → 4.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -9
- package/package.json +1 -1
- package/src/i18n.mjs +12 -15
- package/src/index.mjs +20 -33
- package/src/templates/claude_md.mjs +9 -8
- package/src/templates/readme_md.mjs +45 -318
- package/template/docs/glendix_guide.md +178 -131
- package/template/docs/mendraw_guide.md +328 -0
- package/template/gleam.toml +3 -1
- package/template/package.json +1 -6
- package/template/src/__widget_name__.gleam +1 -1
- package/template/src/editor_config.gleam +1 -1
- package/template/src/editor_preview.gleam +1 -1
- package/src/templates/widgets_readme.mjs +0 -275
- package/template/rollup.config.mjs +0 -10
- package/template/widgets/README.md +0 -1
|
@@ -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
|
+
사용자가 별도로 지정할 필요 없다.
|
package/template/gleam.toml
CHANGED
|
@@ -8,7 +8,9 @@ runtime = "node"
|
|
|
8
8
|
|
|
9
9
|
[dependencies]
|
|
10
10
|
gleam_stdlib = ">= 0.44.0 and < 2.0.0"
|
|
11
|
-
glendix = ">=
|
|
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"
|
package/template/package.json
CHANGED
|
@@ -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",
|
|
@@ -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 +0,0 @@
|
|
|
1
|
-
{{I18N:widgets_readme}}
|