RepoPilotOpen in app →

louisdh/panelkit

A UI framework that enables panels on iOS.

Mixed

Stale — last commit 7y ago

worst of 4 axes
Use as dependencyMixed

last commit was 7y ago; top contributor handles 99% of recent commits…

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • 2 active contributors
  • MIT licensed
  • CI configured
Show 4 more →
  • Stale — last commit 7y ago
  • Small team — 2 contributors active in recent commits
  • Single-maintainer risk — top contributor 99% of recent commits
  • No test directory detected
What would change the summary?
  • Use as dependency MixedHealthy if: 1 commit in the last 365 days; diversify commit ownership (top <90%)

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Forkable" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Forkable
[![RepoPilot: Forkable](https://repopilot.app/api/badge/louisdh/panelkit?axis=fork)](https://repopilot.app/r/louisdh/panelkit)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/louisdh/panelkit on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: louisdh/panelkit

Generated by RepoPilot · 2026-05-10 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/louisdh/panelkit shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

WAIT — Stale — last commit 7y ago

  • 2 active contributors
  • MIT licensed
  • CI configured
  • ⚠ Stale — last commit 7y ago
  • ⚠ Small team — 2 contributors active in recent commits
  • ⚠ Single-maintainer risk — top contributor 99% of recent commits
  • ⚠ No test directory detected

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live louisdh/panelkit repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/louisdh/panelkit.

What it runs against: a local clone of louisdh/panelkit — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in louisdh/panelkit | Confirms the artifact applies here, not a fork | | 2 | License is still MIT | Catches relicense before you depend on it | | 3 | Default branch master exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 2668 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>louisdh/panelkit</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of louisdh/panelkit. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/louisdh/panelkit.git
#   cd panelkit
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of louisdh/panelkit and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "louisdh/panelkit(\\.git)?\\b" \\
  && ok "origin remote is louisdh/panelkit" \\
  || miss "origin remote is not louisdh/panelkit (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
  && ok "license is MIT" \\
  || miss "license drift — was MIT at generation time"

# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
  && ok "default branch master exists" \\
  || miss "default branch master no longer exists"

# 4. Critical files exist
test -f "PanelKit/PanelManager/PanelManager.swift" \\
  && ok "PanelKit/PanelManager/PanelManager.swift" \\
  || miss "missing critical file: PanelKit/PanelManager/PanelManager.swift"
test -f "PanelKit/Controller/PanelViewController.swift" \\
  && ok "PanelKit/Controller/PanelViewController.swift" \\
  || miss "missing critical file: PanelKit/Controller/PanelViewController.swift"
test -f "PanelKit/PanelContentDelegate/PanelContentDelegate.swift" \\
  && ok "PanelKit/PanelContentDelegate/PanelContentDelegate.swift" \\
  || miss "missing critical file: PanelKit/PanelContentDelegate/PanelContentDelegate.swift"
test -f "PanelKit/Model/PanelFloatingState.swift" \\
  && ok "PanelKit/Model/PanelFloatingState.swift" \\
  || miss "missing critical file: PanelKit/Model/PanelFloatingState.swift"
test -f "PanelKit/PanelManager/PanelManager+Dragging.swift" \\
  && ok "PanelKit/PanelManager/PanelManager+Dragging.swift" \\
  || miss "missing critical file: PanelKit/PanelManager/PanelManager+Dragging.swift"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 2668 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~2638d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/louisdh/panelkit"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

PanelKit is a Swift UI framework that enables flexible panel presentation on iOS, supporting modal, popover, floating (draggable), and pinned (left/right sidebar) layouts. It handles the complex gesture interactions, keyboard avoidance, and layout mechanics automatically, letting developers define panels by implementing the PanelContentDelegate protocol on any UIViewController. Single-framework design: PanelKit.xcodeproj is the main library (source in PanelKit/ directory, inferred from podspec). Example/ contains a reference app with sample panel types (MapPanelContentViewController, TextPanelContentViewController). Test targets include PanelKit Test Host (unit tests) and PanelKit UI Test Host (UI tests), following standard Xcode structure.

👥Who it's for

iOS app developers building multi-panel UIs (like note-taking apps, productivity tools, or creative software) who need drag-and-drop panels, pinning behavior, and keyboard-aware layout without building custom view controller presentation logic.

🌱Maturity & risk

Actively maintained but modest scale—137KB Swift codebase with CI/CD via Travis CI and Codecov integration. The framework predates SwiftUI (last major updates align with Swift 4.1 era) and shows stable API design, but commit recency and test coverage metrics are not visible in provided data. Production-ready for UIKit-based apps but not actively gaining new features.

Single maintainer (louisdh) with no visible recent activity timestamps raises sustainability risk. Minimal dependencies (only standard UIKit) lowers technical debt risk, but the UIKit-only stance means no SwiftUI support—risky for projects migrating to modern iOS. No visible open issue backlog or PR activity provided, making it hard to assess community responsiveness.

Active areas of work

No specific active development visible in provided file list. The codebase appears stable and mature; the presence of .travis.yml, .codecov.yml, and .tailor.yml indicates automated quality gates were set up but no recent changes are evident. CHANGELOG.md exists but content not provided.

🚀Get running

Check README for instructions.

Daily commands: open PanelKit.xcodeproj in Xcode, select Example scheme, then Run (⌘R). For tests: select PanelKit Test Host or PanelKit UI Test Host scheme and Run.

🗺️Map of the codebase

  • PanelKit/PanelManager/PanelManager.swift — Core orchestrator managing all panel lifecycle, state, and interactions—the primary entry point for understanding panel management.
  • PanelKit/Controller/PanelViewController.swift — Central UIViewController subclass representing a single panel; handles display, gestures, and core panel behavior.
  • PanelKit/PanelContentDelegate/PanelContentDelegate.swift — Protocol defining how content controllers communicate with the panel system; essential for integrating custom panel content.
  • PanelKit/Model/PanelFloatingState.swift — Enum capturing panel states (floating, pinned, offscreen); critical for understanding state machine and transitions.
  • PanelKit/PanelManager/PanelManager+Dragging.swift — Handles gesture recognition and drag mechanics; core interaction logic for moving and resizing panels.
  • PanelKit/PanelManager/PanelManager+Pinning.swift — Manages panel pinning/unpinning and repositioning logic; essential for understanding panel layout constraints.
  • PanelKit/Controller/PanelViewController+States.swift — State transition and notification logic for individual panels; required reading for lifecycle understanding.

🛠️How to make changes

Add a new Panel to an existing PanelManager

  1. Create a content view controller conforming to PanelContentDelegate (inherit from UIViewController) (PanelKit/PanelContentDelegate/PanelContentDelegate.swift)
  2. Implement optional delegate methods (e.g., panelContentWantsToBeginDragging, preferredPanelHeight) in your content controller (PanelKit/PanelContentDelegate/PanelContentDelegate+Default.swift)
  3. Create a PanelViewController, passing your content controller as the contentViewController property (PanelKit/Controller/PanelViewController.swift)
  4. Add the panel to your PanelManager instance using addPanel(_:) (PanelKit/PanelManager/PanelManager.swift)

Customize Panel Appearance & Behavior

  1. Access the panel's appearance properties (shadowOpacity, cornerRadius, etc.) through the PanelViewController instance (PanelKit/Controller/PanelViewController+Appearance.swift)
  2. Set preferred dimensions and pinning behavior via PanelContentDelegate in your content controller (PanelKit/PanelContentDelegate/PanelContentDelegate.swift)
  3. Override resize start behavior or constraints via panelDidStartResizing in PanelContentDelegate (PanelKit/Model/ResizeStart.swift)

Persist & Restore Panel Layout

  1. Call panelManager.saveState() to serialize all panel states (positions, pinned sides, etc.) (PanelKit/PanelManager/PanelManager+State.swift)
  2. Retrieve states via PanelStateCoder to encode/decode PanelState objects to disk (PanelKit/State Restoration/PanelStateCoder.swift)
  3. On app relaunch, restore by passing the saved states back to the PanelManager (PanelKit/State Restoration/PanelState.swift)

Handle Pinning & Floating State Transitions

  1. Monitor state changes by implementing panelDidChangeFloatingState in PanelContentDelegate (PanelKit/PanelContentDelegate/PanelContentDelegate.swift)
  2. Trigger programmatic pins/unpins via panelManager.pin(panel:side:) (PanelKit/PanelManager/PanelManager+Pinning.swift)
  3. Observe auto-transitions in PanelViewController+States for state change notifications (PanelKit/Controller/PanelViewController+States.swift)

🔧Why these technologies

  • UIViewController hierarchy — PanelKit wraps content in PanelViewController, enabling clean separation of panel chrome (dragging, pinning) from content logic.
  • AutoLayout & NSLayoutConstraint — Dynamic constraint management allows panels to smoothly transition between states (floating, pinned, offscreen) and adapt to keyboard/device rotation.
  • Protocol-based delegation (PanelContentDelegate) — Decouples content view controllers from framework internals; content only needs to implement optional delegate methods to customize behavior.
  • State enums (PanelFloatingState, PanelPinSide) — Type-safe state representation prevents invalid state transitions and makes intent explicit in code.
  • UIGestureRecognizer subclassing — Custom gesture recognizers with closure callbacks simplify drag/resize handling without complex delegate chains.

⚖️Trade-offs already made

  • Single PanelManager per view hierarchy

    • Why: Simplifies coordination of multiple panels and prevents conflicting state changes.
    • Consequence: Apps with multiple independent panel regions need multiple PanelManager instances; coordination overhead increases.
  • Pinning limited to left/right sides only

    • Why: Reduces complexity and covers most iOS app layouts (iPad split-view, sidebar patterns).
    • Consequence: Top/bottom pinning not supported; apps needing other layouts must use floating mode only.

🪤Traps & gotchas

Swift version constraint (.swift-version file) likely pins to Swift 4.1+; verify Xcode version compatibility. PanelKit relies on UIKit's view controller presentation APIs which behave differently on iPad vs iPhone and differ between iOS versions—test on target OS versions. Keyboard avoidance logic is built-in but may conflict with custom keyboard handling in panel content views. No SwiftUI support means it cannot be used in SwiftUI-first projects without wrapping UIViewControllers.

🏗️Architecture

💡Concepts to learn

  • UIPanGestureRecognizer — Core to PanelKit's dragging behavior; understanding gesture state machine (began, changed, ended, cancelled) is essential to modifying panel movement logic
  • UIViewControllerTransitioningDelegate — PanelKit likely uses custom transitions to animate panel presentation (modal/popover); mastering this protocol unlocks custom animation customization
  • Protocol-Based View Controller Composition — PanelKit's design pattern (PanelContentDelegate, PanelManager as protocols, not base classes) enables flexible composition without deep inheritance; critical for understanding how to extend it
  • Safe Area Insets & Keyboard Notifications — Panel layout must respect safe areas and respond to UIKeyboardWillShow/Hide notifications for keyboard avoidance; these iOS-specific concepts drive PanelKit's layout logic
  • CGAffineTransform for Gesture Translation — Dragging panels involves translating views via CGAffineTransform or frame updates; understanding transform composition is needed to debug/modify panel movement
  • View Controller Containment (addChild/removeFromParent) — PanelViewController embeds user content UIViewControllers as children; proper containment lifecycle management prevents memory leaks and controller state issues
  • MrRaindrop/PanelScrollViewController — Alternative iOS panel framework using scroll-based disclosure, contrasts with PanelKit's gesture-driven approach
  • hackiftekhar/IQKeyboardManager — Complementary library handling keyboard avoidance; PanelKit includes this logic internally but this repo is the de-facto standard for iOS keyboard management
  • ramotion/paper-switch — Another Ramotion gesture-heavy iOS component; shows similar custom UIView interaction patterns
  • material-components/material-components-ios — Google's Material Design components for iOS; includes MDC sheets and panels as reference implementations of panel-like UI patterns
  • louisdh/openterm — Author's other open-source iOS app; likely uses PanelKit or provides real-world usage context

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add comprehensive unit tests for PanelViewController state management

The repo has PanelViewController+States.swift managing panel states, but the test coverage appears incomplete (only UI tests exist in PanelKit UI Tests/). Unit tests for state transitions (collapsed, expanded, closed) would improve reliability and catch regressions. This is critical since state management is core to the framework.

  • [ ] Create Tests/PanelViewControllerStatesTests.swift with unit tests for PanelViewController+States.swift
  • [ ] Add tests for state transition logic (valid/invalid transitions)
  • [ ] Test state change callbacks and delegation
  • [ ] Verify state persistence edge cases (keyboard shown, dragging interrupts, etc.)
  • [ ] Update .codecov.yml to track new test coverage

Add unit tests for PanelViewController dragging and resize behaviors

PanelViewController+Dragging.swift and PanelViewController+Resize.swift contain gesture handling logic that lacks dedicated unit tests. These features are complex (touch tracking, gesture conflicts) and deserve isolated testing separate from UI tests to catch bugs early.

  • [ ] Create Tests/PanelViewControllerDraggingTests.swift with gesture recognizer mocking
  • [ ] Test drag threshold detection and panel movement calculations
  • [ ] Create Tests/PanelViewControllerResizeTests.swift for resize handle interactions
  • [ ] Test resize boundary constraints and animation handling
  • [ ] Verify gesture conflicts and cancellation scenarios

Migrate from Travis CI to GitHub Actions with Swift-specific workflow

The repo uses .travis.yml (outdated CI service with declining ecosystem support) when GitHub Actions is now standard. This would modernize the CI/CD pipeline, improve integration with GitHub's native tooling, and reduce external dependencies. The .swift-version file suggests Swift version pinning that should be reflected in the workflow.

  • [ ] Create .github/workflows/swift-tests.yml with Swift build/test matrix (iOS simulator)
  • [ ] Include SwiftLint validation step (referenced in .tailor.yml/.codeclimate.yml)
  • [ ] Add codecov upload step matching current .codecov.yml configuration
  • [ ] Test against multiple Swift/iOS versions (parse from .swift-version and PanelKit.podspec)
  • [ ] Remove or deprecate .travis.yml with migration notice in README

🌿Good first issues

  • Add unit tests for keyboard avoidance behavior in PanelViewController by creating XCTest cases in the PanelKit Test Host target, mimicking the MapPanelContentViewController and TextPanelContentViewController setups
  • Document the PanelManager initialization and configuration in a new IMPLEMENTATION_GUIDE.md file, with code examples extracted from Example/Example/ViewController.swift showing each panel presentation mode (modal, popover, floating, pinned)
  • Add SwiftUI wrapper convenience initializers (PanelViewController extensions) to support modern iOS projects, starting with a simple UIViewControllerRepresentable bridge in a new SwiftUI subdirectory

Top contributors

Click to expand

📝Recent commits

Click to expand
  • 71d105a — Update isFloating check (louisdh)
  • 394d7e0 — isFloating -> false when manager doesn't allow floating panels. (louisdh)
  • d5803e6 — Fix panel pinned positions (louisdh)
  • 63fef93 — Fix test (louisdh)
  • 842750b — Add third panel to example (louisdh)
  • e628eb1 — Use live shadow to prevent glitches when unpinning. (louisdh)
  • 1b520db — Improve unpinning (louisdh)
  • 5fed68f — Improve drag handling (louisdh)
  • b1d9cc6 — Only allow panel dragging on navigationBar (louisdh)
  • 561ac3d — Add hideCloseButtonWhilePinned API (louisdh)

🔒Security observations

The PanelKit codebase is a UI framework for iOS with moderate security posture. Primary concerns are outdated development infrastructure (Swift 4.1, Travis CI) and lack of formal security documentation. The framework itself appears to follow iOS UI patterns without obvious injection vulnerabilities or hardcoded secrets. Immediate actions should focus on: 1) Upgrading Swift and build infrastructure to current versions, 2) Establishing a security policy, and 3) Conducting code review of custom implementations like gesture handling and associated objects. The absence of a package dependency file in the provided structure prevents assessment of third-party dependency security.

  • Medium · Outdated Swift Version — .swift-version. The .swift-version file indicates Swift 4.1 is being used. This version is significantly outdated (released in 2018) and likely contains known security vulnerabilities and bugs that have been patched in newer Swift releases. Fix: Update to the latest stable Swift version (5.9 or later). Ensure all dependencies and code are compatible with the newer version.
  • Medium · Outdated Build Infrastructure — .travis.yml. The .travis.yml configuration file indicates use of Travis CI, which is an older CI/CD platform. Modern alternatives with better security practices are available. Additionally, Travis CI has been deprecated for open-source projects. Fix: Migrate to modern CI/CD platforms such as GitHub Actions, GitLab CI, or CircleCI with security scanning capabilities enabled.
  • Low · Missing Security Configuration Files — Repository root. No evidence of SECURITY.md or security policy documentation. The repository lacks clear guidelines for responsible vulnerability disclosure. Fix: Create a SECURITY.md file with a responsible disclosure policy and contact information for security researchers to report vulnerabilities privately.
  • Low · Potential Insecure Deserialization Risk in AssociatedObject — PanelKit/Model/AssociatedObject.swift. The file 'PanelKit/Model/AssociatedObject.swift' suggests use of associated objects, which could potentially involve object serialization/deserialization. Without reviewing the source code, this represents a potential attack surface if not properly validated. Fix: Review AssociatedObject implementation to ensure: 1) No untrusted data is deserialized, 2) Proper type validation is performed, 3) No arbitrary code execution paths exist.
  • Low · Custom Gesture Recognizer Implementation — PanelKit/Model/BlockGestureRecognizer.swift. The 'BlockGestureRecognizer.swift' file suggests custom gesture handling logic. Custom gesture recognizers can be a vector for input validation bypass or unexpected behavior if not properly implemented. Fix: Review the BlockGestureRecognizer implementation to ensure: 1) Proper input validation, 2) No race conditions, 3) Thread-safe operations, 4) Proper cleanup of gesture state.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Mixed signals · louisdh/panelkit — RepoPilot