-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathFilledTextInputRenderer.kt
More file actions
147 lines (139 loc) · 6.72 KB
/
Copy pathFilledTextInputRenderer.kt
File metadata and controls
147 lines (139 loc) · 6.72 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
package com.nativephp.plugins.native_ui.ui
import androidx.compose.foundation.interaction.FocusInteraction
import androidx.compose.foundation.interaction.Interaction
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.dp
import com.nativephp.mobile.ui.nativerender.NativeUINode
import com.nativephp.plugins.native_ui.NativeUITheme
/**
* Material3 filled text field.
*
* Higher emphasis than outlined — tonal surface fill with a bottom accent
* indicator. Best for forms where inputs need to stand out.
*
* Shares prop parsing + the echo-prevention value sync (plan K) with the
* outlined variant via [parseTextInputProps].
*/
object FilledTextInputRenderer {
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun Render(node: NativeUINode, modifier: Modifier) {
val props = parseTextInputProps(node)
val theme = if (isSystemInDarkTheme()) NativeUITheme.dark else NativeUITheme.light
val scope = rememberCoroutineScope()
var text by remember { mutableStateOf(props.serverValue) }
var lastSentValue by remember { mutableStateOf(props.serverValue) }
LaunchedEffect(props.serverValue) {
if (props.serverValue != lastSentValue) {
text = props.serverValue
lastSentValue = props.serverValue
}
}
val dispatcher = remember(props.syncMode, props.debounceMs, props.onChangeCb) {
TextInputDispatcher(
scope = scope,
props = props,
nodeId = node.id,
setLastSent = { lastSentValue = it },
getLastSent = { lastSentValue },
)
}
val interactionSource = remember { MutableInteractionSource() }
LaunchedEffect(interactionSource) {
val focusStack = mutableListOf<FocusInteraction.Focus>()
interactionSource.interactions.collect { interaction: Interaction ->
when (interaction) {
is FocusInteraction.Focus -> focusStack += interaction
is FocusInteraction.Unfocus -> {
focusStack.remove(interaction.focus)
if (focusStack.isEmpty()) dispatcher.onBlur(text)
}
else -> { /* ignore */ }
}
}
}
val textSize = when (props.size) {
"sm" -> theme.fontSm
"lg" -> theme.fontLg
else -> theme.fontMd
}
TextField(
value = text,
onValueChange = { new ->
val filtered = if (props.maxLength > 0) new.take(props.maxLength) else new
text = filtered
dispatcher.onTextChanged(filtered)
},
// Full width by default (parity with the iOS renderer's
// maxWidth: .infinity); an explicit width in `modifier` (FIXED
// layout mode) still wins since it comes later in the chain.
modifier = Modifier.fillMaxWidth().then(modifier).nuiA11y(props.a11yLabel, props.a11yHint),
enabled = props.enabled,
readOnly = props.readOnly,
interactionSource = interactionSource,
label = labelSlot(props.label),
placeholder = placeholderSlot(props.placeholder),
supportingText = supportingSlot(props.supporting),
prefix = prefixSlot(props.prefix),
suffix = suffixSlot(props.suffix),
leadingIcon = leadingIconSlot(props.leadingIcon),
trailingIcon = if (props.loading) {
{ CircularProgressIndicator(modifier = Modifier.size(18.dp), strokeWidth = 2.dp, color = theme.onSurfaceVariant) }
} else trailingIconSlot(props.trailingIcon),
isError = props.isError,
singleLine = props.singleLine,
maxLines = props.maxLines,
minLines = props.minLines,
visualTransformation = props.visualTransformation,
keyboardOptions = keyboardOptionsFor(props),
keyboardActions = KeyboardActions(onDone = { dispatcher.onSubmit(text) }),
textStyle = TextStyle(fontSize = textSize, color = theme.onSurface),
colors = TextFieldDefaults.colors(
focusedTextColor = theme.onSurface,
unfocusedTextColor = theme.onSurface,
disabledTextColor = theme.onSurface.copy(alpha = 0.6f),
errorTextColor = theme.onSurface,
cursorColor = theme.primary,
errorCursorColor = theme.destructive,
focusedContainerColor = theme.surfaceVariant,
unfocusedContainerColor = theme.surfaceVariant,
disabledContainerColor = theme.surfaceVariant.copy(alpha = 0.5f),
errorContainerColor = theme.surfaceVariant,
focusedIndicatorColor = theme.primary,
unfocusedIndicatorColor = theme.outline,
disabledIndicatorColor = theme.outline.copy(alpha = 0.5f),
errorIndicatorColor = theme.destructive,
focusedLabelColor = theme.primary,
unfocusedLabelColor = theme.onSurfaceVariant,
disabledLabelColor = theme.onSurfaceVariant.copy(alpha = 0.6f),
errorLabelColor = theme.destructive,
focusedPlaceholderColor = theme.onSurfaceVariant,
unfocusedPlaceholderColor = theme.onSurfaceVariant,
focusedSupportingTextColor = theme.onSurfaceVariant,
unfocusedSupportingTextColor = theme.onSurfaceVariant,
errorSupportingTextColor = theme.destructive,
focusedLeadingIconColor = theme.onSurfaceVariant,
unfocusedLeadingIconColor = theme.onSurfaceVariant,
focusedTrailingIconColor = theme.onSurfaceVariant,
unfocusedTrailingIconColor = theme.onSurfaceVariant,
),
)
}
}