Fix#180534
## Pre-launch Checklist
- [X] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [X] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [X] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [X] I signed the [CLA].
- [X] I listed at least one issue that this PR fixes in the description
above.
- [X] I updated/added relevant documentation (doc comments with `///`).
- [X] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [X] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [X] All existing and new tests are passing.
I don't know if there is an issue for this, but without the fix it looks
like (in particular see the end of the video)
https://github.com/user-attachments/assets/0c25ffdf-1fc0-4eb2-a18e-f5b369b266d3
and with the fix it looks like
https://github.com/user-attachments/assets/ade37009-a40b-4d1e-be22-b5ca5adfe246
Basically, we were using the value passed in by the engine in
`onDisplayPlatformView(2)` to try to calculate the offset for this
touch. However, we aren't guaranteed a call to `onDisplayPlatformView`
for each call to `FlutterMutatorView.onTouchEvent`, and in practice we
don't normally get them lined up like that, so the value is stale. Also,
the touches are frequently changing by sub pixel values, but the values
passed to `onDisplayPlatformView` are received as ints (we could maybe
fix this, if it matters elsewhere). So this is fragile, comparing whole
pixel to sub pixel, and also uses stale values. We can instead just ask
android where the view is, I believe (this is what the PR does, and it
works AFAICT).
I don't know how to test this.
---------
Co-authored-by: Gray Mackall <mackall@google.com>
The wiki is supposed to be for team-focused documentation, but this page
was client-focused. That was resolved at some point via the creation of
https://docs.flutter.dev/platform-integration/android/platform-views,
https://docs.flutter.dev/platform-integration/ios/platform-views, and
https://docs.flutter.dev/platform-integration/macos/platform-views, and
this page is now a somewhat outdated (e.g., in doesn't use code
excerpting to ensure correctness like the docs page does), less
client-friendly version of those pages.
This removes essentially all of the duplicated content, and makes it a
much smaller, team-focused page, following the format of the
corresponding TLHC page in the wiki.
Since there are likely external pages that linked here for the old
content, this leaves a breadcrumb to the client-facing docs at the top.
Fixes https://github.com/flutter/flutter/issues/124801
---------
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
## Description
This PR fixes a division by zero crash in `RenderTable` when intrinsic
size methods are called on empty tables (0 rows × 0 columns) with
non-zero constraints.
### The Problem
When `RenderTable` has 0 columns and intrinsic size methods
(`computeMinIntrinsicHeight`, `computeMaxIntrinsicHeight`,
`computeMinIntrinsicWidth`, `computeMaxIntrinsicWidth`) are called with
non-zero width constraints, the code calls `_computeColumnWidths()`
without checking if the table is empty. This leads to division by zero
at line 1140:
```dart
final double delta = (minWidthConstraint - tableWidth) / columns;
// When columns = 0, this crashes with division by zero
```
### The Solution
Added early return checks `if (rows * columns == 0) return 0.0;` to all
four intrinsic size methods, matching the pattern already used by other
methods that call `_computeColumnWidths()`:
- `computeDryBaseline` (line 1242) - already has the check
- `computeDryLayout` (line 1274) - already has the check
- `performLayout` (line 1318) - already has the check
- `paint` (line 1461) - already has the check
Now all four intrinsic methods are consistent with the rest of the
codebase.
### Testing
Added comprehensive test coverage (`Empty table intrinsic dimensions
should not crash`) that:
- Creates an empty table (0×0)
- Calls all four intrinsic size methods with various constraints
- Verifies they return 0.0 without crashing
### Changes Made
**packages/flutter/lib/src/rendering/table.dart:**
- Added empty table check to `computeMinIntrinsicWidth` (line 963-965)
- Added empty table check to `computeMaxIntrinsicWidth` (line 978-980)
- Added empty table check to `computeMinIntrinsicHeight` (line 995-997)
- Added empty table check to `computeMaxIntrinsicHeight` (line
1016-1019)
**packages/flutter/test/rendering/table_test.dart:**
- Added test case `Empty table intrinsic dimensions should not crash`
- Tests all four intrinsic methods with both finite and infinite
constraints
## Related Issues
This fix addresses a potential crash when using `RenderTable` with
intrinsic sizing widgets (like `IntrinsicHeight`, `IntrinsicWidth`) on
empty tables.
## Checklist
Before you create this PR, confirm all the requirements listed below by
checking the relevant checkboxes (`[x]`). This will ensure a smooth
review process.
- [x] I have read the [Contributor Guide] and followed the process
outlined there for submitting PRs.
- [x] I have read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I have read and followed the [Flutter Style Guide], including
[Features we expect every widget to implement].
- [x] I have signed the [CLA].
- [x] I have listed at least one issue that this PR fixes (defensive
programming for edge case).
- [x] I have updated/added relevant documentation (doc comments with
`///`).
- [x] I have added new tests that verify the fix works.
- [x] All existing and new tests are passing (`flutter analyze` shows no
issues).
- [x] I have followed the [breaking change policy] and added [Data
Driven Fixes] where applicable (no breaking changes in this PR).
[Contributor Guide]:
https://github.com/flutter/flutter/blob/master/docs/contributing/Tree-hygiene.md#overview
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/master/docs/contributing/Tree-hygiene.md
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/master/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/master/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[breaking change policy]:
https://github.com/flutter/flutter/blob/master/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/master/docs/contributing/Data-driven-Fixes.md
---------
Co-authored-by: Kate Lovett <katelovett@google.com>
Fly-by clean-up: My understanding from the
[changelog](https://pub.dev/packages/dds/changelog) is that the change
causing the bug in 5.0.4 has been reverted in 5.0.5. Therefore, the pin
should be no longer necessary? Unpinning to find out...
> 5.0.5
[DAP] The change in DDS 5.0.4 to individually add/remove breakpoints has
been reverted and may be restored in a future version.
>
>5.0.4
[DAP] Breakpoints are now added/removed individually instead of all
being cleared and re-added during a setBreakpoints request. This
improves performance and can avoid breakpoints flickering between
unresolved/resolved when adding new breakpoints in the same file.
## Description
This PR adds logic to resolve `DropdownMenuEntry.style` properties with
the correct `WidgetState` when an item is highlighted.
When `MenuItemButton` are highlighted the focused state is not added
automatically because the focus does not move to the items (it stays on
the `TextField` in order to let the user enters text to filter the items
list). This PR sets the `MenuItemButton.statesController` with a forced
focused state to let `MenuItemButton` know that the focused state should
be use to resolve the properties.
## Related Issue
Fixes [DropdownMenuEntry style's text style is not resolving with
states](https://github.com/flutter/flutter/issues/177363)
## Tests
- Adds 1 tests.
Adds logic to pass `--include-unsupported-platform-library-stubs` to the
CFE when launched via `flutter widget-preview start`, as well as logic
to ensure the flag can't be passed as an extra frontend option to bypass
compile time errors due to imports of unsupported libraries.
Fixes https://github.com/flutter/flutter/issues/166431
<!--
Thanks for filing a pull request!
Reviewers are typically assigned within a week of filing a request.
To learn more about code review, see our documentation on Tree Hygiene:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
-->
## Add --web-define option for runtime variable injection in Flutter web
templates
This PR adds support for injecting environment-specific variables into
Flutter web templates during development and build processes through a
new `--web-define` command-line option.
### What this changes
**Before**: Developers had to manually edit HTML templates or use
build-time workarounds to inject environment-specific values (API URLs,
feature flags, etc.) into Flutter web applications.
**After**: Developers can now use `--web-define KEY=VALUE` to inject
variables directly into web templates using `{{VARIABLE_NAME}}`
placeholders.
### Key features
- **Template variable substitution**: Support for `{{VARIABLE_NAME}}`
placeholders in `index.html` and `flutter_bootstrap.js`
- **Runtime validation**: Throws clear errors when required variables
are missing with helpful suggestions
- **Command-line integration**: Works with both `flutter run` and
`flutter build web` commands
- **Multiple variable support**: Can define multiple variables in a
single command
- **Built-in variable protection**: Ignores Flutter's built-in template
variables during validation
### Usage examples
```bash
# Development with API configuration
flutter run -d chrome --web-define=API_URL=https://dev-api.example.com --web-define=DEBUG_MODE=true
# Production build with environment variables
flutter build web --web-define=API_URL=https://api.example.com --web-define=ANALYTICS_ID=GA-123456 --web-define=DEBUG_MODE=false
# Multiple environments
flutter run -d chrome --web-define=ENV=staging --web-define=FEATURE_X=enabled
```
### Template usage
In your `web/index.html`:
```html
<script>
window.config = {
apiUrl: '{{API_URL}}',
environment: '{{ENV}}',
debugMode: {{DEBUG_MODE}}
};
</script>
```
### Error handling
If a variable is missing, the tool provides clear feedback:
```
Missing web-define variable: API_URL
Please provide the missing variable using:
flutter run --web-define=API_URL=VALUE
or
flutter build web --web-define=API_URL=VALUE
```
## Issues fixed
Fixes https://github.com/flutter/flutter/issues/127853
## Additional Usage Examples
### Environment-Specific Configurations (Flavors)
```bash
# Development
flutter run -d chrome --web-define=ENV=dev --web-define=API_URL=http://localhost:3000 --web-define=DEBUG=true
# Production
flutter build web --web-define=ENV=prod --web-define=API_URL=https://api.example.com --web-define=DEBUG=false
```
**Template:**
```html
<script>
window.config = {
environment: '{{ENV}}',
apiUrl: '{{API_URL}}',
debugMode: {{DEBUG}}
};
</script>
```
### Dynamic Asset Loading
```bash
flutter build web --web-define=CDN_URL=https://cdn.example.com --web-define=LOGO_PATH=/assets/logo.png
```
**Template:**
```html
<link rel="icon" href="{{CDN_URL}}{{LOGO_PATH}}">
<link rel="stylesheet" href="{{CDN_URL}}/styles/theme.css">
```
### Analytics Integration
```bash
flutter build web --web-define=GA_ID=G-XXXXXXXXXX --web-define=SENTRY_DSN=https://xxx@sentry.io/123
```
**Template:**
```html
<script async src="https://www.googletagmanager.com/gtag/js?id={{GA_ID}}"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '{{GA_ID}}');
</script>
```
### Feature Flags
```bash
flutter run -d chrome --web-define=FEATURE_X=true --web-define=FEATURE_Y=false
```
**Template:**
```html
<script>
window.features = { featureX: {{FEATURE_X}}, featureY: {{FEATURE_Y}} };
</script>
```
### Multi-Tenant/White-Label Apps
```bash
flutter build web --web-define=TENANT=acme --web-define=PRIMARY_COLOR=#FF5733 --web-define=LOGO_URL=https://cdn.acme.com/logo.png
```
**Template:**
```html
<head>
<title>{{TENANT}} Portal</title>
<link rel="icon" href="{{LOGO_URL}}">
<style>:root { --primary: {{PRIMARY_COLOR}}; }</style>
</head>
```
### Backend Service URLs
```bash
flutter build web \
--web-define=API_URL=https://api.example.com \
--web-define=WS_URL=wss://ws.example.com \
--web-define=AUTH_DOMAIN=auth.example.com
```
**Template:**
```html
<script>
window.services = {
api: '{{API_URL}}',
websocket: '{{WS_URL}}',
auth: '{{AUTH_DOMAIN}}'
};
</script>
```
### SEO & Meta Tags
```bash
flutter build web --web-define=APP_TITLE="My App" --web-define=APP_DESC="Description" --web-define=OG_IMAGE=https://example.com/og.png
```
**Template:**
```html
<head>
<title>{{APP_TITLE}}</title>
<meta name="description" content="{{APP_DESC}}">
<meta property="og:title" content="{{APP_TITLE}}">
<meta property="og:image" content="{{OG_IMAGE}}">
</head>
```
### Build Automation
```json
{
"scripts": {
"dev": "flutter run -d chrome --web-define=ENV=dev --web-define=API_URL=http://localhost:3000",
"prod": "flutter build web --web-define=ENV=prod --web-define=API_URL=https://api.example.com"
}
}
```
### Important Notes
- **Security**: Never expose secrets via `--web-define` (client-side
only)
## Pre-launch Checklist
- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.
If you need help, consider asking for advice on the #hackers-new channel
on [Discord].
**Note**: The Flutter team is currently trialing the use of [Gemini Code
Assist for
GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code).
Comments from the `gemini-code-assist` bot should not be taken as
authoritative feedback from the Flutter team. If you find its comments
useful you can update your code accordingly, but if you are unsure or
disagree with the feedback, please feel free to wait for a Flutter team
member's review for guidance on which automated comments should be
addressed.
<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
---------
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: Ben Konyi <bkonyi@google.com>
Co-authored-by: Mouad Debbar <mdebbar@google.com>
This PR restores the correct precedence behavior for web development
server configuration. Since Flutter 3.38, CLI arguments were being
ignored when `web_dev_config.yaml` was present — specifically for HTTPS
and headers.
According to the design and documentation, the precedence should be:
1. Command-line arguments (highest priority)
2. `web_dev_config.yaml`
3. Built-in defaults (lowest priority)
## Root Cause
The regression affected:
* **HTTP headers** — merge order was reversed, causing file config to
override CLI
* **HTTPS config** — CLI TLS arguments were ignored under certain
conditions
Note:
`--web-port` and `--web-hostname` were already working correctly due to
the `host ?? this.host` and `port ?? this.port` pattern.
The observed issue was due to headers + HTTPS only.
## Changes Made
* Fixed header merge order so CLI takes precedence
* Corrected HTTPS config resolution and precedence logic
* Unified logic across `run` and `drive` commands
* Simplified HTTPS handling using `HttpsConfig.parse()`
* Added tests for CLI precedence behavior
## Before (broken)
```
flutter run -d chrome --web-tls-cert-path cert.pem
```
❌ CLI TLS args ignored when config file existed
❌ headers overridden by file config
## After (fixed)
```
flutter run -d chrome --web-tls-cert-path cert.pem
```
✅ CLI TLS args respected
✅ headers override config as expected
## Tests
* Added tests verifying CLI takes precedence
* All existing and new tests pass
* No breaking changes introduced
## Fixes
Fixes: #179014
---------
Co-authored-by: Kevin Moore <kevmoo@google.com>
Co-authored-by: Kevin Moore <kevmoo@users.noreply.github.com>
Co-authored-by: Ben Konyi <bkonyi@google.com>
When targeting Android, don't fail in Flutter tools if the NDK is not
installed. Instead, pass a `null` c compiler config to the hooks. The
hooks can then decide to fail if they need the NDK. If no hook happened
to require the NDK, Flutter for Android apps can be built without the
NDK installed.
Bug: https://github.com/flutter/flutter/issues/180163
## Pre-launch Checklist
- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.
This PR fixes https://github.com/flutter/flutter/issues/173491 by adding
the missing 'Share' option to the default iOS SystemContextMenu when
shareEnabled is true.
Changes:
Added IOSSystemContextMenuItemShare to getDefaultItems in
system_context_menu.dart.
Added a widget test to ensure Share is present in the default items for
non-empty selections on iOS.
Rationale:
This aligns Flutter's default iOS text selection context menu with
native iOS behavior, ensuring users see the expected 'Share' option when
selecting text.
Demo:
Video showing Share option in iOS context menu:
https://github.com/user-attachments/assets/e04cd1f9-7d92-4147-a09b-719f03d9c625
Closes https://github.com/flutter/flutter/issues/180031
### Description
- Adds `tooltip` support to `PlatformMenuItem` and `PlatformMenu`
- Updates `platform_menu_bar_test.dart` to cover `tooltip` related
changes and makes test-specific code private
- Updates `FlutterMenuPlugin.mm` to support `tooltip`
- Updates `FlutterMenuPluginTest.mm` to cover `tooltip` related changes
https://github.com/user-attachments/assets/abafc1ec-dc2f-45ae-a3b5-1e88759dac37
<details closed><summary>Code sample</summary>
```dart
// THIS SAMPLE ONLY WORKS ON MACOS.
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
/// Flutter code sample for [PlatformMenuBar].
void main() => runApp(const ExampleApp());
enum MenuSelection { about, showMessage }
class ExampleApp extends StatelessWidget {
const ExampleApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(home: Scaffold(body: PlatformMenuBarExample()));
}
}
class PlatformMenuBarExample extends StatefulWidget {
const PlatformMenuBarExample({super.key});
@override
State<PlatformMenuBarExample> createState() => _PlatformMenuBarExampleState();
}
class _PlatformMenuBarExampleState extends State<PlatformMenuBarExample> {
String _message = 'Hello';
bool _showMessage = false;
void _handleMenuSelection(MenuSelection value) {
switch (value) {
case MenuSelection.about:
showAboutDialog(
context: context,
applicationName: 'MenuBar Sample',
applicationVersion: '1.0.0',
);
case MenuSelection.showMessage:
setState(() {
_showMessage = !_showMessage;
});
}
}
@override
Widget build(BuildContext context) {
////////////////////////////////////
// THIS SAMPLE ONLY WORKS ON MACOS.
////////////////////////////////////
// This builds a menu hierarchy that looks like this:
// Flutter API Sample
// ├ About
// ├ ──────── (group divider)
// ├ Hide/Show Message
// ├ Messages
// │ ├ I am not throwing away my shot.
// │ └ There's a million things I haven't done, but just you wait.
// └ Quit
return PlatformMenuBar(
menus: <PlatformMenuItem>[
PlatformMenu(
label: 'Flutter API Sample',
menus: <PlatformMenuItem>[
PlatformMenuItemGroup(
members: <PlatformMenuItem>[
PlatformMenuItem(
label: 'About',
tooltip: 'Show information about APP_NAME',
onSelected: () {
_handleMenuSelection(MenuSelection.about);
},
),
],
),
PlatformMenuItemGroup(
members: <PlatformMenuItem>[
PlatformMenuItem(
onSelected: () {
_handleMenuSelection(MenuSelection.showMessage);
},
shortcut: const CharacterActivator('m'),
label: _showMessage ? 'Hide Message' : 'Show Message',
tooltip: _showMessage
? 'The message will be hidden.'
: 'The message will be shown.',
),
PlatformMenu(
label: 'Messages',
menus: <PlatformMenuItem>[
PlatformMenuItem(
label: 'I am not throwing away my shot.',
shortcut: const SingleActivator(
LogicalKeyboardKey.digit1,
meta: true,
),
onSelected: () {
setState(() {
_message = 'I am not throwing away my shot.';
});
},
),
PlatformMenuItem(
label:
"There's a million things I haven't done, but just you wait.",
shortcut: const SingleActivator(
LogicalKeyboardKey.digit2,
meta: true,
),
onSelected: () {
setState(() {
_message =
"There's a million things I haven't done, but just you wait.";
});
},
),
],
),
],
),
if (PlatformProvidedMenuItem.hasMenu(
PlatformProvidedMenuItemType.quit,
))
const PlatformProvidedMenuItem(
type: PlatformProvidedMenuItemType.quit,
),
],
),
],
child: Center(
child: Text(
_showMessage
? _message
: 'This space intentionally left blank.\n'
'Show a message here using the menu.',
),
),
);
}
}
```
</details>
## Pre-launch Checklist
- [X] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [X] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [X] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [X] I signed the [CLA].
- [X] I listed at least one issue that this PR fixes in the description
above.
- [X] I updated/added relevant documentation (doc comments with `///`).
- [X] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [X] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [X] All existing and new tests are passing.
<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
## Description
This PR adds the `DropdownMenuFormField.errorBuilder` property which
makes it possible to customize the widget used to display the error
message.
This is a follow-up to https://github.com/flutter/flutter/pull/162255
which added the `errorBuilder` property to other form fields.
## Related Issue
Fixes [DropdownMenuFormField is missing an errorBuilder
property](https://github.com/flutter/flutter/issues/172416)
## Tests
Updates 5 tests.
Adds 1 test.