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.
- package/README.md +1 -1
- package/package.json +1 -1
- package/src/i18n.mjs +334 -0
- package/src/index.mjs +211 -652
- package/src/prompts.mjs +142 -116
- package/src/scaffold.mjs +97 -89
- package/src/templates/claude_md.mjs +105 -0
- package/src/templates/readme_md.mjs +785 -0
- package/src/templates/widgets_readme.mjs +272 -0
- package/template/_gitignore +58 -58
- package/template/gleam.toml +11 -11
- package/template/src/__widget_name__.gleam +12 -12
- package/template/src/components/hello_world.gleam +13 -13
- package/template/src/editor_config.gleam +18 -18
- package/template/src/editor_preview.gleam +12 -12
- package/template/widgets/README.md +1 -82
|
@@ -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
|
+
}
|