create-mendix-widget-gleam 2.0.13 → 2.0.14

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
@@ -30,11 +30,11 @@ my-widget/
30
30
  widgets/ # .mpk 위젯 파일 (glendix/widget로 바인딩)
31
31
  bindings.json # 외부 React 컴포넌트 바인딩 설정
32
32
  package.json # npm 의존성 (React, 외부 라이브러리 등)
33
- gleam.toml # Gleam 프로젝트 설정 (glendix >= 2.0.13 의존성 포함)
33
+ gleam.toml # Gleam 프로젝트 설정 (glendix >= 2.0.14 의존성 포함)
34
34
  CLAUDE.md # AI 어시스턴트용 프로젝트 컨텍스트
35
35
  ```
36
36
 
37
- React/Mendix FFI 바인딩은 프로젝트에 포함되지 않으며, [glendix](https://hexdocs.pm/glendix/) Hex 패키지로 제공된다.
37
+ React/Mendix FFI 및 JS Interop 바인딩은 프로젝트에 포함되지 않으며, [glendix](https://hexdocs.pm/glendix/) Hex 패키지로 제공된다.
38
38
 
39
39
  ## 생성 후 시작하기
40
40
 
@@ -52,6 +52,7 @@ gleam run -m glendix/marketplace # Marketplace 위젯 검색/다운로드
52
52
 
53
53
  - **React** — `react`, `react/attribute`, `react/hook`, `react/event`, `react/html`, `react/svg`, `react/svg_attribute`, `binding`, `widget`
54
54
  - **Mendix** — `mendix`, `mendix/editable_value`, `mendix/action`, `mendix/list_value`, `mendix/selection`, `mendix/reference`, `mendix/reference_set`, `mendix/date`, `mendix/big`, `mendix/filter` 등
55
+ - **JS Interop** — `js/array`, `js/object`, `js/json`, `js/promise`, `js/dom`, `js/timer`
55
56
 
56
57
  ## 라이선스
57
58
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-mendix-widget-gleam",
3
- "version": "2.0.13",
3
+ "version": "2.0.14",
4
4
  "description": "Scaffold a Mendix Pluggable Widget powered by Gleam",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -125,7 +125,7 @@ bindings.json # External React component binding configurat
125
125
  package.json # npm dependencies (React, external libraries, etc.)
126
126
  \`\`\`
127
127
 
128
- React/Mendix FFI bindings are provided by the [glendix](https://hexdocs.pm/glendix/) Hex package.
128
+ React/Mendix FFI and JS Interop bindings are provided by the [glendix](https://hexdocs.pm/glendix/) Hex package.
129
129
 
130
130
  ## Using External React Components
131
131
 
@@ -266,7 +266,7 @@ Widget names use the \`<name>\` value from the \`.mpk\`'s internal XML, and prop
266
266
  ## Tech Stack
267
267
 
268
268
  - **Gleam** → JavaScript compilation
269
- - **[glendix](https://hexdocs.pm/glendix/)** — React + Mendix API Gleam bindings
269
+ - **[glendix](https://hexdocs.pm/glendix/)** — React + Mendix API + JS Interop Gleam bindings
270
270
  - **Mendix Pluggable Widget** (React 19)
271
271
  - **${pm}** — Package manager
272
272
 
@@ -379,7 +379,7 @@ bindings.json # 외부 React 컴포넌트 바인딩 설정
379
379
  package.json # npm 의존성 (React, 외부 라이브러리 등)
380
380
  \`\`\`
381
381
 
382
- React/Mendix FFI 바인딩은 [glendix](https://hexdocs.pm/glendix/) Hex 패키지로 제공됩니다.
382
+ React/Mendix FFI 및 JS Interop 바인딩은 [glendix](https://hexdocs.pm/glendix/) Hex 패키지로 제공됩니다.
383
383
 
384
384
  ## 외부 React 컴포넌트 사용
385
385
 
@@ -520,7 +520,7 @@ switch.render(props)
520
520
  ## 기술 스택
521
521
 
522
522
  - **Gleam** → JavaScript 컴파일
523
- - **[glendix](https://hexdocs.pm/glendix/)** — React + Mendix API Gleam 바인딩
523
+ - **[glendix](https://hexdocs.pm/glendix/)** — React + Mendix API + JS Interop Gleam 바인딩
524
524
  - **Mendix Pluggable Widget** (React 19)
525
525
  - **${pm}** — 패키지 매니저
526
526
 
@@ -633,7 +633,7 @@ bindings.json # 外部Reactコンポーネントバイン
633
633
  package.json # npm依存関係(React、外部ライブラリなど)
634
634
  \`\`\`
635
635
 
636
- React/Mendix FFIバインディングは[glendix](https://hexdocs.pm/glendix/) Hexパッケージとして提供される。
636
+ React/Mendix FFIおよびJS Interopバインディングは[glendix](https://hexdocs.pm/glendix/) Hexパッケージとして提供される。
637
637
 
638
638
  ## 外部Reactコンポーネントの使用
639
639
 
@@ -774,7 +774,7 @@ switch.render(props)
774
774
  ## 技術スタック
775
775
 
776
776
  - **Gleam** → JavaScriptコンパイル
777
- - **[glendix](https://hexdocs.pm/glendix/)** — React + Mendix API Gleamバインディング
777
+ - **[glendix](https://hexdocs.pm/glendix/)** — React + Mendix API + JS Interop Gleamバインディング
778
778
  - **Mendix Pluggable Widget**(React 19)
779
779
  - **${pm}** — パッケージマネージャー
780
780
 
@@ -2179,7 +2179,210 @@ camera_widget.render(props)
2179
2179
 
2180
2180
  ---
2181
2181
 
2182
- ## 6. 트러블슈팅
2182
+ ## 6. JS Interop — 외부 JS 라이브러리 연동
2183
+
2184
+ `glendix/js/` 모듈은 외부 JavaScript 라이브러리(SpreadJS, Chart.js 등)와 직접 상호작용할 때 사용하는 저수준 interop API를 제공합니다. React 컴포넌트 바인딩(`glendix/binding`)으로 해결되지 않는 경우의 escape hatch입니다.
2185
+
2186
+ > 모든 JS 값은 `Dynamic` 타입으로 표현됩니다. 타입 안전성보다 유연성을 우선하는 설계이므로, 가능하면 `glendix/binding`이나 전용 opaque 래퍼를 먼저 고려하세요.
2187
+
2188
+ ### 6.1 배열 변환 — `js/array`
2189
+
2190
+ Gleam List ↔ JS Array 변환 유틸리티입니다.
2191
+
2192
+ ```gleam
2193
+ import gleam/dynamic.{type Dynamic}
2194
+ import glendix/js/array
2195
+
2196
+ // Gleam List → JS Array (Dynamic)
2197
+ let js_arr = array.from_list([1, 2, 3])
2198
+
2199
+ // JS Array → Gleam List
2200
+ let gleam_list: List(Int) = array.to_list(js_arr)
2201
+ ```
2202
+
2203
+ ### 6.2 객체 조작 — `js/object`
2204
+
2205
+ JS 객체 생성, 속성 접근, 메서드 호출을 제공합니다.
2206
+
2207
+ ```gleam
2208
+ import gleam/dynamic
2209
+ import glendix/js/object
2210
+
2211
+ // 객체 생성
2212
+ let config = object.object([
2213
+ #("width", dynamic.from(800)),
2214
+ #("height", dynamic.from(600)),
2215
+ #("editable", dynamic.from(True)),
2216
+ ])
2217
+
2218
+ // 빈 객체
2219
+ let obj = object.empty()
2220
+
2221
+ // 속성 읽기/쓰기 (set은 mutation — 원본 반환)
2222
+ let width = object.get(config, "width")
2223
+ let config = object.set(config, "theme", dynamic.from("dark"))
2224
+
2225
+ // 속성 삭제/존재 확인
2226
+ let config = object.delete(config, "editable")
2227
+ let has_theme = object.has(config, "theme") // True
2228
+
2229
+ // 메서드 호출
2230
+ let result = object.call_method(spreadsheet, "getCell", [
2231
+ dynamic.from(0),
2232
+ dynamic.from(0),
2233
+ ])
2234
+ let value = object.call_method_0(cell, "getValue")
2235
+
2236
+ // new 연산자로 인스턴스 생성
2237
+ let instance = object.new_instance(constructor, [
2238
+ dynamic.from("arg1"),
2239
+ ])
2240
+ ```
2241
+
2242
+ ### 6.3 JSON — `js/json`
2243
+
2244
+ JSON 직렬화/역직렬화입니다.
2245
+
2246
+ ```gleam
2247
+ import gleam/dynamic
2248
+ import glendix/js/json
2249
+
2250
+ // 직렬화
2251
+ let json_str = json.stringify(dynamic.from(config))
2252
+
2253
+ // 역직렬화 (Result 반환)
2254
+ case json.parse("{\"key\": \"value\"}") {
2255
+ Ok(data) -> object.get(data, "key")
2256
+ Error(msg) -> // 파싱 에러 메시지
2257
+ }
2258
+ ```
2259
+
2260
+ ### 6.4 Promise — `js/promise`
2261
+
2262
+ Promise 체이닝, 에러 처리, 병렬 실행을 제공합니다. `glendix/react`의 `Promise(a)` 타입을 사용합니다.
2263
+
2264
+ ```gleam
2265
+ import gleam/dynamic.{type Dynamic}
2266
+ import glendix/js/promise
2267
+ import glendix/react.{type Promise}
2268
+
2269
+ // 즉시 이행/거부
2270
+ let p = promise.resolve(42)
2271
+ let err = promise.reject("something went wrong")
2272
+
2273
+ // 체이닝 (flatMap)
2274
+ promise.then_(fetch_data(), fn(data) {
2275
+ promise.resolve(transform(data))
2276
+ })
2277
+
2278
+ // 값 변환 (map)
2279
+ promise.map(fetch_data(), fn(data) {
2280
+ object.get(data, "name")
2281
+ })
2282
+
2283
+ // 에러 처리
2284
+ promise.catch_(risky_operation(), fn(error: Dynamic) {
2285
+ promise.resolve(fallback_value)
2286
+ })
2287
+
2288
+ // 병렬 실행 (모든 Promise 대기)
2289
+ promise.all([fetch_users(), fetch_roles()])
2290
+ |> promise.map(fn(results) {
2291
+ // results: List(a)
2292
+ })
2293
+
2294
+ // 가장 빠른 결과
2295
+ promise.race([fetch_from_primary(), fetch_from_backup()])
2296
+
2297
+ // fire-and-forget 콜백
2298
+ promise.await_(save_data(), fn(result) {
2299
+ // 이행 시 실행, 반환값 무시
2300
+ Nil
2301
+ })
2302
+ ```
2303
+
2304
+ ### 6.5 DOM 조작 — `js/dom`
2305
+
2306
+ DOM 요소에 대한 직접 조작 유틸리티입니다. `hook.use_ref`로 얻은 ref의 current 값과 함께 사용합니다.
2307
+
2308
+ ```gleam
2309
+ import glendix/js/dom
2310
+ import glendix/react/hook
2311
+
2312
+ let input_ref = hook.use_ref(Nil)
2313
+
2314
+ // 포커스/블러/클릭
2315
+ dom.focus(hook.get_ref(input_ref))
2316
+ dom.blur(hook.get_ref(input_ref))
2317
+ dom.click(hook.get_ref(input_ref))
2318
+
2319
+ // 스크롤
2320
+ dom.scroll_into_view(hook.get_ref(input_ref))
2321
+
2322
+ // 위치/크기 정보 (DOMRect)
2323
+ let rect = dom.get_bounding_client_rect(hook.get_ref(input_ref))
2324
+
2325
+ // CSS 선택자로 하위 요소 검색
2326
+ case dom.query_selector(hook.get_ref(container_ref), ".target") {
2327
+ Some(el) -> dom.focus(el)
2328
+ None -> Nil
2329
+ }
2330
+ ```
2331
+
2332
+ ### 6.6 타이머 — `js/timer`
2333
+
2334
+ setTimeout/setInterval 래퍼입니다. `TimerId`는 opaque type으로 숫자 조작을 방지합니다.
2335
+
2336
+ ```gleam
2337
+ import glendix/js/timer
2338
+
2339
+ // 지연 실행
2340
+ let id = timer.set_timeout(fn() {
2341
+ // 1초 후 실행
2342
+ Nil
2343
+ }, 1000)
2344
+
2345
+ // 취소
2346
+ timer.clear_timeout(id)
2347
+
2348
+ // 반복 실행
2349
+ let interval_id = timer.set_interval(fn() {
2350
+ // 500ms마다 실행
2351
+ Nil
2352
+ }, 500)
2353
+
2354
+ // 반복 취소
2355
+ timer.clear_interval(interval_id)
2356
+ ```
2357
+
2358
+ #### useEffect와 함께 사용 (클린업 패턴)
2359
+
2360
+ ```gleam
2361
+ hook.use_effect_once_cleanup(fn() {
2362
+ let id = timer.set_interval(fn() {
2363
+ update_count(fn(prev) { prev + 1 })
2364
+ Nil
2365
+ }, 1000)
2366
+
2367
+ // 언마운트 시 타이머 정리
2368
+ fn() { timer.clear_interval(id) }
2369
+ })
2370
+ ```
2371
+
2372
+ ### 6.7 모듈 요약
2373
+
2374
+ | 모듈 | 용도 | FFI |
2375
+ |------|------|-----|
2376
+ | `js/array` | Gleam List ↔ JS Array 변환 | 없음 (react_ffi.mjs 재사용) |
2377
+ | `js/object` | 객체 생성/속성 CRUD/메서드 호출 | object_ffi.mjs |
2378
+ | `js/json` | JSON stringify/parse | json_ffi.mjs |
2379
+ | `js/promise` | Promise 체이닝/병렬/에러 처리 | promise_ffi.mjs |
2380
+ | `js/dom` | DOM 포커스/클릭/스크롤/쿼리 | dom_ffi.mjs |
2381
+ | `js/timer` | setTimeout/setInterval | timer_ffi.mjs |
2382
+
2383
+ ---
2384
+
2385
+ ## 7. 트러블슈팅
2183
2386
 
2184
2387
  ### 빌드 에러
2185
2388
 
@@ -8,4 +8,4 @@ runtime = "node"
8
8
 
9
9
  [dependencies]
10
10
  gleam_stdlib = ">= 0.44.0 and < 2.0.0"
11
- glendix = ">= 2.0.13 and < 3.0.0"
11
+ glendix = ">= 2.0.14 and < 3.0.0"