create-mendix-widget-gleam 1.0.0 → 1.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": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Scaffold a Mendix Pluggable Widget powered by Gleam",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
package/src/index.mjs CHANGED
@@ -130,7 +130,7 @@ Gleam 언어로 Mendix Pluggable Widget을 개발하여 "Hello World"를 화면
130
130
  ## Tech Stack
131
131
 
132
132
  - **Gleam** → JavaScript 컴파일 (target: javascript)
133
- - **Gleam FFI** (\`@external\` 어노테이션 + \`.ffi.mjs\` 파일) — React API를 Gleam에서 직접 호출
133
+ - **Gleam FFI** (\`@external\` 어노테이션 + FFI 파일) — React API와 Mendix API를 Gleam에서 직접 호출
134
134
  - **Mendix Pluggable Widget** (React 19)
135
135
  - **Package Manager**: ${pm} (npm 의존성은 \`gleam run -m scripts/install\`로 설치)
136
136
  - **Build**: \`@mendix/pluggable-widgets-tools\` (Rollup 기반)
@@ -141,7 +141,12 @@ Gleam 언어로 Mendix Pluggable Widget을 개발하여 "Hello World"를 화면
141
141
  src/
142
142
  widget/ # 핵심 Gleam 코드 (개발자가 작업하는 곳)
143
143
  ${names.snakeCase}.gleam # 위젯 메인 모듈
144
- ${names.snakeCase}_ffi.mjs # React FFI 어댑터
144
+ react_ffi.mjs # React FFI 어댑터 (React 원시 함수)
145
+ mendix_ffi.mjs # Mendix FFI 어댑터 (Mendix 런타임 타입 접근)
146
+ react.gleam # 핵심 타입 + createElement + fragment/text/none
147
+ react/ # React 모듈 (prop, hook, event, html)
148
+ mendix.gleam # Mendix 핵심 타입 + Props 접근자
149
+ mendix/ # Mendix API 모듈 (editable_value, action, list_value 등)
145
150
  editor_config.gleam # Studio Pro 속성 패널 설정
146
151
  scripts/ # 빌드/개발 스크립트 (gleam run -m으로 실행)
147
152
  cmd.gleam # 셸 명령어 실행 유틸리티
@@ -167,9 +172,9 @@ docs/
167
172
  ## Build Pipeline
168
173
 
169
174
  \`\`\`
170
- [src/widget/${names.snakeCase}.gleam] + [src/widget/${names.snakeCase}_ffi.mjs]
175
+ [src/widget/*.gleam] + [src/widget/react_ffi.mjs] + [src/widget/mendix_ffi.mjs]
171
176
  ↓ gleam run -m scripts/build
172
- [build/dev/javascript/${names.snakeCase}/widget/${names.snakeCase}.mjs]
177
+ [build/dev/javascript/${names.snakeCase}/widget/*.mjs]
173
178
  ↓ src/${names.pascalCase}.js (브릿지)가 import
174
179
  ↓ Rollup (pluggable-widgets-tools build:web)
175
180
  [dist/1.0.0/mendix.${names.lowerCase}.${names.pascalCase}.mpk]
@@ -192,9 +197,27 @@ gleam format # Gleam 코드 포맷팅
192
197
 
193
198
  ## Gleam FFI Convention
194
199
 
195
- - FFI 파일명: \`<module_name>_ffi.mjs\`
196
- - \`@external(javascript, "./<module>_ffi.mjs", "<function>")\` 형식으로 바인딩
197
- - FFI 파일에는 React API 래핑만 작성. 위젯 로직은 반드시 Gleam으로 작성
200
+ - FFI 도메인별로 분리: \`react_ffi.mjs\` (React 원시 함수), \`mendix_ffi.mjs\` (Mendix 런타임 타입 접근)
201
+ - \`react.gleam\`/\`mendix.gleam\`에서 \`@external(javascript, "./<ffi>.mjs", "<function>")\` 형식으로 바인딩
202
+ - \`react/*.gleam\`에서 \`@external(javascript, "../react_ffi.mjs", "<function>")\` 형식으로 바인딩
203
+ - \`mendix/*.gleam\`에서 \`@external(javascript, "../mendix_ffi.mjs", "<function>")\` 형식으로 바인딩
204
+ - FFI 파일에는 API 래핑만 작성. 위젯 로직은 반드시 Gleam으로 작성
205
+ - \`mendix_ffi.mjs\`에서 JS \`undefined\`/\`null\` ↔ Gleam \`Option\` 변환 자동 처리
206
+
207
+ ## Mendix API Modules
208
+
209
+ - \`mendix.gleam\` — \`ValueStatus\`, \`ObjectItem\`, Props 접근자 (\`get_prop\`, \`get_string_prop\`)
210
+ - \`mendix/editable_value.gleam\` — \`EditableValue\` (편집 가능한 값)
211
+ - \`mendix/action.gleam\` — \`ActionValue\` (마이크로플로우/나노플로우 실행)
212
+ - \`mendix/dynamic_value.gleam\` — \`DynamicValue\` (동적 읽기 전용 값)
213
+ - \`mendix/list_value.gleam\` — \`ListValue\`, \`FilterCondition\`, \`SortInstruction\`
214
+ - \`mendix/list_attribute.gleam\` — \`ListAttributeValue\` 등 리스트 연결 타입
215
+ - \`mendix/selection.gleam\` — 단일/다중 선택
216
+ - \`mendix/reference.gleam\` — 참조 관계 값
217
+ - \`mendix/file.gleam\` — 파일/이미지
218
+ - \`mendix/icon.gleam\` — 아이콘
219
+ - \`mendix/formatter.gleam\` — 값 포맷팅/파싱
220
+ - \`mendix/filter.gleam\` — 필터 조건 빌더
198
221
 
199
222
  ## Mendix Widget Conventions
200
223
 
@@ -205,7 +228,7 @@ gleam format # Gleam 코드 포맷팅
205
228
  ## Code Style
206
229
 
207
230
  - Gleam 파일: \`gleam format\` 사용
208
- - FFI 파일(\`.ffi.mjs\`): React API 노출만 담당, 최소한으로 유지
231
+ - FFI 파일(\`react_ffi.mjs\`, \`mendix_ffi.mjs\`): API 노출만 담당, 비즈니스 로직 금지
209
232
  - 한국어 주석 사용
210
233
  `;
211
234
 
@@ -268,7 +291,10 @@ gleam format # 코드 포맷팅
268
291
  src/
269
292
  widget/ # Gleam 위젯 코드
270
293
  ${names.snakeCase}.gleam # 메인 위젯 모듈
271
- ${names.snakeCase}_ffi.mjs # React FFI 어댑터
294
+ react_ffi.mjs # React FFI 어댑터
295
+ mendix_ffi.mjs # Mendix FFI 어댑터
296
+ react.gleam + react/ # React 모듈 계층
297
+ mendix.gleam + mendix/ # Mendix API 모듈 계층
272
298
  editor_config.gleam # Studio Pro 속성 패널
273
299
  scripts/ # 빌드/개발 스크립트
274
300
  ${names.pascalCase}.js # Mendix 브릿지 진입점
@@ -278,7 +304,7 @@ src/
278
304
  ## 기술 스택
279
305
 
280
306
  - **Gleam** → JavaScript 컴파일
281
- - **Gleam FFI** — React API 직접 바인딩
307
+ - **Gleam FFI** — React/Mendix API 직접 바인딩
282
308
  - **Mendix Pluggable Widget** (React 19)
283
309
  - **${pm}** — 패키지 매니저
284
310
 
@@ -1,20 +1,15 @@
1
1
  // Mendix Pluggable Widget - "Hello World"
2
2
  // React 함수형 컴포넌트: fn(JsProps) -> ReactElement
3
3
 
4
- // 외부 타입 (JS 값의 opaque 핸들)
5
- pub type ReactElement
6
-
7
- pub type JsProps
8
-
9
- // FFI 바인딩
10
- @external(javascript, "./{{SNAKE_CASE}}_ffi.mjs", "create_div")
11
- fn create_div(class_name: String, text_content: String) -> ReactElement
12
-
13
- @external(javascript, "./{{SNAKE_CASE}}_ffi.mjs", "get_string_prop")
14
- fn get_string_prop(props: JsProps, key: String) -> String
4
+ import widget/mendix
5
+ import widget/react.{type JsProps, type ReactElement}
6
+ import widget/react/html
7
+ import widget/react/prop
15
8
 
16
9
  /// 위젯 메인 함수 - Mendix 런타임이 React 컴포넌트로 호출
17
10
  pub fn widget(props: JsProps) -> ReactElement {
18
- let sample_text = get_string_prop(props, "sampleText")
19
- create_div("widget-hello-world", "Hello " <> sample_text)
11
+ let sample_text = mendix.get_string_prop(props, "sampleText")
12
+ html.div(prop.new() |> prop.class("widget-hello-world"), [
13
+ react.text("Hello " <> sample_text),
14
+ ])
20
15
  }
@@ -0,0 +1,41 @@
1
+ // Mendix ActionValue 타입 — 실행 가능한 액션 (마이크로플로우, 나노플로우 등)
2
+
3
+ import gleam/option.{type Option, None, Some}
4
+
5
+ // === 타입 ===
6
+
7
+ pub type ActionValue
8
+
9
+ // === 접근자 ===
10
+
11
+ /// 실행 가능 여부
12
+ @external(javascript, "../mendix_ffi.mjs", "get_action_can_execute")
13
+ pub fn can_execute(action: ActionValue) -> Bool
14
+
15
+ /// 현재 실행 중인지 여부
16
+ @external(javascript, "../mendix_ffi.mjs", "get_action_is_executing")
17
+ pub fn is_executing(action: ActionValue) -> Bool
18
+
19
+ // === 메서드 ===
20
+
21
+ /// 액션 실행
22
+ @external(javascript, "../mendix_ffi.mjs", "action_execute")
23
+ pub fn execute(action: ActionValue) -> Nil
24
+
25
+ // === 편의 함수 (순수 Gleam) ===
26
+
27
+ /// 실행 가능할 때만 실행
28
+ pub fn execute_if_can(action: ActionValue) -> Nil {
29
+ case can_execute(action) {
30
+ True -> execute(action)
31
+ False -> Nil
32
+ }
33
+ }
34
+
35
+ /// Option(ActionValue)를 받아 실행 가능하면 실행
36
+ pub fn execute_action(action: Option(ActionValue)) -> Nil {
37
+ case action {
38
+ Some(a) -> execute_if_can(a)
39
+ None -> Nil
40
+ }
41
+ }
@@ -0,0 +1,30 @@
1
+ // Mendix DynamicValue 타입 — 동적으로 계산되는 읽기 전용 값
2
+ // 사용: 표현식 속성 (expression property)
3
+
4
+ import gleam/option.{type Option}
5
+ import widget/mendix.{type ValueStatus}
6
+
7
+ // === 타입 ===
8
+
9
+ pub type DynamicValue
10
+
11
+ // === 접근자 ===
12
+
13
+ @external(javascript, "../mendix_ffi.mjs", "get_status")
14
+ fn get_status_raw(dv: DynamicValue) -> String
15
+
16
+ /// 현재 상태 (Available, Loading, Unavailable)
17
+ pub fn status(dv: DynamicValue) -> ValueStatus {
18
+ mendix.to_value_status(get_status_raw(dv))
19
+ }
20
+
21
+ /// 현재 값 (undefined → None)
22
+ @external(javascript, "../mendix_ffi.mjs", "get_dynamic_value")
23
+ pub fn value(dv: DynamicValue) -> Option(a)
24
+
25
+ // === 편의 함수 (순수 Gleam) ===
26
+
27
+ /// 값이 사용 가능한지 확인
28
+ pub fn is_available(dv: DynamicValue) -> Bool {
29
+ status(dv) == mendix.Available
30
+ }
@@ -0,0 +1,73 @@
1
+ // Mendix EditableValue 타입 — 편집 가능한 값의 접근자와 메서드
2
+ // 사용: 텍스트, 숫자, 날짜 등 Mendix 속성 편집
3
+
4
+ import gleam/option.{type Option}
5
+ import widget/mendix.{type ValueStatus}
6
+ import widget/mendix/formatter.{type ValueFormatter}
7
+
8
+ // === 타입 ===
9
+
10
+ pub type EditableValue
11
+
12
+ // === 접근자 ===
13
+
14
+ @external(javascript, "../mendix_ffi.mjs", "get_status")
15
+ fn get_status_raw(ev: EditableValue) -> String
16
+
17
+ /// 현재 상태 (Available, Loading, Unavailable)
18
+ pub fn status(ev: EditableValue) -> ValueStatus {
19
+ mendix.to_value_status(get_status_raw(ev))
20
+ }
21
+
22
+ /// 현재 값 (undefined → None)
23
+ @external(javascript, "../mendix_ffi.mjs", "get_editable_value")
24
+ pub fn value(ev: EditableValue) -> Option(a)
25
+
26
+ /// 읽기 전용 여부
27
+ @external(javascript, "../mendix_ffi.mjs", "get_editable_read_only")
28
+ pub fn read_only(ev: EditableValue) -> Bool
29
+
30
+ /// 유효성 검사 메시지 (없으면 None)
31
+ @external(javascript, "../mendix_ffi.mjs", "get_editable_validation")
32
+ pub fn validation(ev: EditableValue) -> Option(String)
33
+
34
+ /// 표시용 문자열 (포맷팅 적용된 값)
35
+ @external(javascript, "../mendix_ffi.mjs", "get_editable_display_value")
36
+ pub fn display_value(ev: EditableValue) -> String
37
+
38
+ /// 값 포매터
39
+ @external(javascript, "../mendix_ffi.mjs", "get_editable_formatter")
40
+ pub fn get_formatter(ev: EditableValue) -> ValueFormatter
41
+
42
+ /// 가능한 값 목록 (열거형 속성 등)
43
+ @external(javascript, "../mendix_ffi.mjs", "get_editable_universe")
44
+ pub fn universe(ev: EditableValue) -> Option(List(a))
45
+
46
+ // === 메서드 ===
47
+
48
+ /// 값 설정 (None → undefined 전달)
49
+ @external(javascript, "../mendix_ffi.mjs", "editable_set_value")
50
+ pub fn set_value(ev: EditableValue, value: Option(a)) -> Nil
51
+
52
+ /// 텍스트 값 직접 설정 (파싱은 Mendix가 처리)
53
+ @external(javascript, "../mendix_ffi.mjs", "editable_set_text_value")
54
+ pub fn set_text_value(ev: EditableValue, text: String) -> Nil
55
+
56
+ /// 유효성 검사기 설정 (None → 검사기 제거)
57
+ @external(javascript, "../mendix_ffi.mjs", "editable_set_validator")
58
+ pub fn set_validator(
59
+ ev: EditableValue,
60
+ validator: Option(fn(Option(a)) -> Option(String)),
61
+ ) -> Nil
62
+
63
+ // === 편의 함수 (순수 Gleam) ===
64
+
65
+ /// 값이 사용 가능한지 확인
66
+ pub fn is_available(ev: EditableValue) -> Bool {
67
+ status(ev) == mendix.Available
68
+ }
69
+
70
+ /// 편집 가능한 상태인지 확인 (사용 가능 + 읽기 전용 아님)
71
+ pub fn is_editable(ev: EditableValue) -> Bool {
72
+ is_available(ev) && !read_only(ev)
73
+ }
@@ -0,0 +1,34 @@
1
+ // Mendix FileValue / WebImage 타입 — 파일 및 이미지 속성
2
+ // FileValue: 일반 파일, WebImage: 이미지 (altText 추가)
3
+
4
+ import gleam/option.{type Option}
5
+
6
+ // === 타입 ===
7
+
8
+ pub type FileValue
9
+
10
+ pub type WebImage
11
+
12
+ // === FileValue 접근자 ===
13
+
14
+ /// 파일 URI
15
+ @external(javascript, "../mendix_ffi.mjs", "get_file_uri")
16
+ pub fn uri(f: FileValue) -> String
17
+
18
+ /// 파일 이름 (없으면 None)
19
+ @external(javascript, "../mendix_ffi.mjs", "get_file_name")
20
+ pub fn name(f: FileValue) -> Option(String)
21
+
22
+ // === WebImage 접근자 (FileValue 확장) ===
23
+
24
+ /// 이미지 URI
25
+ @external(javascript, "../mendix_ffi.mjs", "get_file_uri")
26
+ pub fn image_uri(img: WebImage) -> String
27
+
28
+ /// 이미지 파일 이름 (없으면 None)
29
+ @external(javascript, "../mendix_ffi.mjs", "get_file_name")
30
+ pub fn image_name(img: WebImage) -> Option(String)
31
+
32
+ /// 이미지 대체 텍스트 (없으면 None)
33
+ @external(javascript, "../mendix_ffi.mjs", "get_image_alt_text")
34
+ pub fn alt_text(img: WebImage) -> Option(String)
@@ -0,0 +1,109 @@
1
+ // Mendix Filter 조건 빌더 — mendix/filters/builders 래핑
2
+ // 사용: ListValue의 필터 조건 프로그래매틱 구성
3
+
4
+ import widget/mendix/list_value.{type FilterCondition}
5
+
6
+ // === 타입 ===
7
+
8
+ /// 필터 표현식 (attribute, literal, association, empty)
9
+ pub type ValueExpression
10
+
11
+ // === Boolean 조합 ===
12
+
13
+ /// AND 조합 (모든 조건 충족)
14
+ @external(javascript, "../mendix_ffi.mjs", "filter_and")
15
+ pub fn and_(conditions: List(FilterCondition)) -> FilterCondition
16
+
17
+ /// OR 조합 (하나 이상 충족)
18
+ @external(javascript, "../mendix_ffi.mjs", "filter_or")
19
+ pub fn or_(conditions: List(FilterCondition)) -> FilterCondition
20
+
21
+ /// NOT 부정
22
+ @external(javascript, "../mendix_ffi.mjs", "filter_not")
23
+ pub fn not_(condition: FilterCondition) -> FilterCondition
24
+
25
+ // === 동등 비교 ===
26
+
27
+ @external(javascript, "../mendix_ffi.mjs", "filter_equals")
28
+ pub fn equals(a: ValueExpression, b: ValueExpression) -> FilterCondition
29
+
30
+ @external(javascript, "../mendix_ffi.mjs", "filter_not_equal")
31
+ pub fn not_equal(a: ValueExpression, b: ValueExpression) -> FilterCondition
32
+
33
+ // === 크기 비교 ===
34
+
35
+ @external(javascript, "../mendix_ffi.mjs", "filter_greater_than")
36
+ pub fn greater_than(a: ValueExpression, b: ValueExpression) -> FilterCondition
37
+
38
+ @external(javascript, "../mendix_ffi.mjs", "filter_greater_than_or_equal")
39
+ pub fn greater_than_or_equal(
40
+ a: ValueExpression,
41
+ b: ValueExpression,
42
+ ) -> FilterCondition
43
+
44
+ @external(javascript, "../mendix_ffi.mjs", "filter_less_than")
45
+ pub fn less_than(a: ValueExpression, b: ValueExpression) -> FilterCondition
46
+
47
+ @external(javascript, "../mendix_ffi.mjs", "filter_less_than_or_equal")
48
+ pub fn less_than_or_equal(
49
+ a: ValueExpression,
50
+ b: ValueExpression,
51
+ ) -> FilterCondition
52
+
53
+ // === 문자열 검색 ===
54
+
55
+ @external(javascript, "../mendix_ffi.mjs", "filter_contains")
56
+ pub fn contains(a: ValueExpression, b: ValueExpression) -> FilterCondition
57
+
58
+ @external(javascript, "../mendix_ffi.mjs", "filter_starts_with")
59
+ pub fn starts_with(a: ValueExpression, b: ValueExpression) -> FilterCondition
60
+
61
+ @external(javascript, "../mendix_ffi.mjs", "filter_ends_with")
62
+ pub fn ends_with(a: ValueExpression, b: ValueExpression) -> FilterCondition
63
+
64
+ // === 날짜 비교 ===
65
+
66
+ @external(javascript, "../mendix_ffi.mjs", "filter_day_equals")
67
+ pub fn day_equals(a: ValueExpression, b: ValueExpression) -> FilterCondition
68
+
69
+ @external(javascript, "../mendix_ffi.mjs", "filter_day_not_equal")
70
+ pub fn day_not_equal(a: ValueExpression, b: ValueExpression) -> FilterCondition
71
+
72
+ @external(javascript, "../mendix_ffi.mjs", "filter_day_greater_than")
73
+ pub fn day_greater_than(
74
+ a: ValueExpression,
75
+ b: ValueExpression,
76
+ ) -> FilterCondition
77
+
78
+ @external(javascript, "../mendix_ffi.mjs", "filter_day_greater_than_or_equal")
79
+ pub fn day_greater_than_or_equal(
80
+ a: ValueExpression,
81
+ b: ValueExpression,
82
+ ) -> FilterCondition
83
+
84
+ @external(javascript, "../mendix_ffi.mjs", "filter_day_less_than")
85
+ pub fn day_less_than(a: ValueExpression, b: ValueExpression) -> FilterCondition
86
+
87
+ @external(javascript, "../mendix_ffi.mjs", "filter_day_less_than_or_equal")
88
+ pub fn day_less_than_or_equal(
89
+ a: ValueExpression,
90
+ b: ValueExpression,
91
+ ) -> FilterCondition
92
+
93
+ // === 표현식 생성 ===
94
+
95
+ /// 속성 참조 표현식 (속성 ID로 지정)
96
+ @external(javascript, "../mendix_ffi.mjs", "filter_attribute")
97
+ pub fn attribute(id: String) -> ValueExpression
98
+
99
+ /// 연관 관계 참조 표현식 (연관 ID로 지정)
100
+ @external(javascript, "../mendix_ffi.mjs", "filter_association")
101
+ pub fn association(id: String) -> ValueExpression
102
+
103
+ /// 리터럴 값 표현식
104
+ @external(javascript, "../mendix_ffi.mjs", "filter_literal")
105
+ pub fn literal(value: a) -> ValueExpression
106
+
107
+ /// 빈 값 표현식
108
+ @external(javascript, "../mendix_ffi.mjs", "filter_empty")
109
+ pub fn empty() -> ValueExpression
@@ -0,0 +1,18 @@
1
+ // Mendix ValueFormatter 타입 — 값 포맷팅/파싱
2
+ // 사용: EditableValue, ListAttributeValue 등의 포매터
3
+
4
+ import gleam/option.{type Option}
5
+
6
+ // === 타입 ===
7
+
8
+ pub type ValueFormatter
9
+
10
+ // === 메서드 ===
11
+
12
+ /// 값을 표시 문자열로 포맷팅 (None → 빈 값 포맷)
13
+ @external(javascript, "../mendix_ffi.mjs", "formatter_format")
14
+ pub fn format(fmt: ValueFormatter, value: Option(a)) -> String
15
+
16
+ /// 문자열을 값으로 파싱 (실패 시 Error(Nil))
17
+ @external(javascript, "../mendix_ffi.mjs", "formatter_parse")
18
+ pub fn parse(fmt: ValueFormatter, text: String) -> Result(Option(a), Nil)
@@ -0,0 +1,34 @@
1
+ // Mendix WebIcon 타입 — 아이콘 (글리프, 이미지, 아이콘 폰트)
2
+ // Studio Pro에서 설정한 아이콘 속성
3
+
4
+ // === 타입 ===
5
+
6
+ pub type WebIcon
7
+
8
+ pub type IconType {
9
+ Glyph
10
+ Image
11
+ IconFont
12
+ }
13
+
14
+ // === 접근자 ===
15
+
16
+ @external(javascript, "../mendix_ffi.mjs", "get_icon_type")
17
+ fn get_icon_type_raw(icon: WebIcon) -> String
18
+
19
+ /// 아이콘 종류 (Glyph, Image, IconFont)
20
+ pub fn icon_type(icon: WebIcon) -> IconType {
21
+ case get_icon_type_raw(icon) {
22
+ "glyph" -> Glyph
23
+ "image" -> Image
24
+ _ -> IconFont
25
+ }
26
+ }
27
+
28
+ /// 아이콘 CSS 클래스 (Glyph, IconFont에서 사용)
29
+ @external(javascript, "../mendix_ffi.mjs", "get_icon_class")
30
+ pub fn icon_class(icon: WebIcon) -> String
31
+
32
+ /// 아이콘 이미지 URL (Image에서 사용)
33
+ @external(javascript, "../mendix_ffi.mjs", "get_icon_url")
34
+ pub fn icon_url(icon: WebIcon) -> String
@@ -0,0 +1,57 @@
1
+ // Mendix List-linked 타입 — ListValue의 아이템별 접근자
2
+ // ListAttributeValue, ListActionValue, ListExpressionValue, ListWidgetValue
3
+
4
+ import gleam/option.{type Option}
5
+ import widget/mendix.{type ObjectItem}
6
+ import widget/mendix/formatter.{type ValueFormatter}
7
+ import widget/react.{type ReactElement}
8
+
9
+ // === 타입 ===
10
+
11
+ pub type ListAttributeValue
12
+
13
+ pub type ListActionValue
14
+
15
+ pub type ListExpressionValue
16
+
17
+ pub type ListWidgetValue
18
+
19
+ // === 아이템별 값 접근 (공용 FFI: list_type_get) ===
20
+
21
+ /// 특정 아이템의 속성 값 가져오기 (EditableValue 반환)
22
+ @external(javascript, "../mendix_ffi.mjs", "list_type_get")
23
+ pub fn get_attribute(attr: ListAttributeValue, item: ObjectItem) -> a
24
+
25
+ /// 특정 아이템의 액션 가져오기 (Option(ActionValue) 반환)
26
+ @external(javascript, "../mendix_ffi.mjs", "list_type_get")
27
+ pub fn get_action(action: ListActionValue, item: ObjectItem) -> Option(a)
28
+
29
+ /// 특정 아이템의 표현식 값 가져오기 (DynamicValue 반환)
30
+ @external(javascript, "../mendix_ffi.mjs", "list_type_get")
31
+ pub fn get_expression(expr: ListExpressionValue, item: ObjectItem) -> a
32
+
33
+ /// 특정 아이템의 위젯 렌더링 가져오기 (ReactElement 반환)
34
+ @external(javascript, "../mendix_ffi.mjs", "list_type_get")
35
+ pub fn get_widget(widget: ListWidgetValue, item: ObjectItem) -> ReactElement
36
+
37
+ // === ListAttributeValue 메타데이터 ===
38
+
39
+ /// 속성 ID
40
+ @external(javascript, "../mendix_ffi.mjs", "get_list_attr_id")
41
+ pub fn attr_id(attr: ListAttributeValue) -> String
42
+
43
+ /// 정렬 가능 여부
44
+ @external(javascript, "../mendix_ffi.mjs", "get_list_attr_sortable")
45
+ pub fn attr_sortable(attr: ListAttributeValue) -> Bool
46
+
47
+ /// 필터링 가능 여부
48
+ @external(javascript, "../mendix_ffi.mjs", "get_list_attr_filterable")
49
+ pub fn attr_filterable(attr: ListAttributeValue) -> Bool
50
+
51
+ /// 속성 타입 문자열 ("String", "Integer", "DateTime" 등)
52
+ @external(javascript, "../mendix_ffi.mjs", "get_list_attr_type")
53
+ pub fn attr_type(attr: ListAttributeValue) -> String
54
+
55
+ /// 속성 포매터
56
+ @external(javascript, "../mendix_ffi.mjs", "get_list_attr_formatter")
57
+ pub fn attr_formatter(attr: ListAttributeValue) -> ValueFormatter
@@ -0,0 +1,106 @@
1
+ // Mendix ListValue 타입 — 데이터 소스에서 가져온 객체 목록
2
+ // 사용: 데이터 그리드, 리스트 뷰 등
3
+
4
+ import gleam/option.{type Option}
5
+ import widget/mendix.{type ObjectItem, type ValueStatus}
6
+
7
+ // === 타입 ===
8
+
9
+ pub type ListValue
10
+
11
+ pub type FilterCondition
12
+
13
+ pub type SortInstruction
14
+
15
+ pub type SortDirection {
16
+ Asc
17
+ Desc
18
+ }
19
+
20
+ // === 접근자 ===
21
+
22
+ @external(javascript, "../mendix_ffi.mjs", "get_status")
23
+ fn get_status_raw(lv: ListValue) -> String
24
+
25
+ /// 현재 상태 (Available, Loading, Unavailable)
26
+ pub fn status(lv: ListValue) -> ValueStatus {
27
+ mendix.to_value_status(get_status_raw(lv))
28
+ }
29
+
30
+ /// 아이템 목록 (로딩 중이면 None)
31
+ @external(javascript, "../mendix_ffi.mjs", "get_list_items")
32
+ pub fn items(lv: ListValue) -> Option(List(ObjectItem))
33
+
34
+ /// 현재 오프셋
35
+ @external(javascript, "../mendix_ffi.mjs", "get_list_offset")
36
+ pub fn offset(lv: ListValue) -> Int
37
+
38
+ /// 현재 페이지 크기
39
+ @external(javascript, "../mendix_ffi.mjs", "get_list_limit")
40
+ pub fn limit(lv: ListValue) -> Int
41
+
42
+ /// 더 많은 아이템이 있는지 (불확실하면 None)
43
+ @external(javascript, "../mendix_ffi.mjs", "get_list_has_more_items")
44
+ pub fn has_more_items(lv: ListValue) -> Option(Bool)
45
+
46
+ /// 전체 아이템 수 (요청하지 않았으면 None)
47
+ @external(javascript, "../mendix_ffi.mjs", "get_list_total_count")
48
+ pub fn total_count(lv: ListValue) -> Option(Int)
49
+
50
+ /// 현재 정렬 순서
51
+ @external(javascript, "../mendix_ffi.mjs", "get_list_sort_order")
52
+ pub fn sort_order(lv: ListValue) -> List(SortInstruction)
53
+
54
+ /// 현재 필터 조건 (없으면 None)
55
+ @external(javascript, "../mendix_ffi.mjs", "get_list_filter")
56
+ pub fn filter(lv: ListValue) -> Option(FilterCondition)
57
+
58
+ // === 메서드 ===
59
+
60
+ /// 오프셋 설정 (페이지네이션)
61
+ @external(javascript, "../mendix_ffi.mjs", "list_set_offset")
62
+ pub fn set_offset(lv: ListValue, offset: Int) -> Nil
63
+
64
+ /// 페이지 크기 설정
65
+ @external(javascript, "../mendix_ffi.mjs", "list_set_limit")
66
+ pub fn set_limit(lv: ListValue, limit: Int) -> Nil
67
+
68
+ /// 필터 조건 설정 (None → 필터 해제)
69
+ @external(javascript, "../mendix_ffi.mjs", "list_set_filter")
70
+ pub fn set_filter(lv: ListValue, filter: Option(FilterCondition)) -> Nil
71
+
72
+ /// 정렬 순서 설정
73
+ @external(javascript, "../mendix_ffi.mjs", "list_set_sort_order")
74
+ pub fn set_sort_order(lv: ListValue, order: List(SortInstruction)) -> Nil
75
+
76
+ /// 데이터 새로고침
77
+ @external(javascript, "../mendix_ffi.mjs", "list_reload")
78
+ pub fn reload(lv: ListValue) -> Nil
79
+
80
+ /// 전체 아이템 수 요청 (True → 요청, False → 해제)
81
+ @external(javascript, "../mendix_ffi.mjs", "list_request_total_count")
82
+ pub fn request_total_count(lv: ListValue, need: Bool) -> Nil
83
+
84
+ // === SortInstruction 빌더 ===
85
+
86
+ @external(javascript, "../mendix_ffi.mjs", "make_sort_instruction")
87
+ fn make_sort_raw(id: String, asc: Bool) -> SortInstruction
88
+
89
+ /// 정렬 명령 생성
90
+ pub fn sort(id: String, direction: SortDirection) -> SortInstruction {
91
+ make_sort_raw(id, direction == Asc)
92
+ }
93
+
94
+ @external(javascript, "../mendix_ffi.mjs", "get_sort_id")
95
+ pub fn sort_id(instr: SortInstruction) -> String
96
+
97
+ @external(javascript, "../mendix_ffi.mjs", "get_sort_asc")
98
+ fn sort_asc_raw(instr: SortInstruction) -> Bool
99
+
100
+ /// 정렬 방향 조회
101
+ pub fn sort_direction(instr: SortInstruction) -> SortDirection {
102
+ case sort_asc_raw(instr) {
103
+ True -> Asc
104
+ False -> Desc
105
+ }
106
+ }