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,272 @@
|
|
|
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/mendix
|
|
52
|
+
import glendix/react.{type JsProps, type ReactElement}
|
|
53
|
+
import glendix/react/attribute
|
|
54
|
+
import glendix/widget
|
|
55
|
+
|
|
56
|
+
/// Render Switch widget - reads properties from props and passes them to the widget
|
|
57
|
+
pub fn render(props: JsProps) -> ReactElement {
|
|
58
|
+
let boolean_attribute = mendix.get_prop_required(props, "booleanAttribute")
|
|
59
|
+
let action = mendix.get_prop_required(props, "action")
|
|
60
|
+
|
|
61
|
+
let comp = widget.component("Switch")
|
|
62
|
+
react.component_el(
|
|
63
|
+
comp,
|
|
64
|
+
[
|
|
65
|
+
attribute.attribute("booleanAttribute", boolean_attribute),
|
|
66
|
+
attribute.attribute("action", action),
|
|
67
|
+
],
|
|
68
|
+
[],
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
\`\`\`
|
|
72
|
+
|
|
73
|
+
- Required/optional properties are distinguished automatically
|
|
74
|
+
- If optional properties exist, \`optional_attr\` helper and \`gleam/option\` import are added automatically
|
|
75
|
+
- Gleam reserved words (e.g. \`type\`) are automatically suffixed with \`_\`
|
|
76
|
+
- Generated files can be freely modified as needed
|
|
77
|
+
|
|
78
|
+
### 4. Use from Gleam
|
|
79
|
+
|
|
80
|
+
\`\`\`gleam
|
|
81
|
+
import widgets/switch
|
|
82
|
+
|
|
83
|
+
// Inside a component
|
|
84
|
+
switch.render(props)
|
|
85
|
+
\`\`\`
|
|
86
|
+
|
|
87
|
+
## How it works
|
|
88
|
+
|
|
89
|
+
- \`glendix/widget\` module's \`widget.component("Name")\` imports \`.mpk\` widgets as React components
|
|
90
|
+
- Props are passed via the generic \`attribute.attribute(key, value)\` function
|
|
91
|
+
- Widget names use the \`<name>\` value from the \`.mpk\`'s internal XML, and property keys use the original keys from the \`.mpk\` XML
|
|
92
|
+
- Unlike the \`binding\` module, 1 mpk = 1 component, so \`widget.component("Name")\` imports it in one call
|
|
93
|
+
|
|
94
|
+
## Notes
|
|
95
|
+
|
|
96
|
+
- After adding/removing \`.mpk\` files, you must run \`gleam run -m glendix/install\` again
|
|
97
|
+
- \`widget_ffi.mjs\` is auto-generated — do not edit it directly
|
|
98
|
+
- Do not write \`.mjs\` FFI files for \`.mpk\` widgets manually — use the \`widgets/\` directory + \`glendix/widget\`
|
|
99
|
+
`;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function generateKo() {
|
|
103
|
+
return `# widgets/
|
|
104
|
+
|
|
105
|
+
Mendix 위젯 바인딩 디렉토리. \`.mpk\` 파일(Mendix 위젯 빌드 결과물)을 이 디렉토리에 배치하면, Gleam 코드에서 기존 Mendix 위젯을 React 컴포넌트로 렌더링할 수 있다.
|
|
106
|
+
|
|
107
|
+
## 사용법
|
|
108
|
+
|
|
109
|
+
### 1. \`.mpk\` 파일 배치
|
|
110
|
+
|
|
111
|
+
빌드된 Mendix 위젯의 \`.mpk\` 파일을 이 디렉토리에 복사한다:
|
|
112
|
+
|
|
113
|
+
\`\`\`
|
|
114
|
+
widgets/
|
|
115
|
+
├── Switch.mpk
|
|
116
|
+
├── Badge.mpk
|
|
117
|
+
└── README.md
|
|
118
|
+
\`\`\`
|
|
119
|
+
|
|
120
|
+
### 2. 바인딩 생성
|
|
121
|
+
|
|
122
|
+
\`\`\`bash
|
|
123
|
+
gleam run -m glendix/install
|
|
124
|
+
\`\`\`
|
|
125
|
+
|
|
126
|
+
실행 시 다음이 자동 처리된다:
|
|
127
|
+
|
|
128
|
+
- \`.mpk\` 내부의 \`.mjs\`와 \`.css\`가 추출되고, \`widget_ffi.mjs\`가 생성된다
|
|
129
|
+
- \`.mpk\` XML의 \`<property>\` 정의를 파싱하여 \`src/widgets/\`에 바인딩 \`.gleam\` 파일이 자동 생성된다 (이미 존재하면 건너뜀)
|
|
130
|
+
|
|
131
|
+
### 3. 자동 생성된 바인딩 확인
|
|
132
|
+
|
|
133
|
+
예를 들어 \`Switch.mpk\`를 배치하면 \`src/widgets/switch.gleam\`이 생성된다:
|
|
134
|
+
|
|
135
|
+
\`\`\`gleam
|
|
136
|
+
// src/widgets/switch.gleam (자동 생성)
|
|
137
|
+
import glendix/mendix
|
|
138
|
+
import glendix/react.{type JsProps, type ReactElement}
|
|
139
|
+
import glendix/react/attribute
|
|
140
|
+
import glendix/widget
|
|
141
|
+
|
|
142
|
+
/// Switch 위젯 렌더링 - props에서 속성을 읽어 위젯에 전달
|
|
143
|
+
pub fn render(props: JsProps) -> ReactElement {
|
|
144
|
+
let boolean_attribute = mendix.get_prop_required(props, "booleanAttribute")
|
|
145
|
+
let action = mendix.get_prop_required(props, "action")
|
|
146
|
+
|
|
147
|
+
let comp = widget.component("Switch")
|
|
148
|
+
react.component_el(
|
|
149
|
+
comp,
|
|
150
|
+
[
|
|
151
|
+
attribute.attribute("booleanAttribute", boolean_attribute),
|
|
152
|
+
attribute.attribute("action", action),
|
|
153
|
+
],
|
|
154
|
+
[],
|
|
155
|
+
)
|
|
156
|
+
}
|
|
157
|
+
\`\`\`
|
|
158
|
+
|
|
159
|
+
- required/optional 속성이 자동 구분된다
|
|
160
|
+
- optional 속성이 있으면 \`optional_attr\` 헬퍼와 \`gleam/option\` import가 자동 추가된다
|
|
161
|
+
- Gleam 예약어(\`type\` 등)는 접미사 \`_\`로 자동 회피된다
|
|
162
|
+
- 생성된 파일은 필요에 따라 자유롭게 수정 가능하다
|
|
163
|
+
|
|
164
|
+
### 4. Gleam에서 사용
|
|
165
|
+
|
|
166
|
+
\`\`\`gleam
|
|
167
|
+
import widgets/switch
|
|
168
|
+
|
|
169
|
+
// 컴포넌트 내부에서
|
|
170
|
+
switch.render(props)
|
|
171
|
+
\`\`\`
|
|
172
|
+
|
|
173
|
+
## 동작 원리
|
|
174
|
+
|
|
175
|
+
- \`glendix/widget\` 모듈의 \`widget.component("Name")\`으로 \`.mpk\` 위젯을 React 컴포넌트로 가져온다
|
|
176
|
+
- Props는 \`attribute.attribute(key, value)\` 범용 함수로 전달한다
|
|
177
|
+
- 위젯 이름은 \`.mpk\` 내부 XML의 \`<name>\` 값을, property key는 XML의 원본 key를 그대로 사용한다
|
|
178
|
+
- \`binding\` 모듈과 달리 1 mpk = 1 컴포넌트이므로 \`widget.component("Name")\` 한 번에 가져온다
|
|
179
|
+
|
|
180
|
+
## 주의사항
|
|
181
|
+
|
|
182
|
+
- \`.mpk\` 파일을 추가/제거한 후에는 반드시 \`gleam run -m glendix/install\`을 다시 실행해야 한다
|
|
183
|
+
- \`widget_ffi.mjs\`는 자동 생성 파일이므로 직접 수정하지 않는다
|
|
184
|
+
- \`.mpk\` 위젯용 \`.mjs\` FFI 파일을 직접 작성하지 않는다 — \`widgets/\` 디렉토리 + \`glendix/widget\`을 사용한다
|
|
185
|
+
`;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function generateJa() {
|
|
189
|
+
return `# widgets/
|
|
190
|
+
|
|
191
|
+
Mendixウィジェットバインディングディレクトリ。\`.mpk\`ファイル(Mendixウィジェットビルド成果物)をこのディレクトリに配置すると、Gleamコードから既存のMendixウィジェットをReactコンポーネントとしてレンダリングできる。
|
|
192
|
+
|
|
193
|
+
## 使い方
|
|
194
|
+
|
|
195
|
+
### 1. \`.mpk\`ファイルの配置
|
|
196
|
+
|
|
197
|
+
ビルド済みMendixウィジェットの\`.mpk\`ファイルをこのディレクトリにコピーする:
|
|
198
|
+
|
|
199
|
+
\`\`\`
|
|
200
|
+
widgets/
|
|
201
|
+
├── Switch.mpk
|
|
202
|
+
├── Badge.mpk
|
|
203
|
+
└── README.md
|
|
204
|
+
\`\`\`
|
|
205
|
+
|
|
206
|
+
### 2. バインディングの生成
|
|
207
|
+
|
|
208
|
+
\`\`\`bash
|
|
209
|
+
gleam run -m glendix/install
|
|
210
|
+
\`\`\`
|
|
211
|
+
|
|
212
|
+
実行時に以下が自動処理される:
|
|
213
|
+
|
|
214
|
+
- \`.mpk\`内部の\`.mjs\`と\`.css\`が抽出され、\`widget_ffi.mjs\`が生成される
|
|
215
|
+
- \`.mpk\` XMLの\`<property>\`定義をパースし、\`src/widgets/\`にバインディング\`.gleam\`ファイルが自動生成される(既存ファイルはスキップ)
|
|
216
|
+
|
|
217
|
+
### 3. 自動生成されたバインディングの確認
|
|
218
|
+
|
|
219
|
+
例えば\`Switch.mpk\`を配置すると\`src/widgets/switch.gleam\`が生成される:
|
|
220
|
+
|
|
221
|
+
\`\`\`gleam
|
|
222
|
+
// src/widgets/switch.gleam(自動生成)
|
|
223
|
+
import glendix/mendix
|
|
224
|
+
import glendix/react.{type JsProps, type ReactElement}
|
|
225
|
+
import glendix/react/attribute
|
|
226
|
+
import glendix/widget
|
|
227
|
+
|
|
228
|
+
/// Switchウィジェットのレンダリング - propsからプロパティを読み取りウィジェットに渡す
|
|
229
|
+
pub fn render(props: JsProps) -> ReactElement {
|
|
230
|
+
let boolean_attribute = mendix.get_prop_required(props, "booleanAttribute")
|
|
231
|
+
let action = mendix.get_prop_required(props, "action")
|
|
232
|
+
|
|
233
|
+
let comp = widget.component("Switch")
|
|
234
|
+
react.component_el(
|
|
235
|
+
comp,
|
|
236
|
+
[
|
|
237
|
+
attribute.attribute("booleanAttribute", boolean_attribute),
|
|
238
|
+
attribute.attribute("action", action),
|
|
239
|
+
],
|
|
240
|
+
[],
|
|
241
|
+
)
|
|
242
|
+
}
|
|
243
|
+
\`\`\`
|
|
244
|
+
|
|
245
|
+
- required/optionalプロパティは自動的に区別される
|
|
246
|
+
- optionalプロパティがある場合、\`optional_attr\`ヘルパーと\`gleam/option\` importが自動追加される
|
|
247
|
+
- Gleam予約語(\`type\`等)はサフィックス\`_\`で自動回避される
|
|
248
|
+
- 生成されたファイルは必要に応じて自由に編集できる
|
|
249
|
+
|
|
250
|
+
### 4. Gleamから使用
|
|
251
|
+
|
|
252
|
+
\`\`\`gleam
|
|
253
|
+
import widgets/switch
|
|
254
|
+
|
|
255
|
+
// コンポーネント内で
|
|
256
|
+
switch.render(props)
|
|
257
|
+
\`\`\`
|
|
258
|
+
|
|
259
|
+
## 仕組み
|
|
260
|
+
|
|
261
|
+
- \`glendix/widget\`モジュールの\`widget.component("Name")\`で\`.mpk\`ウィジェットをReactコンポーネントとしてインポートする
|
|
262
|
+
- Propsは\`attribute.attribute(key, value)\`汎用関数で渡す
|
|
263
|
+
- ウィジェット名は\`.mpk\`内部XMLの\`<name>\`値を、プロパティキーはXMLの元のキーをそのまま使用する
|
|
264
|
+
- \`binding\`モジュールと異なり1 mpk = 1コンポーネントなので、\`widget.component("Name")\`で一度にインポートする
|
|
265
|
+
|
|
266
|
+
## 注意事項
|
|
267
|
+
|
|
268
|
+
- \`.mpk\`ファイルを追加/削除した後は必ず\`gleam run -m glendix/install\`を再実行すること
|
|
269
|
+
- \`widget_ffi.mjs\`は自動生成ファイルなので直接編集しない
|
|
270
|
+
- \`.mpk\`ウィジェット用の\`.mjs\` FFIファイルを直接記述しない — \`widgets/\`ディレクトリ + \`glendix/widget\`を使用する
|
|
271
|
+
`;
|
|
272
|
+
}
|
package/template/_gitignore
CHANGED
|
@@ -1,58 +1,58 @@
|
|
|
1
|
-
|
|
2
|
-
node_modules/
|
|
3
|
-
.yarn/
|
|
4
|
-
.pnp.*
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
package-lock.json
|
|
8
|
-
yarn.lock
|
|
9
|
-
pnpm-lock.yaml
|
|
10
|
-
bun.lockb
|
|
11
|
-
bun.lock
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
.npmrc
|
|
15
|
-
.yarnrc
|
|
16
|
-
.yarnrc.yml
|
|
17
|
-
.pnpmfile.cjs
|
|
18
|
-
.npmignore
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
build/
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
dist/
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
.env
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
*.log
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
.DS_Store
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
.idea/
|
|
37
|
-
.vscode/
|
|
38
|
-
*.launch
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
tests/testProject/
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
coverage/
|
|
45
|
-
**/e2e/diffs/
|
|
46
|
-
**/screenshot/
|
|
47
|
-
**/screenshot-results/
|
|
48
|
-
**/artifacts/
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
src/*.js
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
.claude/
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
.marketplace-cache/
|
|
58
|
-
|
|
1
|
+
{{I18N:gitignore_deps}}
|
|
2
|
+
node_modules/
|
|
3
|
+
.yarn/
|
|
4
|
+
.pnp.*
|
|
5
|
+
|
|
6
|
+
{{I18N:gitignore_lockfiles}}
|
|
7
|
+
package-lock.json
|
|
8
|
+
yarn.lock
|
|
9
|
+
pnpm-lock.yaml
|
|
10
|
+
bun.lockb
|
|
11
|
+
bun.lock
|
|
12
|
+
|
|
13
|
+
{{I18N:gitignore_pm_cache}}
|
|
14
|
+
.npmrc
|
|
15
|
+
.yarnrc
|
|
16
|
+
.yarnrc.yml
|
|
17
|
+
.pnpmfile.cjs
|
|
18
|
+
.npmignore
|
|
19
|
+
|
|
20
|
+
{{I18N:gitignore_gleam_build}}
|
|
21
|
+
build/
|
|
22
|
+
|
|
23
|
+
{{I18N:gitignore_mendix_build}}
|
|
24
|
+
dist/
|
|
25
|
+
|
|
26
|
+
{{I18N:gitignore_env}}
|
|
27
|
+
.env
|
|
28
|
+
|
|
29
|
+
{{I18N:gitignore_logs}}
|
|
30
|
+
*.log
|
|
31
|
+
|
|
32
|
+
{{I18N:gitignore_os}}
|
|
33
|
+
.DS_Store
|
|
34
|
+
|
|
35
|
+
{{I18N:gitignore_ide}}
|
|
36
|
+
.idea/
|
|
37
|
+
.vscode/
|
|
38
|
+
*.launch
|
|
39
|
+
|
|
40
|
+
{{I18N:gitignore_test_project}}
|
|
41
|
+
tests/testProject/
|
|
42
|
+
|
|
43
|
+
{{I18N:gitignore_test_artifacts}}
|
|
44
|
+
coverage/
|
|
45
|
+
**/e2e/diffs/
|
|
46
|
+
**/screenshot/
|
|
47
|
+
**/screenshot-results/
|
|
48
|
+
**/artifacts/
|
|
49
|
+
|
|
50
|
+
{{I18N:gitignore_bridge}}
|
|
51
|
+
src/*.js
|
|
52
|
+
|
|
53
|
+
{{I18N:gitignore_ai}}
|
|
54
|
+
.claude/
|
|
55
|
+
|
|
56
|
+
{{I18N:gitignore_marketplace}}
|
|
57
|
+
.marketplace-cache/
|
|
58
|
+
|
package/template/gleam.toml
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
name = "{{SNAKE_CASE}}"
|
|
2
|
-
version = "1.0.0"
|
|
3
|
-
target = "javascript"
|
|
4
|
-
|
|
5
|
-
[javascript]
|
|
6
|
-
typescript_declarations = false
|
|
7
|
-
runtime = "node"
|
|
8
|
-
|
|
9
|
-
[dependencies]
|
|
10
|
-
gleam_stdlib = ">= 0.44.0 and < 2.0.0"
|
|
11
|
-
glendix = ">= 2.0.
|
|
1
|
+
name = "{{SNAKE_CASE}}"
|
|
2
|
+
version = "1.0.0"
|
|
3
|
+
target = "javascript"
|
|
4
|
+
|
|
5
|
+
[javascript]
|
|
6
|
+
typescript_declarations = false
|
|
7
|
+
runtime = "node"
|
|
8
|
+
|
|
9
|
+
[dependencies]
|
|
10
|
+
gleam_stdlib = ">= 0.44.0 and < 2.0.0"
|
|
11
|
+
glendix = ">= 2.0.13 and < 3.0.0"
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import components/hello_world
|
|
5
|
-
import glendix/mendix
|
|
6
|
-
import glendix/react.{type JsProps, type ReactElement}
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
pub fn widget(props: JsProps) -> ReactElement {
|
|
10
|
-
let sample_text = mendix.get_string_prop(props, "sampleText")
|
|
11
|
-
hello_world.render(sample_text)
|
|
12
|
-
}
|
|
1
|
+
{{I18N:widget_main_1}}
|
|
2
|
+
{{I18N:widget_main_2}}
|
|
3
|
+
|
|
4
|
+
import components/hello_world
|
|
5
|
+
import glendix/mendix
|
|
6
|
+
import glendix/react.{type JsProps, type ReactElement}
|
|
7
|
+
|
|
8
|
+
{{I18N:widget_main_doc}}
|
|
9
|
+
pub fn widget(props: JsProps) -> ReactElement {
|
|
10
|
+
let sample_text = mendix.get_string_prop(props, "sampleText")
|
|
11
|
+
hello_world.render(sample_text)
|
|
12
|
+
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import glendix/react.{type ReactElement}
|
|
5
|
-
import glendix/react/attribute
|
|
6
|
-
import glendix/react/html
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
pub fn render(sample_text: String) -> ReactElement {
|
|
10
|
-
html.div([attribute.class("widget-hello-world")], [
|
|
11
|
-
react.text("Hello " <> sample_text),
|
|
12
|
-
])
|
|
13
|
-
}
|
|
1
|
+
{{I18N:hello_world_1}}
|
|
2
|
+
{{I18N:hello_world_2}}
|
|
3
|
+
|
|
4
|
+
import glendix/react.{type ReactElement}
|
|
5
|
+
import glendix/react/attribute
|
|
6
|
+
import glendix/react/html
|
|
7
|
+
|
|
8
|
+
{{I18N:hello_world_doc}}
|
|
9
|
+
pub fn render(sample_text: String) -> ReactElement {
|
|
10
|
+
html.div([attribute.class("widget-hello-world")], [
|
|
11
|
+
react.text("Hello " <> sample_text),
|
|
12
|
+
])
|
|
13
|
+
}
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
pub type Values
|
|
6
|
-
|
|
7
|
-
pub type Properties
|
|
8
|
-
|
|
9
|
-
pub type Target
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
pub fn get_properties(
|
|
13
|
-
_values: Values,
|
|
14
|
-
default_properties: Properties,
|
|
15
|
-
_target: Target,
|
|
16
|
-
) -> Properties {
|
|
17
|
-
default_properties
|
|
18
|
-
}
|
|
1
|
+
{{I18N:editor_config_1}}
|
|
2
|
+
{{I18N:editor_config_2}}
|
|
3
|
+
|
|
4
|
+
{{I18N:editor_config_3}}
|
|
5
|
+
pub type Values
|
|
6
|
+
|
|
7
|
+
pub type Properties
|
|
8
|
+
|
|
9
|
+
pub type Target
|
|
10
|
+
|
|
11
|
+
{{I18N:editor_config_doc}}
|
|
12
|
+
pub fn get_properties(
|
|
13
|
+
_values: Values,
|
|
14
|
+
default_properties: Properties,
|
|
15
|
+
_target: Target,
|
|
16
|
+
) -> Properties {
|
|
17
|
+
default_properties
|
|
18
|
+
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import components/hello_world
|
|
5
|
-
import glendix/mendix
|
|
6
|
-
import glendix/react.{type JsProps, type ReactElement}
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
pub fn preview(props: JsProps) -> ReactElement {
|
|
10
|
-
let sample_text = mendix.get_string_prop(props, "sampleText")
|
|
11
|
-
hello_world.render(sample_text)
|
|
12
|
-
}
|
|
1
|
+
{{I18N:editor_preview_1}}
|
|
2
|
+
{{I18N:editor_preview_2}}
|
|
3
|
+
|
|
4
|
+
import components/hello_world
|
|
5
|
+
import glendix/mendix
|
|
6
|
+
import glendix/react.{type JsProps, type ReactElement}
|
|
7
|
+
|
|
8
|
+
{{I18N:editor_preview_doc}}
|
|
9
|
+
pub fn preview(props: JsProps) -> ReactElement {
|
|
10
|
+
let sample_text = mendix.get_string_prop(props, "sampleText")
|
|
11
|
+
hello_world.render(sample_text)
|
|
12
|
+
}
|
|
@@ -1,82 +1 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
Mendix 위젯 바인딩 디렉토리. `.mpk` 파일(Mendix 위젯 빌드 결과물)을 이 디렉토리에 배치하면, Gleam 코드에서 기존 Mendix 위젯을 React 컴포넌트로 렌더링할 수 있다.
|
|
4
|
-
|
|
5
|
-
## 사용법
|
|
6
|
-
|
|
7
|
-
### 1. `.mpk` 파일 배치
|
|
8
|
-
|
|
9
|
-
빌드된 Mendix 위젯의 `.mpk` 파일을 이 디렉토리에 복사한다:
|
|
10
|
-
|
|
11
|
-
```
|
|
12
|
-
widgets/
|
|
13
|
-
├── Switch.mpk
|
|
14
|
-
├── Badge.mpk
|
|
15
|
-
└── README.md
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
### 2. 바인딩 생성
|
|
19
|
-
|
|
20
|
-
```bash
|
|
21
|
-
gleam run -m glendix/install
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
실행 시 다음이 자동 처리된다:
|
|
25
|
-
|
|
26
|
-
- `.mpk` 내부의 `.mjs`와 `.css`가 추출되고, `widget_ffi.mjs`가 생성된다
|
|
27
|
-
- `.mpk` XML의 `<property>` 정의를 파싱하여 `src/widgets/`에 바인딩 `.gleam` 파일이 자동 생성된다 (이미 존재하면 건너뜀)
|
|
28
|
-
|
|
29
|
-
### 3. 자동 생성된 바인딩 확인
|
|
30
|
-
|
|
31
|
-
예를 들어 `Switch.mpk`를 배치하면 `src/widgets/switch.gleam`이 생성된다:
|
|
32
|
-
|
|
33
|
-
```gleam
|
|
34
|
-
// src/widgets/switch.gleam (자동 생성)
|
|
35
|
-
import glendix/mendix
|
|
36
|
-
import glendix/react.{type JsProps, type ReactElement}
|
|
37
|
-
import glendix/react/attribute
|
|
38
|
-
import glendix/widget
|
|
39
|
-
|
|
40
|
-
/// Switch 위젯 렌더링 - props에서 속성을 읽어 위젯에 전달
|
|
41
|
-
pub fn render(props: JsProps) -> ReactElement {
|
|
42
|
-
let boolean_attribute = mendix.get_prop_required(props, "booleanAttribute")
|
|
43
|
-
let action = mendix.get_prop_required(props, "action")
|
|
44
|
-
|
|
45
|
-
let comp = widget.component("Switch")
|
|
46
|
-
react.component_el(
|
|
47
|
-
comp,
|
|
48
|
-
[
|
|
49
|
-
attribute.attribute("booleanAttribute", boolean_attribute),
|
|
50
|
-
attribute.attribute("action", action),
|
|
51
|
-
],
|
|
52
|
-
[],
|
|
53
|
-
)
|
|
54
|
-
}
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
- required/optional 속성이 자동 구분된다
|
|
58
|
-
- optional 속성이 있으면 `optional_attr` 헬퍼와 `gleam/option` import가 자동 추가된다
|
|
59
|
-
- Gleam 예약어(`type` 등)는 접미사 `_`로 자동 회피된다
|
|
60
|
-
- 생성된 파일은 필요에 따라 자유롭게 수정 가능하다
|
|
61
|
-
|
|
62
|
-
### 4. Gleam에서 사용
|
|
63
|
-
|
|
64
|
-
```gleam
|
|
65
|
-
import widgets/switch
|
|
66
|
-
|
|
67
|
-
// 위젯 컴포넌트 내부에서
|
|
68
|
-
switch.render(props)
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
## 동작 원리
|
|
72
|
-
|
|
73
|
-
- `glendix/widget` 모듈의 `widget.component("Name")`으로 `.mpk` 위젯을 React 컴포넌트로 가져온다
|
|
74
|
-
- Props는 `attribute.attribute(key, value)` 범용 함수로 전달한다
|
|
75
|
-
- 위젯 이름은 `.mpk` 내부 XML의 `<name>` 값을, property key는 XML의 원본 key를 그대로 사용한다
|
|
76
|
-
- `binding` 모듈과 달리 1 mpk = 1 컴포넌트이므로 `widget.component("Name")` 한 번에 가져온다
|
|
77
|
-
|
|
78
|
-
## 주의사항
|
|
79
|
-
|
|
80
|
-
- `.mpk` 파일을 추가/제거한 후에는 반드시 `gleam run -m glendix/install`을 다시 실행해야 한다
|
|
81
|
-
- `widget_ffi.mjs`는 자동 생성 파일이므로 직접 수정하지 않는다
|
|
82
|
-
- `.mpk` 위젯용 `.mjs` FFI 파일을 직접 작성하지 않는다 — `widgets/` 디렉토리 + `glendix/widget`을 사용한다
|
|
1
|
+
{{I18N:widgets_readme}}
|