create-mendix-widget-gleam 3.0.1 → 3.0.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-mendix-widget-gleam",
3
- "version": "3.0.1",
3
+ "version": "3.0.2",
4
4
  "description": "Scaffold a Mendix Pluggable Widget powered by Gleam",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -43,7 +43,7 @@ glendix는 Gleam으로 Mendix Pluggable Widget을 작성하는 FFI 라이브러
43
43
 
44
44
  ```toml
45
45
  [dependencies]
46
- glendix = ">= 3.0.0 and < 4.0.0"
46
+ glendix = ">= 3.0.2 and < 4.0.0"
47
47
  ```
48
48
 
49
49
  Peer dependency (위젯 프로젝트 `package.json`):
@@ -51,12 +51,13 @@ Peer dependency (위젯 프로젝트 `package.json`):
51
51
  ```json
52
52
  {
53
53
  "dependencies": { "big.js": "^6.0.0" },
54
- "overrides": { "@types/react": "19.0.0", "@types/react-dom": "19.0.0" },
55
- "resolutions": { "@types/react": "19.0.0", "@types/react-dom": "19.0.0" }
54
+ "overrides": { "react": "19.0.0", "react-dom": "19.0.0", "@types/react": "19.0.0", "@types/react-dom": "19.0.0" },
55
+ "resolutions": { "react": "19.0.0", "react-dom": "19.0.0", "@types/react": "19.0.0", "@types/react-dom": "19.0.0" }
56
56
  }
57
57
  ```
58
58
 
59
- > `react`/`react-dom`은 `dependencies`에 넣지 않는다. `pluggable-widgets-tools`가 자동 제공하며, 직접 선언하면 마이그레이션 충돌이 발생한다.
59
+ > - `react`/`react-dom`은 `dependencies`에 넣지 않는다. `pluggable-widgets-tools`가 자동 제공하며, 직접 선언하면 번들 충돌이 발생한다.
60
+ > - `overrides`/`resolutions`에서 반드시 **캐럿(`^`) 없이 정확한 버전**을 지정한다. `^19.0.0`은 react와 react-dom이 서로 다른 19.x.x로 해석되어 런타임 버전 불일치 에러를 일으킨다.
60
61
 
61
62
  ```bash
62
63
  gleam run -m glendix/install # 의존성 설치 + 바인딩 생성
@@ -81,7 +82,7 @@ pub fn widget(props: JsProps) -> Element
81
82
 
82
83
  ---
83
84
 
84
- ## 3. 렌더링 경로 선택
85
+ ## 4. 렌더링 경로 선택
85
86
 
86
87
  glendix는 두 가지 렌더링 경로를 지원합니다. 둘 다 `redraw.Element`를 반환하므로 자유롭게 합성 가능합니다.
87
88
 
@@ -97,9 +98,9 @@ glendix는 두 가지 렌더링 경로를 지원합니다. 둘 다 `redraw.Eleme
97
98
 
98
99
  ---
99
100
 
100
- ## 4. redraw 렌더링 경로 — 레퍼런스
101
+ ## 5. redraw 렌더링 경로 — 레퍼런스
101
102
 
102
- ### 4.1 필수 import 패턴
103
+ ### 5.1 필수 import 패턴
103
104
 
104
105
  ```gleam
105
106
  import glendix/mendix.{type JsProps} // Mendix props 타입
@@ -109,7 +110,7 @@ import redraw/dom/attribute // HTML 속성
109
110
  import redraw/dom/events // 이벤트 핸들러
110
111
  ```
111
112
 
112
- ### 4.2 HTML 엘리먼트 생성
113
+ ### 5.2 HTML 엘리먼트 생성
113
114
 
114
115
  ```gleam
115
116
  // 속성 + 자식
@@ -124,7 +125,7 @@ html.img([attribute.src("image.png"), attribute.alt("설명")])
124
125
  html.br([])
125
126
  ```
126
127
 
127
- ### 4.3 텍스트, 빈 렌더링, Fragment
128
+ ### 5.3 텍스트, 빈 렌더링, Fragment
128
129
 
129
130
  ```gleam
130
131
  html.text("안녕하세요") // 텍스트 노드
@@ -135,7 +136,7 @@ html.none() // 아무것도 렌더링하지 않음 (Rea
135
136
  redraw.fragment([child1, child2]) // Fragment
136
137
  ```
137
138
 
138
- ### 4.4 조건부 렌더링
139
+ ### 5.4 조건부 렌더링
139
140
 
140
141
  v3.0에서는 Gleam `case` 표현식을 직접 사용합니다:
141
142
 
@@ -160,7 +161,7 @@ case mendix.get_status(value) {
160
161
  }
161
162
  ```
162
163
 
163
- ### 4.5 리스트 렌더링
164
+ ### 5.5 리스트 렌더링
164
165
 
165
166
  ```gleam
166
167
  import gleam/list
@@ -174,7 +175,7 @@ html.ul([], list.map(items, fn(item) {
174
175
 
175
176
  > 리스트 렌더링 시 `attribute.key()`를 항상 설정해야 합니다. React reconciliation에 필요합니다.
176
177
 
177
- ### 4.6 속성
178
+ ### 5.6 속성
178
179
 
179
180
  ```gleam
180
181
  import redraw/dom/attribute
@@ -199,7 +200,7 @@ attribute.attribute("data-custom", "value")
199
200
  attribute.ref(my_ref)
200
201
  ```
201
202
 
202
- ### 4.7 이벤트 핸들러
203
+ ### 5.7 이벤트 핸들러
203
204
 
204
205
  ```gleam
205
206
  import redraw/dom/events
@@ -216,7 +217,7 @@ events.on_blur(fn(e) { Nil })
216
217
  events.on_click_capture(fn(e) { Nil })
217
218
  ```
218
219
 
219
- ### 4.8 Hooks
220
+ ### 5.8 Hooks
220
221
 
221
222
  모든 훅은 `redraw` 메인 모듈에 있습니다:
222
223
 
@@ -233,8 +234,11 @@ redraw.use_effect(fn() { Nil }, deps) // 의존성 지정
233
234
  redraw.use_effect_(fn() { fn() { cleanup() } }, deps) // 클린업 포함
234
235
 
235
236
  // Ref
236
- let my_ref = redraw.use_ref() // Option(a)
237
- let my_ref = redraw.use_ref_(initial) // 초기값 지정
237
+ import redraw/ref
238
+ let my_ref = redraw.use_ref() // Ref(Option(a))
239
+ let my_ref = redraw.use_ref_(initial) // Ref(a) — 초기값 지정
240
+ ref.current(my_ref) // 현재 값 읽기
241
+ ref.assign(my_ref, new_value) // 값 쓰기
238
242
 
239
243
  // 메모이제이션
240
244
  let result = redraw.use_memo(fn() { expensive(data) }, data)
@@ -252,7 +256,7 @@ let #(is_pending, start) = redraw.use_transition()
252
256
  let deferred = redraw.use_deferred_value(value)
253
257
  ```
254
258
 
255
- ### 4.9 컴포넌트 정의
259
+ ### 5.9 컴포넌트 정의
256
260
 
257
261
  ```gleam
258
262
  import redraw
@@ -266,7 +270,7 @@ let my_comp = redraw.component_("MyComponent", fn(props) {
266
270
  let memoized = redraw.memoize_(my_comp)
267
271
  ```
268
272
 
269
- ### 4.10 Context API
273
+ ### 5.10 Context API
270
274
 
271
275
  ```gleam
272
276
  import redraw
@@ -280,7 +284,7 @@ redraw.provider(theme_ctx, "dark", [child_elements])
280
284
  let theme = redraw.use_context(theme_ctx)
281
285
  ```
282
286
 
283
- ### 4.11 SVG
287
+ ### 5.11 SVG
284
288
 
285
289
  ```gleam
286
290
  import redraw/dom/svg
@@ -298,9 +302,9 @@ svg.svg([attribute.attribute("viewBox", "0 0 100 100")], [
298
302
 
299
303
  ---
300
304
 
301
- ## 5. lustre 렌더링 경로 — 레퍼런스
305
+ ## 6. lustre 렌더링 경로 — 레퍼런스
302
306
 
303
- ### 5.1 TEA 패턴 (use_tea)
307
+ ### 6.1 TEA 패턴 (use_tea)
304
308
 
305
309
  `update`와 `view`는 표준 lustre 코드와 100% 동일합니다. 진입점만 `glendix/lustre.use_tea()`를 사용합니다.
306
310
 
@@ -347,7 +351,7 @@ pub fn widget(_props: JsProps) -> Element {
347
351
  }
348
352
  ```
349
353
 
350
- ### 5.2 Simple TEA (use_simple) — Effect 없음
354
+ ### 6.2 Simple TEA (use_simple) — Effect 없음
351
355
 
352
356
  ```gleam
353
357
  import glendix/lustre as gl
@@ -364,7 +368,7 @@ fn update_simple(model: Model, msg: Msg) -> Model {
364
368
  }
365
369
  ```
366
370
 
367
- ### 5.3 Lustre Element를 수동으로 변환 (render)
371
+ ### 6.3 Lustre Element를 수동으로 변환 (render)
368
372
 
369
373
  lustre 뷰를 React 트리 안에 삽입할 때 사용합니다:
370
374
 
@@ -374,7 +378,7 @@ import glendix/lustre as gl
374
378
  let react_element = gl.render(lustre_element, dispatch_fn)
375
379
  ```
376
380
 
377
- ### 5.4 redraw Element를 lustre 트리에 삽입 (embed)
381
+ ### 6.4 redraw Element를 lustre 트리에 삽입 (embed)
378
382
 
379
383
  lustre view 안에서 redraw 컴포넌트를 사용할 때 호출합니다:
380
384
 
@@ -401,9 +405,9 @@ fn view(model: Model) {
401
405
 
402
406
  ---
403
407
 
404
- ## 6. 외부 컴포넌트 통합
408
+ ## 7. 외부 컴포넌트 통합
405
409
 
406
- ### 6.1 모듈 선택 가이드
410
+ ### 7.1 모듈 선택 가이드
407
411
 
408
412
  | 컴포넌트 출처 | 사용 모듈 | 예시 |
409
413
  |--------------|----------|------|
@@ -411,7 +415,7 @@ fn view(model: Model) {
411
415
  | `.mpk` Pluggable 위젯 | `glendix/widget` + `glendix/interop` | Switch.mpk, Badge.mpk |
412
416
  | `.mpk` Classic (Dojo) 위젯 | `glendix/classic` | CameraWidget.mpk |
413
417
 
414
- ### 6.2 외부 React 컴포넌트 (binding + interop)
418
+ ### 7.2 외부 React 컴포넌트 (binding + interop)
415
419
 
416
420
  **설정:** `bindings.json` 작성 → `npm install 패키지명` → `gleam run -m glendix/install`
417
421
 
@@ -450,7 +454,7 @@ pub fn tooltip(attrs: List(Attribute)) -> Element {
450
454
  | `interop.component_el_(comp, children)` | 자식만 |
451
455
  | `interop.void_component_el(comp, attrs)` | self-closing (자식 없음) |
452
456
 
453
- ### 6.3 .mpk Pluggable 위젯 (widget + interop)
457
+ ### 7.3 .mpk Pluggable 위젯 (widget + interop)
454
458
 
455
459
  **설정:** `.mpk`를 `widgets/`에 배치 → `gleam run -m glendix/install`
456
460
 
@@ -495,7 +499,7 @@ interop.component_el(comp, [
495
499
 
496
500
  > Mendix에서 받은 prop (JsProps에서 꺼낸 값)은 이미 올바른 형식이므로 `attribute.attribute(key, value)`로 그대로 전달합니다.
497
501
 
498
- ### 6.4 Classic (Dojo) 위젯
502
+ ### 7.4 Classic (Dojo) 위젯
499
503
 
500
504
  ```gleam
501
505
  import gleam/dynamic
@@ -511,9 +515,9 @@ classic.render("CameraWidget.widget.CameraWidget", [
511
515
 
512
516
  ---
513
517
 
514
- ## 7. Mendix API 레퍼런스
518
+ ## 8. Mendix API 레퍼런스
515
519
 
516
- ### 7.1 Props 접근 (`glendix/mendix`)
520
+ ### 8.1 Props 접근 (`glendix/mendix`)
517
521
 
518
522
  `JsProps`는 opaque 타입입니다. 접근자 함수로만 읽습니다.
519
523
 
@@ -533,7 +537,7 @@ mendix.get_string_prop(props, "caption") // String
533
537
  mendix.has_prop(props, "onClick") // Bool
534
538
  ```
535
539
 
536
- ### 7.2 ValueStatus 확인
540
+ ### 8.2 ValueStatus 확인
537
541
 
538
542
  Mendix의 모든 동적 값은 상태를 가집니다:
539
543
 
@@ -547,7 +551,7 @@ case mendix.get_status(some_value) {
547
551
  }
548
552
  ```
549
553
 
550
- ### 7.3 EditableValue (`glendix/mendix/editable_value`)
554
+ ### 8.3 EditableValue (`glendix/mendix/editable_value`)
551
555
 
552
556
  텍스트, 숫자, 날짜 등 편집 가능한 Mendix 속성:
553
557
 
@@ -577,7 +581,7 @@ ev.set_validator(attr, Some(fn(value) {
577
581
  ev.universe(attr) // Option(List(a))
578
582
  ```
579
583
 
580
- ### 7.4 ActionValue (`glendix/mendix/action`)
584
+ ### 8.4 ActionValue (`glendix/mendix/action`)
581
585
 
582
586
  Mendix 마이크로플로우/나노플로우 실행:
583
587
 
@@ -592,7 +596,7 @@ action.can_execute(my_action) // Bool
592
596
  action.is_executing(my_action) // Bool
593
597
  ```
594
598
 
595
- ### 7.5 DynamicValue (`glendix/mendix/dynamic_value`)
599
+ ### 8.5 DynamicValue (`glendix/mendix/dynamic_value`)
596
600
 
597
601
  읽기 전용 표현식 속성:
598
602
 
@@ -604,7 +608,7 @@ dv.status(expr) // String
604
608
  dv.is_available(expr) // Bool
605
609
  ```
606
610
 
607
- ### 7.6 ListValue (`glendix/mendix/list_value`)
611
+ ### 8.6 ListValue (`glendix/mendix/list_value`)
608
612
 
609
613
  Mendix 데이터 소스 리스트:
610
614
 
@@ -637,7 +641,7 @@ lv.set_filter(list_val, None) // 필터 해제
637
641
  lv.reload(list_val)
638
642
  ```
639
643
 
640
- ### 7.7 ListAttribute (`glendix/mendix/list_attribute`)
644
+ ### 8.7 ListAttribute (`glendix/mendix/list_attribute`)
641
645
 
642
646
  리스트의 각 아이템에서 속성/액션/위젯 추출:
643
647
 
@@ -657,7 +661,7 @@ la.attr_type(attr) // "String", "Integer" 등
657
661
  la.attr_formatter(attr) // ValueFormatter
658
662
  ```
659
663
 
660
- ### 7.8 Selection (`glendix/mendix/selection`)
664
+ ### 8.8 Selection (`glendix/mendix/selection`)
661
665
 
662
666
  ```gleam
663
667
  import glendix/mendix/selection
@@ -672,7 +676,7 @@ selection.selections(multi_sel) // List(ObjectItem)
672
676
  selection.set_selections(multi_sel, [item1, item2])
673
677
  ```
674
678
 
675
- ### 7.9 Reference / ReferenceSet
679
+ ### 8.9 Reference / ReferenceSet
676
680
 
677
681
  ```gleam
678
682
  import glendix/mendix/reference as ref
@@ -689,7 +693,7 @@ ref_set.value(my_ref_set) // Option(List(a))
689
693
  ref_set.set_value(my_ref_set, Some([item1, item2]))
690
694
  ```
691
695
 
692
- ### 7.10 Filter (`glendix/mendix/filter`)
696
+ ### 8.10 Filter (`glendix/mendix/filter`)
693
697
 
694
698
  ```gleam
695
699
  import glendix/mendix/filter
@@ -715,7 +719,7 @@ filter.literal(value) // 상수 값
715
719
  filter.empty() // null 비교용
716
720
  ```
717
721
 
718
- ### 7.11 날짜 (`glendix/mendix/date`)
722
+ ### 8.11 날짜 (`glendix/mendix/date`)
719
723
 
720
724
  > Gleam month는 1-based (1~12), JS는 0-based. glendix가 자동 변환합니다.
721
725
 
@@ -737,7 +741,7 @@ date.to_input_value(d) // "2024-03-15" (input[type="date"]용)
737
741
  date.from_input_value(s) // Option(JsDate)
738
742
  ```
739
743
 
740
- ### 7.12 Big (`glendix/mendix/big`)
744
+ ### 8.12 Big (`glendix/mendix/big`)
741
745
 
742
746
  Big.js 래퍼. Mendix Decimal 타입 처리용:
743
747
 
@@ -758,7 +762,7 @@ big.to_string(a) big.to_float(a)
758
762
  big.to_int(a) big.to_fixed(a, 2)
759
763
  ```
760
764
 
761
- ### 7.13 File, Icon, Formatter
765
+ ### 8.13 File, Icon, Formatter
762
766
 
763
767
  ```gleam
764
768
  // FileValue / WebImage
@@ -782,7 +786,7 @@ formatter.parse(fmt, "123.45") // Result(Option(a), Nil)
782
786
 
783
787
  ---
784
788
 
785
- ## 8. Editor Configuration (`glendix/editor_config`)
789
+ ## 9. Editor Configuration (`glendix/editor_config`)
786
790
 
787
791
  Studio Pro의 editorConfig 로직을 Gleam으로 작성합니다.
788
792
 
@@ -829,7 +833,7 @@ pub fn get_properties(
829
833
 
830
834
  ---
831
835
 
832
- ## 9. JS Interop Escape Hatch (`glendix/js/*`)
836
+ ## 10. JS Interop Escape Hatch (`glendix/js/*`)
833
837
 
834
838
  외부 JS 라이브러리(SpreadJS, Chart.js 등)와 직접 상호작용할 때 사용합니다. 모든 값은 `Dynamic` 타입. 가능하면 `glendix/binding`을 먼저 고려하세요.
835
839
 
@@ -841,14 +845,14 @@ array.to_list(js_arr) // JS Array → Gleam List
841
845
 
842
846
  // 객체
843
847
  import glendix/js/object
844
- object.object([#("width", dynamic.from(800))])
848
+ object.object([#("width", dynamic.int(800))])
845
849
  object.get(obj, "key")
846
- object.set(obj, "key", dynamic.from(val))
850
+ object.set(obj, "key", dynamic.string(val))
847
851
  object.call_method(obj, "method", [arg1, arg2])
848
852
 
849
853
  // JSON
850
854
  import glendix/js/json
851
- json.stringify(dynamic.from(data)) // String
855
+ json.stringify(data) // String
852
856
  json.parse("{\"k\":\"v\"}") // Result(Dynamic, String)
853
857
 
854
858
  // Promise
@@ -876,7 +880,7 @@ timer.clear_interval(id)
876
880
 
877
881
  ---
878
882
 
879
- ## 10. 빌드 & 도구
883
+ ## 11. 빌드 & 도구
880
884
 
881
885
  | 명령어 | 설명 |
882
886
  |--------|------|
@@ -895,9 +899,9 @@ timer.clear_interval(id)
895
899
 
896
900
  ---
897
901
 
898
- ## 11. 실전 패턴
902
+ ## 12. 실전 패턴
899
903
 
900
- ### 11.1 폼 입력 위젯
904
+ ### 12.1 폼 입력 위젯
901
905
 
902
906
  ```gleam
903
907
  import gleam/option.{None, Some}
@@ -948,7 +952,7 @@ pub fn text_input_widget(props: JsProps) -> Element {
948
952
  }
949
953
  ```
950
954
 
951
- ### 11.2 데이터 테이블 위젯
955
+ ### 12.2 데이터 테이블 위젯
952
956
 
953
957
  ```gleam
954
958
  import gleam/list
@@ -982,7 +986,7 @@ pub fn data_table(props: JsProps) -> Element {
982
986
  }
983
987
  ```
984
988
 
985
- ### 11.3 검색 가능한 리스트
989
+ ### 12.3 검색 가능한 리스트
986
990
 
987
991
  ```gleam
988
992
  import gleam/option.{None, Some}
@@ -1024,11 +1028,12 @@ pub fn searchable_list(props: JsProps) -> Element {
1024
1028
 
1025
1029
  ---
1026
1030
 
1027
- ## 12. 절대 하지 말 것
1031
+ ## 13. 절대 하지 말 것
1028
1032
 
1029
1033
  | 실수 | 올바른 방법 |
1030
1034
  |------|------------|
1031
1035
  | `import glendix/react` | **삭제됨.** `import redraw` 사용 |
1036
+ | `react`/`react-dom`을 `dependencies`에 추가 | `pluggable-widgets-tools`가 제공. 직접 넣으면 버전 충돌 |
1032
1037
  | 조건 안에서 Hook 호출 | Hook은 항상 함수 최상위에서 호출 |
1033
1038
  | `html.text("")`로 빈 렌더링 | `html.none()` 사용 |
1034
1039
  | `binding.resolve(m(), "pie_chart")` | JS 원본 이름 유지: `"PieChart"` |
@@ -1040,7 +1045,7 @@ pub fn searchable_list(props: JsProps) -> Element {
1040
1045
 
1041
1046
  ---
1042
1047
 
1043
- ## 13. 트러블슈팅
1048
+ ## 14. 트러블슈팅
1044
1049
 
1045
1050
  | 문제 | 원인 | 해결 |
1046
1051
  |------|------|------|
@@ -8,7 +8,7 @@ runtime = "node"
8
8
 
9
9
  [dependencies]
10
10
  gleam_stdlib = ">= 0.44.0 and < 2.0.0"
11
- glendix = ">= 3.0.0 and < 4.0.0"
11
+ glendix = ">= 3.0.2 and < 4.0.0"
12
12
  redraw = ">= 19.2.2 and < 20.0.0"
13
13
  redraw_dom = ">= 19.2.2 and < 20.0.0"
14
14
  lustre = ">= 5.6.0 and < 6.0.0"
@@ -27,10 +27,14 @@
27
27
  "big.js": "^6.0.0"
28
28
  },
29
29
  "resolutions": {
30
+ "react": "19.0.0",
31
+ "react-dom": "19.0.0",
30
32
  "@types/react": "19.0.0",
31
33
  "@types/react-dom": "19.0.0"
32
34
  },
33
35
  "overrides": {
36
+ "react": "19.0.0",
37
+ "react-dom": "19.0.0",
34
38
  "@types/react": "19.0.0",
35
39
  "@types/react-dom": "19.0.0"
36
40
  }