.agents/skills/implement-flet-extension/SKILL.md
Implement a Flet extension around an external Flutter package using existing flet_* packages as implementation templates.
flet_<extension>).LayoutControl for visual controls that participate in page/layout positioning.Control for simple visual controls that do not require page positioning or define their own positioning rules/props (for example Draggable, Divider, MenuBar, NavigationRail).sdk/python/packages/flet-audio, sdk/python/packages/flet-flashlight, sdk/python/packages/flet-secure-storage.LayoutControl, base Control, or Service base class according to classification.parseEnum() for enums — it's exported from package:flet/flet.dart. Call it as parseEnum(MyEnum.values, widget.control.getString("attr"), MyEnum.defaultVal)!. Do NOT write a custom _parseXxx() switch helper.widget.control.getBool()/getDouble()/... accessors.parseSomething() helpers.utils/<control>.dart; shared helpers in utils/<topic>.dart.parse-prefixed helper names when converting input to Flutter structures.Properties with default values on the Python side are not sent to Flutter when unchanged from the default. Every Dart property read must provide the same default as its Python counterpart:
control.getDouble("size", 100.0)! when Python has size: float = 100.0control.getBool("animate", true)! when Python has animate: bool = TrueparseDuration(value["dur"], const Duration(milliseconds: 500))! when Python has dur: DurationValue = field(default_factory=lambda: Duration(milliseconds=500))control.get<List>("items")?.map(...).toList() ?? const [] when Python has items: list[str] = field(default_factory=list)Without matching defaults, Dart receives null and either crashes or silently uses the wrong value. This applies to all property types: bools, numbers, strings, enums, durations, collections, and nested @ft.value types.
client/pubspec.yaml: add flet_<ext>: path: ../sdk/python/packages/flet-<ext>/src/flutter/flet_<ext> under dependencies.client/lib/main.dart: add import 'package:flet_<ext>/flet_<ext>.dart' as flet_<ext>; and flet_<ext>.Extension() to the extensions list.sdk/python/pyproject.toml in two places: the dependencies list and [tool.uv.sources] as { workspace = true }.sdk/python/packages/flet/pyproject.toml in the [dependency-groups] extensions list.sdk/python/examples/apps/flet_build_test/pyproject.toml in three places: [project] dependencies, [tool.uv.sources] as { path = "...", editable = true }, and [tool.flet.dev_packages] as a relative path string.tools/crocodocs/pyproject.toml under [tool.crocodocs.packages] as <pkg_name> = "../../sdk/python/packages/<pkg-dir>/src". This fixes "Missing API entry" errors in the docs. Note: api-data.json is gitignored (generated at build time); only the pyproject.toml change needs committing..github/workflows/ci.yml in both places:
build_flet_extensions -> PACKAGES list.py_publish -> for pkg in ... publish loop..gitignore to Flutter extension project if missing.[tool.uv.sources] local path overrides from example pyproject.toml files before opening a PR (they are development-only conveniences).website/docs/controls/<name> for controls and website/docs/services/<name> for services.index.md for the overview (install instructions, examples, list of links) and individual <controlname>.md files for each control — consistent with flet-color-pickers and other extensions.<ClassSummary name="pkg.ClassName" /> and <ClassMembers name="pkg.ClassName" /> JSX from @site/src/components/crocodocs to render API docs. Do NOT add image=, imageCaption=, or imageWidth= props to <ClassSummary> when no screenshots exist yet.## Examples section, do NOT add ### subtitles above <CodeExample> blocks — titles are injected automatically from the example file itself.website/sidebars.yml navigation.codeeditor.md, not code_editor.md).sdk/python/examples/extensions/<name>/ for extension controls.import flet_<ext> as <short_alias> in examples (e.g., import flet_spinkit as spins). Keep alias short but readable.ft.Colors.SURFACE_CONTAINER_HIGHEST for card/cell backgrounds in showcase examples — it adapts to light and dark system themes automatically.page.theme_mode).packages/flet/integration_tests/extensions/<name>/ — not inside the extension package's own directory (no tests/ folder in the package itself, matching the pattern of flet-code-editor, flet-color-pickers, etc.).assert_control_screenshot or pump_and_settle — they will timeout waiting for animations to settle. Instead use await flet_app.tester.pump(duration=ft.Duration(milliseconds=500)) which advances the clock by a fixed amount. This still runs real Flutter rendering and catches crashes, without screenshot comparison.