{"id":24741,"plugin_id":"plugins~Plugin_f1b845ac33888191ac156169c58733c2","kind":"skill","collection_source":null,"comparison_source":null,"observed_at":"2026-09-30T23:18:36.404Z","digest":"1ee1b643a4b393efaed4f7c5d04360831b00c6cc5a323ec961c1197625cd60c3","against":null,"payload":{"name":"swiftui-ui-patterns","description":"Build and refactor SwiftUI UI with component patterns and examples. Use when shaping navigation, state, layouts, controls, or screen composition.","included_files":[{"relative_path":"agents/openai.yaml","size_in_bytes":221},{"relative_path":"references/app-wiring.md","size_in_bytes":6637},{"relative_path":"references/async-state.md","size_in_bytes":2833},{"relative_path":"references/components-index.md","size_in_bytes":4303},{"relative_path":"references/controls.md","size_in_bytes":1682},{"relative_path":"references/deeplinks.md","size_in_bytes":1703},{"relative_path":"references/focus.md","size_in_bytes":2390},{"relative_path":"references/form.md","size_in_bytes":3062},{"relative_path":"references/grids.md","size_in_bytes":1851},{"relative_path":"references/haptics.md","size_in_bytes":2049},{"relative_path":"references/input-toolbar.md","size_in_bytes":1451},{"relative_path":"references/lightweight-clients.md","size_in_bytes":2524},{"relative_path":"references/list.md","size_in_bytes":2732},{"relative_path":"references/loading-placeholders.md","size_in_bytes":1274},{"relative_path":"references/macos-settings.md","size_in_bytes":1997},{"relative_path":"references/matched-transitions.md","size_in_bytes":1674},{"relative_path":"references/media.md","size_in_bytes":2040},{"relative_path":"references/menu-bar.md","size_in_bytes":2236},{"relative_path":"references/navigationstack.md","size_in_bytes":4343},{"relative_path":"references/overlay.md","size_in_bytes":1238},{"relative_path":"references/performance.md","size_in_bytes":1990},{"relative_path":"references/previews.md","size_in_bytes":1688},{"relative_path":"references/scroll-reveal.md","size_in_bytes":5299},{"relative_path":"references/scrollview.md","size_in_bytes":2364},{"relative_path":"references/searchable.md","size_in_bytes":1727},{"relative_path":"references/sheets.md","size_in_bytes":4272},{"relative_path":"references/split-views.md","size_in_bytes":2027},{"relative_path":"references/tabview.md","size_in_bytes":3486},{"relative_path":"references/theming.md","size_in_bytes":1776},{"relative_path":"references/title-menus.md","size_in_bytes":2115},{"relative_path":"references/top-bar.md","size_in_bytes":1359}],"skill_md_contents":"---\nname: swiftui-ui-patterns\ndescription: Build and refactor SwiftUI UI with component patterns and examples. Use when shaping navigation, state, layouts, controls, or screen composition.\n---\n\n# SwiftUI UI Patterns\n\n## Quick start\n\nChoose a track based on your goal:\n\n### Existing project\n\n- Identify the feature or screen and the primary interaction model (list, detail, editor, settings, tabbed).\n- Find a nearby example in the repo with `rg \"TabView\\(\"` or similar, then read the closest SwiftUI view.\n- Apply local conventions: prefer SwiftUI-native state, keep state local when possible, and use environment injection for shared dependencies.\n- Choose the relevant component reference from `references/components-index.md` and follow its guidance.\n- If the interaction reveals secondary content by dragging or scrolling the primary content away, read `references/scroll-reveal.md` before implementing gestures manually.\n- Build the view with small, focused subviews and SwiftUI-native data flow.\n\n### New project scaffolding\n\n- Start with `references/app-wiring.md` to wire TabView + NavigationStack + sheets.\n- Add a minimal `AppTab` and `RouterPath` based on the provided skeletons.\n- Choose the next component reference based on the UI you need first (TabView, NavigationStack, Sheets).\n- Expand the route and sheet enums as new screens are added.\n\n## General rules to follow\n\n- Use modern SwiftUI state (`@State`, `@Binding`, `@Observable`, `@Environment`) and avoid unnecessary view models.\n- If the deployment target includes iOS 16 or earlier and cannot use the Observation API introduced in iOS 17, fall back to `ObservableObject` with `@StateObject` for root ownership, `@ObservedObject` for injected observation, and `@EnvironmentObject` only for truly shared app-level state.\n- Prefer composition; keep views small and focused.\n- Use async/await with `.task` and explicit loading/error states. For restart, cancellation, and debouncing guidance, read `references/async-state.md`.\n- Keep shared app services in `@Environment`, but prefer explicit initializer injection for feature-local dependencies and models. For root wiring patterns, read `references/app-wiring.md`.\n- Prefer the newest SwiftUI API that fits the deployment target and call out the minimum OS whenever a pattern depends on it.\n- Maintain existing legacy patterns only when editing legacy files.\n- Follow the project's formatter and style guide.\n- **Sheets**: Prefer `.sheet(item:)` over `.sheet(isPresented:)` when state represents a selected model. Avoid `if let` inside a sheet body. Sheets should own their actions and call `dismiss()` internally instead of forwarding `onCancel`/`onConfirm` closures.\n- **Scroll-driven reveals**: Prefer deriving a normalized progress value from scroll offset and driving the visual state from that single source of truth. Avoid parallel gesture state machines unless scroll alone cannot express the interaction.\n\n## State ownership summary\n\nUse the narrowest state tool that matches the ownership model:\n\n| Scenario | Preferred pattern |\n| --- | --- |\n| Local UI state owned by one view | `@State` |\n| Child mutates parent-owned value state | `@Binding` |\n| Root-owned reference model on iOS 17+ | `@State` with an `@Observable` type |\n| Child reads or mutates an injected `@Observable` model on iOS 17+ | Pass it explicitly as a stored property |\n| Shared app service or configuration | `@Environment(Type.self)` |\n| Legacy reference model on iOS 16 and earlier | `@StateObject` at the root, `@ObservedObject` when injected |\n\nChoose the ownership location first, then pick the wrapper. Do not introduce a reference model when plain value state is enough.\n\n## Cross-cutting references\n\n- In addition to the references below, use web search to consult current Apple Developer documentation when SwiftUI APIs, availability, or platform guidance may have changed.\n- `references/navigationstack.md`: navigation ownership, per-tab history, and enum routing.\n- `references/sheets.md`: centralized modal presentation and enum-driven sheets.\n- `references/deeplinks.md`: URL handling and routing external links into app destinations.\n- `references/app-wiring.md`: root dependency graph, environment usage, and app shell wiring.\n- `references/async-state.md`: `.task`, `.task(id:)`, cancellation, debouncing, and async UI state.\n- `references/previews.md`: `#Preview`, fixtures, mock environments, and isolated preview setup.\n- `references/performance.md`: stable identity, observation scope, lazy containers, and render-cost guardrails.\n\n## Anti-patterns\n\n- Giant views that mix layout, business logic, networking, routing, and formatting in one file.\n- Multiple boolean flags for mutually exclusive sheets, alerts, or navigation destinations.\n- Live service calls directly inside `body`-driven code paths instead of view lifecycle hooks or injected models/services.\n- Reaching for `AnyView` to work around type mismatches that should be solved with better composition.\n- Defaulting every shared dependency to `@EnvironmentObject` or a global router without a clear ownership reason.\n\n## Workflow for a new SwiftUI view\n\n1. Define the view's state, ownership location, and minimum OS assumptions before writing UI code.\n2. Identify which dependencies belong in `@Environment` and which should stay as explicit initializer inputs.\n3. Sketch the view hierarchy, routing model, and presentation points; extract repeated parts into subviews. For complex navigation, read `references/navigationstack.md`, `references/sheets.md`, or `references/deeplinks.md`. **Build and verify no compiler errors before proceeding.**\n4. Implement async loading with `.task` or `.task(id:)`, plus explicit loading and error states when needed. Read `references/async-state.md` when the work depends on changing inputs or cancellation.\n5. Add previews for the primary and secondary states, then add accessibility labels or identifiers when the UI is interactive. Read `references/previews.md` when the view needs fixtures or injected mock dependencies.\n6. Validate with a build: confirm no compiler errors, check that previews render without crashing, ensure state changes propagate correctly, and sanity-check that list identity and observation scope will not cause avoidable re-renders. Read `references/performance.md` if the screen is large, scroll-heavy, or frequently updated. For common SwiftUI compilation errors — missing `@State` annotations, ambiguous `ViewBuilder` closures, or mismatched generic types — resolve them before updating callsites. **If the build fails:** read the error message carefully, fix the identified issue, then rebuild before proceeding to the next step. If a preview crashes, isolate the offending subview, confirm its state initialisation is valid, and re-run the preview before continuing.\n\n## Component references\n\nUse `references/components-index.md` as the entry point. Each component reference should include:\n- Intent and best-fit scenarios.\n- Minimal usage pattern with local conventions.\n- Pitfalls and performance notes.\n- Paths to existing examples in the current repo.\n\n## Adding a new component reference\n\n- Create `references/<component>.md`.\n- Keep it short and actionable; link to concrete files in the current repo.\n- Update `references/components-index.md` with the new entry.\n"},"changes":[],"summary":"First saved snapshot. No earlier version is available for comparison.","summary_kind":"deterministic","summary_metadata":{}}