1- import type { JSX } from "react"
1+ import React , { type JSX } from "react"
22
33import type { GridlandInputProps , GridlandModule } from "@gridland/bun"
44
@@ -12,57 +12,45 @@ const renderInputValue = (props: UiTextInputProps): string => {
1212}
1313
1414const inputProps = ( props : UiTextInputProps ) : GridlandInputProps => ( {
15- ariaLabel : props . ariaLabel ,
16- autoFocus : props . autoFocus ,
1715 placeholder : props . placeholder ,
1816 value : renderInputValue ( props )
1917} )
2018
21- export const createGridlandPrimitives = ( gridland : GridlandModule ) => {
22- const GridlandBox = gridland . Box
23- const GridlandInput = gridland . Input
24- const GridlandText = gridland . Text
25-
26- return {
27- Box : ( { children, ...props } : UiBoxProps ) : JSX . Element => (
28- < GridlandBox
29- alignItems = { props . alignItems }
30- backgroundColor = { props . backgroundColor }
31- border = { props . border }
32- borderColor = { props . borderColor }
33- borderStyle = { props . borderStyle }
34- color = { props . fg }
35- flexDirection = { props . flexDirection }
36- flexGrow = { props . flexGrow }
37- flexWrap = { props . flexWrap }
38- gap = { props . gap }
39- height = { props . height }
40- justifyContent = { props . justifyContent }
41- marginBottom = { props . marginBottom }
42- marginLeft = { props . marginLeft }
43- marginRight = { props . marginRight }
44- marginTop = { props . marginTop }
45- padding = { props . padding }
46- width = { props . width }
47- >
48- { children }
49- </ GridlandBox >
50- ) ,
51- Button : ( { label } : UiButtonProps ) : JSX . Element => < GridlandText color = "cyan" > [{ label } ]</ GridlandText > ,
52- Text : ( { children, ...props } : UiTextProps ) : JSX . Element => (
53- < GridlandText
54- bold = { props . bold }
55- color = { props . fg }
56- marginBottom = { props . marginBottom }
57- marginLeft = { props . marginLeft }
58- marginRight = { props . marginRight }
59- marginTop = { props . marginTop }
60- truncate = { props . wrap === "truncate" }
61- width = { props . width }
62- >
63- { children }
64- </ GridlandText >
65- ) ,
66- TextInput : ( props : UiTextInputProps ) : JSX . Element => < GridlandInput { ...inputProps ( props ) } />
67- } as const
68- }
19+ // CHANGE: render Gridland primitives through host component tags instead of helper functions
20+ // WHY: @gridland /bun helper functions return Gridland vnode objects, not React elements; using them as JSX
21+ // children causes React reconciliation to reject the returned object tree in the TTY menu runtime
22+ // QUOTE(ТЗ): "ЧТо бы я мог меню открыть"
23+ // REF: user-request-2026-04-13-gridland-menu-fix
24+ // SOURCE: n/a
25+ // FORMAT THEOREM: ∀p: hostTag(p) → reactElement(p) ∧ renderable(p)
26+ // PURITY: SHELL
27+ // EFFECT: n/a
28+ // INVARIANT: Gridland TUI primitives always return React elements with supported host tags
29+ // COMPLEXITY: O(1)
30+ export const createGridlandPrimitives = ( _gridland : GridlandModule ) => ( {
31+ Box : ( { children, ...props } : UiBoxProps ) : JSX . Element =>
32+ React . createElement ( "box" , {
33+ ...props ,
34+ children
35+ } ) ,
36+ Button : ( { label, onPress } : UiButtonProps ) : JSX . Element =>
37+ React . createElement ( "text" , {
38+ children : `[${ label } ]` ,
39+ fg : "cyan" ,
40+ onClick : onPress
41+ } ) ,
42+ Text : ( { children, ...props } : UiTextProps ) : JSX . Element =>
43+ React . createElement ( "text" , {
44+ ...props ,
45+ children
46+ } ) ,
47+ TextInput : ( props : UiTextInputProps ) : JSX . Element =>
48+ React . createElement ( "input" , {
49+ ...inputProps ( props ) ,
50+ focused : props . autoFocus ,
51+ onChange : props . onChange ,
52+ onSubmit : ( ) => {
53+ props . onEnter ?.( false )
54+ }
55+ } )
56+ } ) as const
0 commit comments