Open hlayan opened 5 months ago
Thanks for the feedback. That's right, currently, there is no onValueChange
callback.
The main reason is that the Chip
class also holds a TextFieldValue
and a FocusInteraction.Focus
, so it may not be a good idea to maintain these ui states in ViewModel
in my opinion.
But if you need the UDF pattern or TextField
like API, you can create a wrapper to sync chips between the view model and the UI:
@Composable
fun ChipTextField(
state: ChipTextFieldState<Chip>,
chips: List<Chip>,
onValueChange: (chips: List<Chip>) -> Unit,
modifier: Modifier = Modifier,
) {
LaunchedEffect(chips) {
state.chips = chips
}
LaunchedEffect(state, onValueChange) {
snapshotFlow { state.chips.map { it.text } }
.collect { onValueChange(state.chips) }
}
ChipTextField(
state = state,
modifier = modifier,
onSubmit = ::Chip,
)
}
This will make your view model dependent on the library class. For List<String>
or your types, you can do a 'half-sync':
data class UiState(
val tags: List<String> = emptyList(),
)
@Composable
fun SomeScreen(
modifier: Modifier = Modifier,
viewModel: ViewModel = remember { ViewModel() },
) {
val uiState by viewModel.uiState.collectAsState()
val state = rememberChipTextFieldState<Chip>()
LaunchedEffect(state, uiState.tags) {
if (state.chips.isEmpty() && uiState.tags.isNotEmpty()) {
// Set the initial chips from the view model
state.chips = uiState.tags.map(::Chip)
}
}
LaunchedEffect(state) {
snapshotFlow { state.chips.map { it.text } }
.collect { viewModel.updateTags(it) } // Update the view model chips
}
ChipTextField(
state = state,
onSubmit = ::Chip,
)
}
Currently, chips are handled by ChipTextFieldState internally. Chips should come from outside like ViewModel. Also there should be Events or Listeners while removing chips that is currently handled internally.
For example, LIKE TextField's value and onValueChanged design (unidirectional)