skills/generators/pagination/SKILL.md
Generates pagination infrastructure with offset or cursor-based patterns, infinite scroll, and search support. Use when user wants to add paginated lists, infinite scrolling, or load-more functionality.
npx skillsauth add rshankras/claude-code-apple-skills paginationInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Generate production pagination infrastructure supporting offset-based and cursor-based APIs, with infinite scroll SwiftUI views, state machine management, and optional search integration.
Use this skill when the user:
Search for existing networking code:
Glob: **/*API*.swift, **/*Client*.swift, **/*Endpoint*.swift
Grep: "APIClient" or "APIEndpoint"
If networking-layer generator was used, detect the APIEndpoint protocol and generate data sources that conform to it.
Search for existing pagination:
Glob: **/*Pagina*.swift, **/*LoadMore*.swift
Grep: "PaginationState" or "loadNextPage" or "hasMorePages"
If found, ask user whether to replace or extend.
Ask user via AskUserQuestion:
Pagination style?
Loading trigger?
Additional features? (multi-select)
Data source pattern?
Read pagination-patterns.md for architecture guidance.
Read templates.md for production Swift code.
Generate these files:
PaginatedResponse.swift — Generic response models for offset and cursorPaginationState.swift — State machine (idle, loading, loaded, error, exhausted)PaginatedDataSource.swift — Protocol endpoints conform toPaginationManager.swift — @Observable manager with state transitionsBased on configuration:
SearchablePaginationManager.swift — If search selectedViews/PaginatedList.swift — Infinite scroll SwiftUI wrapperViews/LoadMoreButton.swift — Manual load-more buttonViews/PaginationStateView.swift — Empty/loading/error state viewsCheck project structure:
Sources/ exists → Sources/Pagination/App/ exists → App/Pagination/Pagination/After generation, provide:
Pagination/
├── PaginatedResponse.swift # Generic response models
├── PaginationState.swift # State machine enum
├── PaginatedDataSource.swift # Data source protocol
├── PaginationManager.swift # @Observable manager
├── SearchablePaginationManager.swift # Optional: search + pagination
└── Views/
├── PaginatedList.swift # Infinite scroll wrapper
├── LoadMoreButton.swift # Manual load-more
└── PaginationStateView.swift # Empty/loading/error states
Define a data source:
struct UsersDataSource: PaginatedDataSource {
typealias Item = User
let apiClient: APIClient
func fetch(page: PageRequest) async throws -> PaginatedResponse<User> {
try await apiClient.request(UsersEndpoint(page: page.page, size: page.size))
}
}
Use PaginationManager in a view model:
@Observable
final class UsersViewModel {
let pagination: PaginationManager<UsersDataSource>
init(apiClient: APIClient) {
pagination = PaginationManager(
dataSource: UsersDataSource(apiClient: apiClient)
)
}
}
With SwiftUI (infinite scroll):
struct UsersListView: View {
@State private var viewModel = UsersViewModel()
var body: some View {
PaginatedList(manager: viewModel.pagination) { user in
UserRow(user: user)
}
.task {
await viewModel.pagination.loadFirstPage()
}
}
}
With search:
struct SearchableUsersView: View {
@State private var searchManager = SearchablePaginationManager(
dataSource: UsersDataSource()
)
var body: some View {
PaginatedList(manager: searchManager.pagination) { user in
UserRow(user: user)
}
.searchable(text: $searchManager.query)
}
}
@Test
func loadFirstPagePopulatesItems() async throws {
let mockSource = MockDataSource(items: User.mockList(count: 20))
let manager = PaginationManager(dataSource: mockSource, pageSize: 10)
await manager.loadFirstPage()
#expect(manager.items.count == 10)
#expect(manager.state == .loaded)
#expect(manager.hasMore == true)
}
@Test
func loadAllPagesReachesExhausted() async throws {
let mockSource = MockDataSource(items: User.mockList(count: 15))
let manager = PaginationManager(dataSource: mockSource, pageSize: 10)
await manager.loadFirstPage()
await manager.loadNextPage()
#expect(manager.items.count == 15)
#expect(manager.state == .exhausted)
}
generators/networking-layer — Base networking layer for data sourcesgenerators/http-cache — Cache paginated responsesdevelopment
US web checkout via the StoreKit External Purchase Link entitlement — currently 0% Apple commission (litigation ongoing), how to ship it safely, and how to architect for a commission flip so a future ruling is a config change, not a rewrite. Use when adding external purchase links, weighing web checkout vs IAP, or planning US-storefront pricing strategy.
tools
Revenue beyond the single-app price tag — own-app bundles, Family Sharing as a conversion lever, cross-developer bundles & suites, and institutional licensing via Group Purchases / Apple School & Business Manager. Use when a developer has multiple apps, a subscription worth sharing, complementary indie partners, or school/clinic/business buyers.
testing
Run a structured accessibility audit on an iOS/macOS app — automated XCUITest audits, Accessibility Inspector, manual VoiceOver/Dynamic Type passes, and App Store Accessibility Nutrition Label evaluation. Use before release, when preparing Nutrition Label declarations, or for EU Accessibility Act compliance.
tools
Stage-by-stage audit of an app's App Store growth machinery against a 54-item P0–P9 playbook — every item scored from an App Store Connect MCP call, a codebase check, or an explicit question to the user, then routed to the skill or command that fixes it. Read-only on App Store Connect. Use for a growth audit or scorecard, a pre-launch growth plan, a quarterly re-audit, or "which growth levers am I missing."