jui-tools-mcp-server 2.5.0
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/.github/workflows/test.yml +35 -0
- package/README.md +148 -0
- package/data/attribute_definitions.json +4248 -0
- package/data/attribute_semantics.json +137 -0
- package/data/binding_semantics.json +115 -0
- package/data/component_metadata.json +769 -0
- package/data/coverage.json +114 -0
- package/data/screen_identity.json +350 -0
- package/dist/cli_runner.d.ts +10 -0
- package/dist/cli_runner.js +33 -0
- package/dist/config.d.ts +19 -0
- package/dist/config.js +67 -0
- package/dist/data/component_metadata.d.ts +30 -0
- package/dist/data/component_metadata.js +498 -0
- package/dist/data/derived.d.ts +198 -0
- package/dist/data/derived.js +293 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +130 -0
- package/dist/spec_loader.d.ts +110 -0
- package/dist/spec_loader.js +445 -0
- package/dist/tools/api/list_api_models.d.ts +10 -0
- package/dist/tools/api/list_api_models.js +37 -0
- package/dist/tools/api/list_api_specs.d.ts +19 -0
- package/dist/tools/api/list_api_specs.js +42 -0
- package/dist/tools/api/preview_api_model_sync.d.ts +11 -0
- package/dist/tools/api/preview_api_model_sync.js +34 -0
- package/dist/tools/context/get_project_config.d.ts +3 -0
- package/dist/tools/context/get_project_config.js +20 -0
- package/dist/tools/context/list_component_specs.d.ts +3 -0
- package/dist/tools/context/list_component_specs.js +35 -0
- package/dist/tools/context/list_layouts.d.ts +3 -0
- package/dist/tools/context/list_layouts.js +118 -0
- package/dist/tools/context/list_screen_specs.d.ts +3 -0
- package/dist/tools/context/list_screen_specs.js +37 -0
- package/dist/tools/context/read_layout_file.d.ts +3 -0
- package/dist/tools/context/read_layout_file.js +25 -0
- package/dist/tools/context/read_spec_file.d.ts +3 -0
- package/dist/tools/context/read_spec_file.js +27 -0
- package/dist/tools/doc/doc_generate_component.d.ts +3 -0
- package/dist/tools/doc/doc_generate_component.js +38 -0
- package/dist/tools/doc/doc_generate_html.d.ts +3 -0
- package/dist/tools/doc/doc_generate_html.js +46 -0
- package/dist/tools/doc/doc_generate_spec.d.ts +3 -0
- package/dist/tools/doc/doc_generate_spec.js +38 -0
- package/dist/tools/doc/doc_init_component.d.ts +3 -0
- package/dist/tools/doc/doc_init_component.js +30 -0
- package/dist/tools/doc/doc_init_spec.d.ts +3 -0
- package/dist/tools/doc/doc_init_spec.js +33 -0
- package/dist/tools/doc/doc_rules_init.d.ts +3 -0
- package/dist/tools/doc/doc_rules_init.js +25 -0
- package/dist/tools/doc/doc_rules_show.d.ts +3 -0
- package/dist/tools/doc/doc_rules_show.js +21 -0
- package/dist/tools/doc/doc_validate_component.d.ts +3 -0
- package/dist/tools/doc/doc_validate_component.js +39 -0
- package/dist/tools/doc/doc_validate_spec.d.ts +3 -0
- package/dist/tools/doc/doc_validate_spec.js +40 -0
- package/dist/tools/jui/jui_build.d.ts +3 -0
- package/dist/tools/jui/jui_build.js +31 -0
- package/dist/tools/jui/jui_generate_converter.d.ts +3 -0
- package/dist/tools/jui/jui_generate_converter.js +43 -0
- package/dist/tools/jui/jui_generate_project.d.ts +3 -0
- package/dist/tools/jui/jui_generate_project.js +43 -0
- package/dist/tools/jui/jui_generate_screen.d.ts +3 -0
- package/dist/tools/jui/jui_generate_screen.js +22 -0
- package/dist/tools/jui/jui_init.d.ts +3 -0
- package/dist/tools/jui/jui_init.js +42 -0
- package/dist/tools/jui/jui_migrate_layouts.d.ts +3 -0
- package/dist/tools/jui/jui_migrate_layouts.js +25 -0
- package/dist/tools/jui/jui_sync_tool.d.ts +3 -0
- package/dist/tools/jui/jui_sync_tool.js +33 -0
- package/dist/tools/jui/jui_verify.d.ts +3 -0
- package/dist/tools/jui/jui_verify.js +43 -0
- package/dist/tools/spec/get_binding_rules.d.ts +3 -0
- package/dist/tools/spec/get_binding_rules.js +8 -0
- package/dist/tools/spec/get_data_source.d.ts +3 -0
- package/dist/tools/spec/get_data_source.js +41 -0
- package/dist/tools/spec/get_modifier_order.d.ts +3 -0
- package/dist/tools/spec/get_modifier_order.js +14 -0
- package/dist/tools/spec/get_platform_mapping.d.ts +3 -0
- package/dist/tools/spec/get_platform_mapping.js +20 -0
- package/dist/tools/spec/get_screen_identity.d.ts +3 -0
- package/dist/tools/spec/get_screen_identity.js +22 -0
- package/dist/tools/spec/lookup_attribute.d.ts +3 -0
- package/dist/tools/spec/lookup_attribute.js +14 -0
- package/dist/tools/spec/lookup_component.d.ts +3 -0
- package/dist/tools/spec/lookup_component.js +15 -0
- package/dist/tools/spec/search_components.d.ts +3 -0
- package/dist/tools/spec/search_components.js +14 -0
- package/dist/tools/test/test_artifacts_pull.d.ts +3 -0
- package/dist/tools/test/test_artifacts_pull.js +48 -0
- package/dist/tools/test/test_artifacts_status.d.ts +3 -0
- package/dist/tools/test/test_artifacts_status.js +28 -0
- package/dist/tools/test/test_generate_description.d.ts +3 -0
- package/dist/tools/test/test_generate_description.js +27 -0
- package/dist/tools/test/test_generate_flow.d.ts +3 -0
- package/dist/tools/test/test_generate_flow.js +29 -0
- package/dist/tools/test/test_generate_screen.d.ts +3 -0
- package/dist/tools/test/test_generate_screen.js +29 -0
- package/dist/tools/test/test_mock_generate.d.ts +3 -0
- package/dist/tools/test/test_mock_generate.js +64 -0
- package/dist/tools/test/test_report.d.ts +3 -0
- package/dist/tools/test/test_report.js +26 -0
- package/dist/tools/test/test_validate.d.ts +3 -0
- package/dist/tools/test/test_validate.js +43 -0
- package/docs/design.md +227 -0
- package/install.sh +90 -0
- package/package.json +24 -0
- package/scripts/fetch-definitions.js +101 -0
- package/scripts/fetch-manifest.js +60 -0
- package/src/cli_runner.ts +55 -0
- package/src/config.ts +88 -0
- package/src/data/derived.ts +305 -0
- package/src/index.ts +157 -0
- package/src/spec_loader.ts +591 -0
- package/src/tools/api/list_api_models.ts +44 -0
- package/src/tools/api/list_api_specs.ts +53 -0
- package/src/tools/api/preview_api_model_sync.ts +41 -0
- package/src/tools/context/get_project_config.ts +27 -0
- package/src/tools/context/list_component_specs.ts +44 -0
- package/src/tools/context/list_layouts.ts +131 -0
- package/src/tools/context/list_screen_specs.ts +46 -0
- package/src/tools/context/read_layout_file.ts +35 -0
- package/src/tools/context/read_spec_file.ts +38 -0
- package/src/tools/doc/doc_generate_component.ts +43 -0
- package/src/tools/doc/doc_generate_html.ts +40 -0
- package/src/tools/doc/doc_generate_spec.ts +43 -0
- package/src/tools/doc/doc_init_component.ts +32 -0
- package/src/tools/doc/doc_init_spec.ts +37 -0
- package/src/tools/doc/doc_rules_init.ts +29 -0
- package/src/tools/doc/doc_rules_show.ts +27 -0
- package/src/tools/doc/doc_validate_component.ts +47 -0
- package/src/tools/doc/doc_validate_spec.ts +48 -0
- package/src/tools/jui/jui_build.ts +31 -0
- package/src/tools/jui/jui_generate_converter.ts +41 -0
- package/src/tools/jui/jui_generate_project.ts +37 -0
- package/src/tools/jui/jui_generate_screen.ts +28 -0
- package/src/tools/jui/jui_init.ts +38 -0
- package/src/tools/jui/jui_migrate_layouts.ts +29 -0
- package/src/tools/jui/jui_sync_tool.ts +33 -0
- package/src/tools/jui/jui_verify.ts +43 -0
- package/src/tools/spec/get_binding_rules.ts +16 -0
- package/src/tools/spec/get_data_source.ts +53 -0
- package/src/tools/spec/get_modifier_order.ts +22 -0
- package/src/tools/spec/get_platform_mapping.ts +28 -0
- package/src/tools/spec/get_screen_identity.ts +31 -0
- package/src/tools/spec/lookup_attribute.ts +22 -0
- package/src/tools/spec/lookup_component.ts +23 -0
- package/src/tools/spec/search_components.ts +22 -0
- package/src/tools/test/test_artifacts_pull.ts +47 -0
- package/src/tools/test/test_artifacts_status.ts +34 -0
- package/src/tools/test/test_generate_description.ts +33 -0
- package/src/tools/test/test_generate_flow.ts +33 -0
- package/src/tools/test/test_generate_screen.ts +33 -0
- package/src/tools/test/test_mock_generate.ts +58 -0
- package/src/tools/test/test_report.ts +32 -0
- package/src/tools/test/test_validate.ts +43 -0
- package/tests/__snapshots__/derived.test.ts.snap +279 -0
- package/tests/bundled_snapshot.test.ts +155 -0
- package/tests/cli_runner.test.ts +120 -0
- package/tests/config.test.ts +212 -0
- package/tests/derived.test.ts +114 -0
- package/tests/helpers.ts +272 -0
- package/tests/setup.ts +27 -0
- package/tests/snapshot_completeness.test.ts +152 -0
- package/tests/spec_loader.test.ts +488 -0
- package/tests/tools_cli.test.ts +687 -0
- package/tests/tools_context.test.ts +274 -0
- package/tests/tools_spec.test.ts +225 -0
- package/tests/tools_test.test.ts +284 -0
- package/tsconfig.json +15 -0
- package/uninstall.sh +46 -0
- package/vitest.config.ts +15 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-component metadata that augments the raw attribute definitions from
|
|
3
|
+
* jsonui-cli/shared/core/attribute_definitions.json.
|
|
4
|
+
*
|
|
5
|
+
* This file holds MCP-presentation facts that do NOT live in attribute_definitions.json:
|
|
6
|
+
* - Human descriptions, aliases
|
|
7
|
+
* - Which platforms generate this component (swift_generated / swift_dynamic / ...)
|
|
8
|
+
* - Which attributes carry two-way bindings (vs. read-only)
|
|
9
|
+
* - Platform-specific implementation notes
|
|
10
|
+
* - Agent-facing prose rules
|
|
11
|
+
*
|
|
12
|
+
* Ported from scripts/generate_specs.py's COMPONENT_METADATA dict.
|
|
13
|
+
* Once jsonui-cli absorbs this schema (Phase B/C of agent-redesign.md), this file shrinks.
|
|
14
|
+
*/
|
|
15
|
+
export interface ComponentMetadata {
|
|
16
|
+
description: string;
|
|
17
|
+
aliases: string[];
|
|
18
|
+
platforms: {
|
|
19
|
+
swift_generated: boolean;
|
|
20
|
+
swift_dynamic: boolean;
|
|
21
|
+
kotlin_generated: boolean;
|
|
22
|
+
kotlin_dynamic: boolean;
|
|
23
|
+
react: boolean;
|
|
24
|
+
};
|
|
25
|
+
twoWayBindings: string[];
|
|
26
|
+
platformSpecific: Record<string, Record<string, string>>;
|
|
27
|
+
rules: string[];
|
|
28
|
+
}
|
|
29
|
+
export declare const COMPONENT_METADATA: Record<string, ComponentMetadata>;
|
|
30
|
+
export declare function getMetadata(componentName: string): ComponentMetadata;
|
|
@@ -0,0 +1,498 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-component metadata that augments the raw attribute definitions from
|
|
3
|
+
* jsonui-cli/shared/core/attribute_definitions.json.
|
|
4
|
+
*
|
|
5
|
+
* This file holds MCP-presentation facts that do NOT live in attribute_definitions.json:
|
|
6
|
+
* - Human descriptions, aliases
|
|
7
|
+
* - Which platforms generate this component (swift_generated / swift_dynamic / ...)
|
|
8
|
+
* - Which attributes carry two-way bindings (vs. read-only)
|
|
9
|
+
* - Platform-specific implementation notes
|
|
10
|
+
* - Agent-facing prose rules
|
|
11
|
+
*
|
|
12
|
+
* Ported from scripts/generate_specs.py's COMPONENT_METADATA dict.
|
|
13
|
+
* Once jsonui-cli absorbs this schema (Phase B/C of agent-redesign.md), this file shrinks.
|
|
14
|
+
*/
|
|
15
|
+
const allPlatforms = {
|
|
16
|
+
swift_generated: true,
|
|
17
|
+
swift_dynamic: true,
|
|
18
|
+
kotlin_generated: true,
|
|
19
|
+
kotlin_dynamic: true,
|
|
20
|
+
react: true,
|
|
21
|
+
};
|
|
22
|
+
export const COMPONENT_METADATA = {
|
|
23
|
+
Label: {
|
|
24
|
+
description: "Text display component",
|
|
25
|
+
aliases: ["Text"],
|
|
26
|
+
platforms: allPlatforms,
|
|
27
|
+
twoWayBindings: [],
|
|
28
|
+
platformSpecific: {
|
|
29
|
+
swift: {
|
|
30
|
+
view: "Text",
|
|
31
|
+
partialAttributes: "Supports styled text ranges via partialAttributes array",
|
|
32
|
+
alignment: ".leading alignment added to frame for textAlign to work",
|
|
33
|
+
},
|
|
34
|
+
kotlin: {
|
|
35
|
+
composable: "Text",
|
|
36
|
+
partialAttributes: "AnnotatedString with SpanStyle for styled ranges",
|
|
37
|
+
},
|
|
38
|
+
react: {
|
|
39
|
+
element: "<span>",
|
|
40
|
+
lineClamping: "lines:1 -> truncate, lines:2+ -> line-clamp-N",
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
rules: [
|
|
44
|
+
"text attribute supports interpolation with @{binding} syntax",
|
|
45
|
+
"partialAttributes allows styling ranges within text",
|
|
46
|
+
"linkable enables auto-detection of URLs",
|
|
47
|
+
"Frame alignment must be .leading for textAlign to work correctly (Swift)",
|
|
48
|
+
],
|
|
49
|
+
},
|
|
50
|
+
TextField: {
|
|
51
|
+
description: "Text input field",
|
|
52
|
+
aliases: ["EditText", "Input"],
|
|
53
|
+
platforms: allPlatforms,
|
|
54
|
+
twoWayBindings: ["text"],
|
|
55
|
+
platformSpecific: {
|
|
56
|
+
swift: {
|
|
57
|
+
view: "TextField / SecureField (when input='password')",
|
|
58
|
+
focusManagement: "@FocusState variable generated, nextFocusId for chain",
|
|
59
|
+
caretColor: "tintColor or caretAttributes.color",
|
|
60
|
+
},
|
|
61
|
+
kotlin: {
|
|
62
|
+
composable: "OutlinedTextField / BasicTextField",
|
|
63
|
+
focusManagement: "FocusManager.requestFocus(nextFocusId)",
|
|
64
|
+
inputType: "KeyboardOptions based on contentType/input",
|
|
65
|
+
},
|
|
66
|
+
react: {
|
|
67
|
+
element: "<input type=\"...\"/>",
|
|
68
|
+
autoHandler: "text binding auto-generates onPropChange handler",
|
|
69
|
+
inputMapping: "email->email, password->password, number->number, phone->tel",
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
rules: [
|
|
73
|
+
"input='password' switches to SecureField in SwiftUI",
|
|
74
|
+
"fieldId + nextFocusId creates focus chain across fields",
|
|
75
|
+
"text binding MUST be two-way ($data. in Swift)",
|
|
76
|
+
"React auto-generates onXxxChange from text binding",
|
|
77
|
+
],
|
|
78
|
+
},
|
|
79
|
+
Button: {
|
|
80
|
+
description: "Tappable button component",
|
|
81
|
+
aliases: [],
|
|
82
|
+
platforms: allPlatforms,
|
|
83
|
+
twoWayBindings: [],
|
|
84
|
+
platformSpecific: {
|
|
85
|
+
swift: {
|
|
86
|
+
view: "StateAwareButtonView (not plain Button+Text)",
|
|
87
|
+
asyncSupport: "isAsync flag for async operations with loading state",
|
|
88
|
+
},
|
|
89
|
+
kotlin: {
|
|
90
|
+
composable: "Button with Text content",
|
|
91
|
+
asyncSupport: "isAsync with CoroutineScope(Dispatchers.Main)",
|
|
92
|
+
},
|
|
93
|
+
react: {
|
|
94
|
+
element: "<button> or <Link><button> (Next.js navigation)",
|
|
95
|
+
stateStyles: "hover/active/disabled via Tailwind prefixes",
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
rules: [
|
|
99
|
+
"Uses StateAwareButtonView in Swift (not plain Text+Button)",
|
|
100
|
+
"Width/height are passed to view for background fill",
|
|
101
|
+
"onclick (lowercase) = selector format, onClick (camelCase) = binding format",
|
|
102
|
+
"Supports async operations with loading state and spinner",
|
|
103
|
+
],
|
|
104
|
+
},
|
|
105
|
+
Image: {
|
|
106
|
+
description: "Local image component",
|
|
107
|
+
aliases: [],
|
|
108
|
+
platforms: allPlatforms,
|
|
109
|
+
twoWayBindings: [],
|
|
110
|
+
platformSpecific: {
|
|
111
|
+
swift: {
|
|
112
|
+
view: "Image (with .resizable().aspectRatio())",
|
|
113
|
+
priority: "srcName > src > defaultImage",
|
|
114
|
+
circleImage: "type='CircleImage' adds .clipShape(Circle())",
|
|
115
|
+
},
|
|
116
|
+
kotlin: {
|
|
117
|
+
composable: "Image with painterResource",
|
|
118
|
+
contentScale: "ContentScale.Fit/Crop/FillBounds",
|
|
119
|
+
},
|
|
120
|
+
react: {
|
|
121
|
+
element: "<img/>",
|
|
122
|
+
objectFit: "aspectfit->contain, aspectfill->cover, scaletofill->fill",
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
rules: [
|
|
126
|
+
".resizable() must come first, then .aspectRatio (Swift)",
|
|
127
|
+
"CircleImage type adds circular clipping",
|
|
128
|
+
"contentMode maps differently per platform",
|
|
129
|
+
],
|
|
130
|
+
},
|
|
131
|
+
NetworkImage: {
|
|
132
|
+
description: "Remote/network image component",
|
|
133
|
+
aliases: [],
|
|
134
|
+
platforms: allPlatforms,
|
|
135
|
+
twoWayBindings: [],
|
|
136
|
+
platformSpecific: {
|
|
137
|
+
swift: {
|
|
138
|
+
view: "AsyncImage or custom NetworkImageView",
|
|
139
|
+
defaultContentMode: ".center for matchParent",
|
|
140
|
+
},
|
|
141
|
+
kotlin: { composable: "AsyncImage (Coil)" },
|
|
142
|
+
react: { element: "<img/> with src binding" },
|
|
143
|
+
},
|
|
144
|
+
rules: [
|
|
145
|
+
"Default contentMode is .center for matchParent (Swift)",
|
|
146
|
+
"Supports placeholder/error images via defaultImage",
|
|
147
|
+
],
|
|
148
|
+
},
|
|
149
|
+
View: {
|
|
150
|
+
description: "Container view (HStack/VStack/ZStack)",
|
|
151
|
+
aliases: [],
|
|
152
|
+
platforms: allPlatforms,
|
|
153
|
+
twoWayBindings: [],
|
|
154
|
+
platformSpecific: {
|
|
155
|
+
swift: {
|
|
156
|
+
view: "HStack/VStack/ZStack based on orientation",
|
|
157
|
+
weightedChildren: "Special body splitting for weighted layouts",
|
|
158
|
+
relativePositioning: "ZStack with alignment for relative layouts",
|
|
159
|
+
},
|
|
160
|
+
kotlin: {
|
|
161
|
+
composable: "Row/Column/Box based on orientation",
|
|
162
|
+
relativePositioning: "ConstraintLayout if children have alignXyzOfView",
|
|
163
|
+
},
|
|
164
|
+
react: {
|
|
165
|
+
element: "<div> with flex classes",
|
|
166
|
+
orientation: "horizontal->flex-row, vertical->flex-col, none->relative",
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
rules: [
|
|
170
|
+
"orientation determines layout: horizontal->HStack/Row, vertical->VStack/Column, none->ZStack/Box",
|
|
171
|
+
"Children with alignXyzOfView trigger relative/constraint layout",
|
|
172
|
+
"bottomToTop/rightToLeft reverses child order",
|
|
173
|
+
"distribution: fillEqually/fill/equalSpacing affects child arrangement",
|
|
174
|
+
],
|
|
175
|
+
},
|
|
176
|
+
ScrollView: {
|
|
177
|
+
description: "Scrollable container",
|
|
178
|
+
aliases: [],
|
|
179
|
+
platforms: allPlatforms,
|
|
180
|
+
twoWayBindings: [],
|
|
181
|
+
platformSpecific: {
|
|
182
|
+
swift: { view: "ScrollView(.horizontal/.vertical)" },
|
|
183
|
+
kotlin: { composable: "LazyColumn/LazyRow or verticalScroll/horizontalScroll" },
|
|
184
|
+
react: { element: "<div> with overflow-auto/scroll" },
|
|
185
|
+
},
|
|
186
|
+
rules: [
|
|
187
|
+
"orientation determines scroll direction",
|
|
188
|
+
"showsIndicator controls scrollbar visibility",
|
|
189
|
+
],
|
|
190
|
+
},
|
|
191
|
+
Collection: {
|
|
192
|
+
description: "List/grid collection with data binding",
|
|
193
|
+
aliases: [],
|
|
194
|
+
platforms: allPlatforms,
|
|
195
|
+
twoWayBindings: [],
|
|
196
|
+
platformSpecific: {
|
|
197
|
+
swift: {
|
|
198
|
+
view: "LazyVStack/LazyHStack for performance",
|
|
199
|
+
sections: "Section-based with headers/footers",
|
|
200
|
+
flowLayout: "Flow layout support",
|
|
201
|
+
},
|
|
202
|
+
kotlin: {
|
|
203
|
+
composable: "LazyColumn/LazyRow/LazyVerticalGrid",
|
|
204
|
+
sections: "Section-based with column count per section",
|
|
205
|
+
},
|
|
206
|
+
react: {
|
|
207
|
+
element: "map() with component references",
|
|
208
|
+
cellFormat: "sections[].cell or cellClasses for component routing",
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
rules: [
|
|
212
|
+
"items binding connects to data source array",
|
|
213
|
+
"Sections support different cell types per section",
|
|
214
|
+
"cellIdProperty extracts unique keys from item data",
|
|
215
|
+
"scrollTo binding enables programmatic scrolling",
|
|
216
|
+
],
|
|
217
|
+
},
|
|
218
|
+
Switch: {
|
|
219
|
+
description: "Toggle switch (iOS style)",
|
|
220
|
+
aliases: [],
|
|
221
|
+
platforms: allPlatforms,
|
|
222
|
+
twoWayBindings: ["isOn", "value", "checked", "bind"],
|
|
223
|
+
platformSpecific: {
|
|
224
|
+
swift: { view: "Toggle with switch style" },
|
|
225
|
+
kotlin: { composable: "Switch" },
|
|
226
|
+
react: { element: "Hidden checkbox + styled span (iOS-style toggle)" },
|
|
227
|
+
},
|
|
228
|
+
rules: [
|
|
229
|
+
"State binding priority: isOn > value > checked > bind",
|
|
230
|
+
"Two-way binding updates via $data. (Swift) or updateData (Kotlin)",
|
|
231
|
+
"onValueChange/onToggle for state change callback",
|
|
232
|
+
],
|
|
233
|
+
},
|
|
234
|
+
Toggle: {
|
|
235
|
+
description: "Toggle control (checkbox style)",
|
|
236
|
+
aliases: [],
|
|
237
|
+
platforms: allPlatforms,
|
|
238
|
+
twoWayBindings: ["isOn", "value", "checked", "bind"],
|
|
239
|
+
platformSpecific: {
|
|
240
|
+
swift: { view: "Toggle" },
|
|
241
|
+
kotlin: { composable: "Checkbox or Switch" },
|
|
242
|
+
react: { element: "<input type=\"checkbox\">" },
|
|
243
|
+
},
|
|
244
|
+
rules: [
|
|
245
|
+
"Similar to Switch but may render differently per platform",
|
|
246
|
+
"State binding priority: isOn > value > checked > bind",
|
|
247
|
+
],
|
|
248
|
+
},
|
|
249
|
+
CheckBox: {
|
|
250
|
+
description: "Checkbox input",
|
|
251
|
+
aliases: ["Check", "Checkbox"],
|
|
252
|
+
platforms: allPlatforms,
|
|
253
|
+
twoWayBindings: ["checked", "isOn", "value", "bind"],
|
|
254
|
+
platformSpecific: {
|
|
255
|
+
swift: { view: "Toggle with checkbox style" },
|
|
256
|
+
kotlin: { composable: "Checkbox or IconToggleButton (custom icons)" },
|
|
257
|
+
react: { element: "<input type=\"checkbox\">" },
|
|
258
|
+
},
|
|
259
|
+
rules: [
|
|
260
|
+
"Kotlin supports custom icon/selectedIcon via IconToggleButton",
|
|
261
|
+
"checked is primary binding attribute",
|
|
262
|
+
],
|
|
263
|
+
},
|
|
264
|
+
Radio: {
|
|
265
|
+
description: "Radio button group",
|
|
266
|
+
aliases: [],
|
|
267
|
+
platforms: allPlatforms,
|
|
268
|
+
twoWayBindings: ["selectedIndex"],
|
|
269
|
+
platformSpecific: {
|
|
270
|
+
swift: { view: "Custom radio button implementation" },
|
|
271
|
+
kotlin: { composable: "RadioButton in Row/Column" },
|
|
272
|
+
react: { element: "<input type=\"radio\">" },
|
|
273
|
+
},
|
|
274
|
+
rules: ["selectedIndex tracks currently selected option"],
|
|
275
|
+
},
|
|
276
|
+
SelectBox: {
|
|
277
|
+
description: "Dropdown/picker selection",
|
|
278
|
+
aliases: [],
|
|
279
|
+
platforms: allPlatforms,
|
|
280
|
+
twoWayBindings: ["selectedIndex"],
|
|
281
|
+
platformSpecific: {
|
|
282
|
+
swift: { view: "Picker" },
|
|
283
|
+
kotlin: { composable: "ExposedDropdownMenuBox" },
|
|
284
|
+
react: { element: "<select>" },
|
|
285
|
+
},
|
|
286
|
+
rules: ["selectedIndex tracks currently selected option"],
|
|
287
|
+
},
|
|
288
|
+
Segment: {
|
|
289
|
+
description: "Segmented control",
|
|
290
|
+
aliases: [],
|
|
291
|
+
platforms: allPlatforms,
|
|
292
|
+
twoWayBindings: ["selectedIndex"],
|
|
293
|
+
platformSpecific: {
|
|
294
|
+
swift: { view: "Picker with segmented style" },
|
|
295
|
+
kotlin: { composable: "TabRow or custom segment" },
|
|
296
|
+
react: { element: "Button group with useState for selectedIndex" },
|
|
297
|
+
},
|
|
298
|
+
rules: [
|
|
299
|
+
"Without binding, React auto-generates useState for selectedIndex",
|
|
300
|
+
"selectedIndex tracks active segment",
|
|
301
|
+
],
|
|
302
|
+
},
|
|
303
|
+
Slider: {
|
|
304
|
+
description: "Slider/range input",
|
|
305
|
+
aliases: [],
|
|
306
|
+
platforms: allPlatforms,
|
|
307
|
+
twoWayBindings: ["value", "bind"],
|
|
308
|
+
platformSpecific: {
|
|
309
|
+
swift: { view: "Slider" },
|
|
310
|
+
kotlin: { composable: "Slider with step calculation" },
|
|
311
|
+
react: { element: "<input type=\"range\">" },
|
|
312
|
+
},
|
|
313
|
+
rules: [
|
|
314
|
+
"value/bind is two-way binding",
|
|
315
|
+
"minimumValue/maximumValue define range (default 0-100)",
|
|
316
|
+
"step defines discrete steps",
|
|
317
|
+
],
|
|
318
|
+
},
|
|
319
|
+
Progress: {
|
|
320
|
+
description: "Progress bar/indicator",
|
|
321
|
+
aliases: [],
|
|
322
|
+
platforms: allPlatforms,
|
|
323
|
+
twoWayBindings: [],
|
|
324
|
+
platformSpecific: {
|
|
325
|
+
swift: { view: "ProgressView" },
|
|
326
|
+
kotlin: { composable: "LinearProgressIndicator / CircularProgressIndicator" },
|
|
327
|
+
react: { element: "<progress> or <div> with width percentage" },
|
|
328
|
+
},
|
|
329
|
+
rules: ["value represents progress (0.0 to 1.0)"],
|
|
330
|
+
},
|
|
331
|
+
Indicator: {
|
|
332
|
+
description: "Activity indicator / loading spinner",
|
|
333
|
+
aliases: [],
|
|
334
|
+
platforms: allPlatforms,
|
|
335
|
+
twoWayBindings: [],
|
|
336
|
+
platformSpecific: {
|
|
337
|
+
swift: { view: "ProgressView (indeterminate)" },
|
|
338
|
+
kotlin: { composable: "CircularProgressIndicator" },
|
|
339
|
+
react: { element: "Animated spinner div" },
|
|
340
|
+
},
|
|
341
|
+
rules: [],
|
|
342
|
+
},
|
|
343
|
+
CircleView: {
|
|
344
|
+
description: "Circular shape view",
|
|
345
|
+
aliases: [],
|
|
346
|
+
platforms: allPlatforms,
|
|
347
|
+
twoWayBindings: [],
|
|
348
|
+
platformSpecific: {
|
|
349
|
+
swift: { view: "Circle()" },
|
|
350
|
+
kotlin: { composable: "Box with CircleShape clip" },
|
|
351
|
+
react: { element: "<div> with rounded-full" },
|
|
352
|
+
},
|
|
353
|
+
rules: [],
|
|
354
|
+
},
|
|
355
|
+
GradientView: {
|
|
356
|
+
description: "Gradient background view",
|
|
357
|
+
aliases: [],
|
|
358
|
+
platforms: allPlatforms,
|
|
359
|
+
twoWayBindings: [],
|
|
360
|
+
platformSpecific: {
|
|
361
|
+
swift: { view: "LinearGradient / RadialGradient" },
|
|
362
|
+
kotlin: { composable: "Brush.linearGradient / radialGradient" },
|
|
363
|
+
react: { element: "<div> with background: linear-gradient(...)" },
|
|
364
|
+
},
|
|
365
|
+
rules: ["colors array defines gradient stops"],
|
|
366
|
+
},
|
|
367
|
+
Blur: {
|
|
368
|
+
description: "Blur effect view",
|
|
369
|
+
aliases: [],
|
|
370
|
+
platforms: {
|
|
371
|
+
swift_generated: true,
|
|
372
|
+
swift_dynamic: true,
|
|
373
|
+
kotlin_generated: false,
|
|
374
|
+
kotlin_dynamic: false,
|
|
375
|
+
react: true,
|
|
376
|
+
},
|
|
377
|
+
twoWayBindings: [],
|
|
378
|
+
platformSpecific: {
|
|
379
|
+
swift: { view: ".blur() modifier or UIVisualEffectView" },
|
|
380
|
+
react: { element: "<div> with backdrop-blur class" },
|
|
381
|
+
},
|
|
382
|
+
rules: [],
|
|
383
|
+
},
|
|
384
|
+
IconLabel: {
|
|
385
|
+
description: "Icon with label combination",
|
|
386
|
+
aliases: [],
|
|
387
|
+
platforms: allPlatforms,
|
|
388
|
+
twoWayBindings: [],
|
|
389
|
+
platformSpecific: {
|
|
390
|
+
swift: { view: "Label with systemImage" },
|
|
391
|
+
kotlin: { composable: "Row with Icon + Text" },
|
|
392
|
+
react: { element: "<span> with icon + text" },
|
|
393
|
+
},
|
|
394
|
+
rules: [],
|
|
395
|
+
},
|
|
396
|
+
Web: {
|
|
397
|
+
description: "Web view / embedded browser",
|
|
398
|
+
aliases: [],
|
|
399
|
+
platforms: allPlatforms,
|
|
400
|
+
twoWayBindings: [],
|
|
401
|
+
platformSpecific: {
|
|
402
|
+
swift: { view: "WKWebView wrapper" },
|
|
403
|
+
kotlin: { composable: "AndroidView with WebView" },
|
|
404
|
+
react: { element: "<iframe>" },
|
|
405
|
+
},
|
|
406
|
+
rules: ["url attribute specifies the web page to load"],
|
|
407
|
+
},
|
|
408
|
+
SafeAreaView: {
|
|
409
|
+
description: "Safe area respecting container",
|
|
410
|
+
aliases: [],
|
|
411
|
+
platforms: {
|
|
412
|
+
swift_generated: true,
|
|
413
|
+
swift_dynamic: true,
|
|
414
|
+
kotlin_generated: true,
|
|
415
|
+
kotlin_dynamic: true,
|
|
416
|
+
react: false,
|
|
417
|
+
},
|
|
418
|
+
twoWayBindings: [],
|
|
419
|
+
platformSpecific: {
|
|
420
|
+
swift: { view: "Respects safeAreaInsets" },
|
|
421
|
+
kotlin: { composable: "Respects WindowInsets" },
|
|
422
|
+
},
|
|
423
|
+
rules: ["Ensures content doesn't overlap with system UI"],
|
|
424
|
+
},
|
|
425
|
+
TabView: {
|
|
426
|
+
description: "Tab-based navigation container",
|
|
427
|
+
aliases: [],
|
|
428
|
+
platforms: allPlatforms,
|
|
429
|
+
twoWayBindings: ["selectedIndex"],
|
|
430
|
+
platformSpecific: {
|
|
431
|
+
swift: { view: "TabView with tag-based selection" },
|
|
432
|
+
kotlin: { composable: "Scaffold with BottomNavigation" },
|
|
433
|
+
react: { element: "Tab buttons + conditional content rendering" },
|
|
434
|
+
},
|
|
435
|
+
rules: ["Each tab child uses tag for identification"],
|
|
436
|
+
},
|
|
437
|
+
TextView: {
|
|
438
|
+
description: "Multi-line text input",
|
|
439
|
+
aliases: [],
|
|
440
|
+
platforms: allPlatforms,
|
|
441
|
+
twoWayBindings: ["text"],
|
|
442
|
+
platformSpecific: {
|
|
443
|
+
swift: { view: "TextEditor" },
|
|
444
|
+
kotlin: { composable: "OutlinedTextField with multiline" },
|
|
445
|
+
react: { element: "<textarea>" },
|
|
446
|
+
},
|
|
447
|
+
rules: [
|
|
448
|
+
"text binding is two-way",
|
|
449
|
+
"Multi-line input (unlike TextField which is single-line by default)",
|
|
450
|
+
],
|
|
451
|
+
},
|
|
452
|
+
EditText: {
|
|
453
|
+
description: "Text input (Android naming convention)",
|
|
454
|
+
aliases: [],
|
|
455
|
+
platforms: {
|
|
456
|
+
swift_generated: false,
|
|
457
|
+
swift_dynamic: false,
|
|
458
|
+
kotlin_generated: true,
|
|
459
|
+
kotlin_dynamic: true,
|
|
460
|
+
react: false,
|
|
461
|
+
},
|
|
462
|
+
twoWayBindings: ["text"],
|
|
463
|
+
platformSpecific: {
|
|
464
|
+
kotlin: { composable: "OutlinedTextField" },
|
|
465
|
+
},
|
|
466
|
+
rules: ["Android-specific alias for TextField functionality"],
|
|
467
|
+
},
|
|
468
|
+
Input: {
|
|
469
|
+
description: "Generic input (React naming convention)",
|
|
470
|
+
aliases: [],
|
|
471
|
+
platforms: {
|
|
472
|
+
swift_generated: false,
|
|
473
|
+
swift_dynamic: false,
|
|
474
|
+
kotlin_generated: false,
|
|
475
|
+
kotlin_dynamic: false,
|
|
476
|
+
react: true,
|
|
477
|
+
},
|
|
478
|
+
twoWayBindings: ["value"],
|
|
479
|
+
platformSpecific: {
|
|
480
|
+
react: { element: "<input>" },
|
|
481
|
+
},
|
|
482
|
+
rules: ["React-specific input component"],
|
|
483
|
+
},
|
|
484
|
+
};
|
|
485
|
+
const DEFAULT_METADATA = {
|
|
486
|
+
description: "",
|
|
487
|
+
aliases: [],
|
|
488
|
+
platforms: allPlatforms,
|
|
489
|
+
twoWayBindings: [],
|
|
490
|
+
platformSpecific: {},
|
|
491
|
+
rules: [],
|
|
492
|
+
};
|
|
493
|
+
export function getMetadata(componentName) {
|
|
494
|
+
return COMPONENT_METADATA[componentName] ?? {
|
|
495
|
+
...DEFAULT_METADATA,
|
|
496
|
+
description: `${componentName} component`,
|
|
497
|
+
};
|
|
498
|
+
}
|