Fix suggestions positioning using CompositedTransformFollower to properly position dropdown below TextField

This commit is contained in:
Leon Bösche
2026-01-24 05:06:30 +01:00
parent 65ad05ac76
commit deb8b50bb9

View File

@@ -38,6 +38,7 @@ class _OrganizationSettingsDialogState
List<User> _userSuggestions = []; List<User> _userSuggestions = [];
late final TextEditingController usernameController; late final TextEditingController usernameController;
final GlobalKey textFieldKey = GlobalKey(); final GlobalKey textFieldKey = GlobalKey();
final LayerLink link = LayerLink();
@override @override
void initState() { void initState() {
@@ -509,45 +510,48 @@ class _OrganizationSettingsDialogState
), ),
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
TextField( CompositedTransformTarget(
key: textFieldKey, link: link,
controller: usernameController, child: TextField(
cursorColor: AppTheme.accentColor, key: textFieldKey,
decoration: InputDecoration( controller: usernameController,
hintText: 'Username', cursorColor: AppTheme.accentColor,
hintStyle: TextStyle(color: AppTheme.secondaryText), decoration: InputDecoration(
contentPadding: const EdgeInsets.all(12), hintText: 'Username',
border: OutlineInputBorder( hintStyle: TextStyle(color: AppTheme.secondaryText),
borderSide: BorderSide( contentPadding: const EdgeInsets.all(12),
color: AppTheme.accentColor.withValues(alpha: 0.3), border: OutlineInputBorder(
borderSide: BorderSide(
color: AppTheme.accentColor.withValues(alpha: 0.3),
),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: AppTheme.accentColor.withValues(alpha: 0.3),
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: AppTheme.accentColor),
), ),
), ),
enabledBorder: OutlineInputBorder( style: TextStyle(color: AppTheme.primaryText),
borderSide: BorderSide( onChanged: (value) async {
color: AppTheme.accentColor.withValues(alpha: 0.3), if (value.length > 2) {
), try {
), _userSuggestions = await widget.orgApi.searchUsers(
focusedBorder: OutlineInputBorder( widget.organization.id,
borderSide: BorderSide(color: AppTheme.accentColor), value,
), );
), } catch (e) {
style: TextStyle(color: AppTheme.primaryText), _userSuggestions = [];
onChanged: (value) async { }
if (value.length > 2) { setState(() {});
try { } else {
_userSuggestions = await widget.orgApi.searchUsers(
widget.organization.id,
value,
);
} catch (e) {
_userSuggestions = []; _userSuggestions = [];
setState(() {});
} }
setState(() {}); },
} else { ),
_userSuggestions = [];
setState(() {});
}
},
), ),
DropdownButtonFormField<String>( DropdownButtonFormField<String>(
initialValue: selectedRole, initialValue: selectedRole,
@@ -645,11 +649,11 @@ class _OrganizationSettingsDialogState
if (_userSuggestions.isNotEmpty) { if (_userSuggestions.isNotEmpty) {
children.add( children.add(
Positioned( CompositedTransformFollower(
top: 240, link: link,
left: 0, offset: const Offset(0, 48),
right: 0,
child: Container( child: Container(
width: 300,
height: 100, height: 100,
decoration: BoxDecoration( decoration: BoxDecoration(
color: AppTheme.primaryBackground, color: AppTheme.primaryBackground,