docs: complete project research
This commit is contained in:
@@ -1,179 +1,198 @@
|
||||
# Technology Stack -- v1.2 Collection Power-Ups
|
||||
# Stack Research -- v1.3 Research & Decision Tools
|
||||
|
||||
**Project:** GearBox
|
||||
**Researched:** 2026-03-16
|
||||
**Scope:** Stack additions for search/filter, weight classification, weight distribution charts, candidate status tracking, weight unit selection
|
||||
**Scope:** Stack additions for side-by-side candidate comparison, setup impact preview, and drag-to-reorder candidate ranking with pros/cons
|
||||
**Confidence:** HIGH
|
||||
|
||||
## Key Finding: Minimal New Dependencies
|
||||
## Key Finding: Zero New Dependencies
|
||||
|
||||
Four of five v1.2 features require **zero new libraries**. They are pure application logic built on top of the existing stack (Drizzle ORM filters, Zod schema extensions, Zustand state, React Query invalidation). The only decision point is whether to add a charting library for weight distribution visualization.
|
||||
All three v1.3 features are achievable with the existing stack. The drag-to-reorder feature, which would normally require a dedicated DnD library, is covered by `framer-motion`'s built-in `Reorder` component — already installed at v12.37.0 with React 19 support confirmed.
|
||||
|
||||
## New Dependency
|
||||
## Recommended Stack: Existing Technologies Only
|
||||
|
||||
### Charting: react-minimal-pie-chart
|
||||
### No New Dependencies Required
|
||||
|
||||
| Technology | Version | Purpose | Why |
|
||||
|------------|---------|---------|-----|
|
||||
| react-minimal-pie-chart | ^9.1.2 | Weight distribution donut/pie charts | Under 2kB gzipped. Supports pie, donut, loading, and completion chart types. SVG-based with CSS animations, hover/click interactions, custom label rendering. React 19 compatible (peerDeps explicitly include `^19`). Zero external dependencies. TypeScript native. |
|
||||
| Feature | Library Needed | Status |
|
||||
|---------|---------------|--------|
|
||||
| Side-by-side comparison view | None — pure layout/UI | Existing Tailwind CSS |
|
||||
| Setup impact preview | None — SQL delta calculation | Existing Drizzle ORM + TanStack Query |
|
||||
| Drag-to-reorder candidates | `Reorder` component | Already in `framer-motion@12.37.0` |
|
||||
| Pros/cons text fields | None — schema + form | Existing Drizzle + Zod + React |
|
||||
|
||||
**Why this over alternatives:**
|
||||
### How Each Feature Uses the Existing Stack
|
||||
|
||||
| Criterion | react-minimal-pie-chart | Recharts | Custom SVG | Chart.js |
|
||||
|-----------|------------------------|----------|------------|----------|
|
||||
| Bundle size | ~2kB gzipped | ~97kB gzipped | 0kB | ~60kB gzipped |
|
||||
| Chart types needed | Pie + donut (exactly what we need) | Overkill (line, bar, area, scatter, etc.) | Manual math | Overkill |
|
||||
| React 19 support | Explicit in peerDeps | Isolated rendering issues reported with 19.2.x | N/A | Wrapper has open React 19 issues |
|
||||
| Interactivity | Click, hover, focus, keyboard events per segment | Full but heavy | Must implement from scratch | Canvas-based (harder to style) |
|
||||
| Labels | Render prop for custom labels (percentage, value, SVG) | Built-in | Must implement | Built-in |
|
||||
| Animation | CSS-based, configurable duration/easing, reveal effect | D3-based, heavier | Must implement | Canvas animation |
|
||||
| Learning curve | Minimal -- one component, straightforward props | Moderate -- many components | High -- SVG arc math | Moderate |
|
||||
| Maintenance risk | Low -- tiny surface area, stable API | Low -- large community | Zero | Medium -- Canvas abstraction |
|
||||
#### 1. Side-by-Side Candidate Comparison
|
||||
|
||||
**Why not custom SVG:** The SVG `<circle>` + `stroke-dasharray` approach works for static charts but breaks interactivity (stacked circles mean only the last segment is clickable). The `<path>` arc approach gives full interactivity but requires implementing arc math, animation, labels, hover states, and accessibility from scratch. At ~2kB, react-minimal-pie-chart costs less than the custom code would and handles all edge cases.
|
||||
|
||||
**Why not Recharts:** GearBox needs exactly one chart type (donut/pie). Recharts adds ~97kB of unused capability. It also had isolated rendering issues reported with React 19.2.x, and pulls in D3 submodules. Significant overkill for this use case.
|
||||
|
||||
## Existing Stack Usage for Each Feature
|
||||
|
||||
### 1. Search/Filter Items
|
||||
|
||||
**No new dependencies.** Uses existing Drizzle ORM operators and React state.
|
||||
**No schema changes. No new dependencies.**
|
||||
|
||||
| Existing Tech | How It Is Used |
|
||||
|---------------|----------------|
|
||||
| Drizzle ORM `like()` | Server-side text search on `items.name` column. SQLite LIKE is case-insensitive by default, so no need for `ilike()`. |
|
||||
| Drizzle ORM `eq()`, `and()` | Category filter: `eq(items.categoryId, selectedId)`. Combine with search: `and(like(...), eq(...))`. |
|
||||
| TanStack Query | New query key pattern: `["items", { search, categoryId }]` for filtered results. Server-side filtering preferred over client-side to establish the pattern early (collections grow). |
|
||||
| Zustand or URL search params | Store active filter state. URL search params preferred (already used for tab state) so filter state is shareable/bookmarkable. |
|
||||
| Zod | Validate query params on the Hono route: `z.object({ search: z.string().optional(), categoryId: z.number().optional() })`. |
|
||||
| Tailwind CSS v4 | Responsive comparison table layout. Horizontal scroll on mobile with `overflow-x-auto`. Fixed first column (row labels) using `sticky left-0`. |
|
||||
| TanStack Query (`useThread`) | Thread detail already fetches all candidates in one query. Comparison view reads from the same cached data — no new API endpoint. |
|
||||
| Lucide React | Comparison row icons (weight, price, status, link). Already in the curated icon set. |
|
||||
| `formatWeight` / `formatPrice` | Existing formatters handle display with selected unit/currency. No changes needed. |
|
||||
| `useWeightUnit` / `useCurrency` | Existing hooks provide formatting context. Comparison view uses them identically to `CandidateCard`. |
|
||||
|
||||
**Implementation approach:** Add query parameters to `GET /api/items` rather than client-side filtering. Drizzle's conditional filter pattern handles optional params cleanly:
|
||||
**Implementation approach:** Add a view toggle (grid vs. comparison table) to the thread detail page. The comparison view is a `<table>` or CSS grid with candidates as columns and attributes as rows. Data already lives in `useThread` response — no API changes.
|
||||
|
||||
#### 2. Setup Impact Preview
|
||||
|
||||
**No new dependencies. Requires one new API endpoint.**
|
||||
|
||||
| Existing Tech | How It Is Used |
|
||||
|---------------|----------------|
|
||||
| Drizzle ORM | New query: for a given setup, sum `weight_grams` and `price_cents` of its items. Then compute delta against each candidate's `weight_grams` and `price_cents`. Pure arithmetic in the service layer. |
|
||||
| TanStack Query | New `useSetupImpact(threadId, setupId)` hook fetching `GET /api/threads/:threadId/impact?setupId=X`. Returns array of `{ candidateId, weightDelta, costDelta }`. |
|
||||
| Hono + Zod validator | New route validates `setupId` query param. Delegates to service function. |
|
||||
| `formatWeight` / `formatPrice` | Format deltas with `+` prefix for positive values (candidate adds weight/cost) and `-` for negative (candidate is lighter/cheaper than what's already in setup). |
|
||||
| `useSetups` hook | Existing `useSetups()` provides the setup list for the picker dropdown. |
|
||||
|
||||
**Delta calculation logic (server-side service):**
|
||||
|
||||
```typescript
|
||||
import { like, eq, and } from "drizzle-orm";
|
||||
// For each candidate in thread:
|
||||
// weightDelta = candidate.weightGrams - (matching item in setup).weightGrams
|
||||
// If no matching item in setup (it would be added, not replaced): delta = candidate.weightGrams
|
||||
|
||||
const conditions = [];
|
||||
if (search) conditions.push(like(items.name, `%${search}%`));
|
||||
if (categoryId) conditions.push(eq(items.categoryId, categoryId));
|
||||
|
||||
db.select().from(items).where(and(...conditions));
|
||||
// A "matching item" means: item in setup with same categoryId as the thread.
|
||||
// This is the intended semantic: "how does picking this candidate affect my setup?"
|
||||
```
|
||||
|
||||
### 2. Weight Classification (Base/Worn/Consumable)
|
||||
**Key decision:** Impact preview is read-only and derived. It does not mutate any data. It computes what *would* happen if the candidate were picked, without modifying the setup. The delta is displayed inline on each candidate card or in the comparison view.
|
||||
|
||||
**No new dependencies.** Schema change + UI state.
|
||||
#### 3. Drag-to-Reorder Candidate Ranking with Pros/Cons
|
||||
|
||||
**No new DnD library. Requires schema changes.**
|
||||
|
||||
| Existing Tech | How It Is Used |
|
||||
|---------------|----------------|
|
||||
| Drizzle ORM | Add `weightClass` column to `setup_items` table: `text("weight_class").notNull().default("base")`. Classification is per-setup-item, not per-item globally (a sleeping bag is "base" in a bikepacking setup but might be categorized differently elsewhere). |
|
||||
| Zod | Extend `syncSetupItemsSchema` to include classification: `z.enum(["base", "worn", "consumable"])`. |
|
||||
| drizzle-kit | Generate migration for the new column: `bun run db:generate`. |
|
||||
| SQL aggregates | Compute base/worn/consumable weight subtotals server-side, same pattern as existing category totals in `useTotals`. |
|
||||
| `framer-motion@12.37.0` `Reorder` | `Reorder.Group` wraps the candidate list. `Reorder.Item` wraps each candidate card. `onReorder` updates local order state. `onDragEnd` fires the persist mutation. |
|
||||
| Drizzle ORM | Two new columns on `thread_candidates`: `sortOrder integer` (default 0, lower = higher rank) and `pros text` / `cons text` (nullable). |
|
||||
| TanStack Query mutation | `usePatchCandidate` for pros/cons text updates. `useReorderCandidates` for bulk sort order update after drag-end. |
|
||||
| Hono + Zod validator | `PATCH /api/threads/:threadId/candidates/reorder` accepts `{ candidates: Array<{ id, sortOrder }> }`. `PATCH /api/candidates/:id` accepts `{ pros?, cons? }`. |
|
||||
| Zod | Extend `updateCandidateSchema` with `pros: z.string().nullable().optional()`, `cons: z.string().nullable().optional()`, `sortOrder: z.number().int().optional()`. |
|
||||
|
||||
**Key design decision:** Weight classification belongs on `setup_items` (the join table), not on `items` directly. An item's classification depends on context -- hiking poles are "worn" if you always use them, "base" if they pitch your tent. LighterPack follows this same model. This means the `syncSetupItemsSchema` changes from `{ itemIds: number[] }` to `{ items: Array<{ itemId: number, weightClass: "base" | "worn" | "consumable" }> }`.
|
||||
**Framer Motion `Reorder` API pattern:**
|
||||
|
||||
### 3. Weight Distribution Charts
|
||||
```typescript
|
||||
import { Reorder } from "framer-motion";
|
||||
|
||||
**One new dependency:** `react-minimal-pie-chart` (documented above).
|
||||
// State holds candidates sorted by sortOrder
|
||||
const [orderedCandidates, setOrderedCandidates] = useState(
|
||||
[...candidates].sort((a, b) => a.sortOrder - b.sortOrder)
|
||||
);
|
||||
|
||||
| Existing Tech | How It Is Used |
|
||||
|---------------|----------------|
|
||||
| TanStack Query (`useTotals`) | Already returns per-category weight totals. Extend to also return per-weight-class totals for a given setup. |
|
||||
| Tailwind CSS | Style chart container, legend, responsive layout. Chart labels use Tailwind color tokens for consistency. |
|
||||
| Lucide React | Category icons in the chart legend, consistent with existing CategoryHeader component. |
|
||||
// onReorder fires continuously during drag — update local state only
|
||||
// onDragEnd fires once on drop — persist to DB
|
||||
<Reorder.Group
|
||||
axis="y"
|
||||
values={orderedCandidates}
|
||||
onReorder={setOrderedCandidates}
|
||||
>
|
||||
{orderedCandidates.map((candidate) => (
|
||||
<Reorder.Item
|
||||
key={candidate.id}
|
||||
value={candidate}
|
||||
onDragEnd={() => persistOrder(orderedCandidates)}
|
||||
>
|
||||
<CandidateCard ... />
|
||||
</Reorder.Item>
|
||||
))}
|
||||
</Reorder.Group>
|
||||
```
|
||||
|
||||
**Chart data sources:**
|
||||
- **By category:** Already available from `GET /api/totals` response (`categories` array with `totalWeight` per category). No new endpoint needed.
|
||||
- **By weight classification:** New endpoint `GET /api/setups/:id/breakdown` returning `{ base: number, worn: number, consumable: number }` computed from the `weight_class` column on `setup_items`.
|
||||
**Schema changes required:**
|
||||
|
||||
### 4. Candidate Status Tracking
|
||||
| Table | Column | Type | Default | Purpose |
|
||||
|-------|--------|------|---------|---------|
|
||||
| `thread_candidates` | `sort_order` | `integer NOT NULL` | `0` | Rank position (lower = higher rank) |
|
||||
| `thread_candidates` | `pros` | `text` | `NULL` | Free-text pros annotation |
|
||||
| `thread_candidates` | `cons` | `text` | `NULL` | Free-text cons annotation |
|
||||
|
||||
**No new dependencies.** Schema change + UI update.
|
||||
|
||||
| Existing Tech | How It Is Used |
|
||||
|---------------|----------------|
|
||||
| Drizzle ORM | Add `status` column to `thread_candidates` table: `text("status").notNull().default("researching")`. Values: `"researching"`, `"ordered"`, `"arrived"`. |
|
||||
| Zod | Add to `createCandidateSchema` and `updateCandidateSchema`: `status: z.enum(["researching", "ordered", "arrived"]).default("researching")`. |
|
||||
| Tailwind CSS | Status badge colors on CandidateCard (gray for researching, amber for ordered, green for arrived). Same badge pattern used for thread status already. |
|
||||
| Lucide React | Status icons: `search` for researching, `truck` for ordered, `check-circle` for arrived. Already in the curated icon set. |
|
||||
|
||||
### 5. Weight Unit Selection
|
||||
|
||||
**No new dependencies.** Settings storage + formatter change.
|
||||
|
||||
| Existing Tech | How It Is Used |
|
||||
|---------------|----------------|
|
||||
| SQLite `settings` table | Store preferred unit: `{ key: "weightUnit", value: "g" }`. Same pattern as existing onboarding settings. |
|
||||
| React Query (`useSettings`) | Already exists. Fetch and cache the weight unit preference. |
|
||||
| `formatWeight()` in `lib/formatters.ts` | Extend to accept a unit parameter and convert from grams (the canonical storage format). |
|
||||
| Zustand (optional) | Could cache the unit preference in UI store for synchronous access in formatters. Alternatively, pass it through React context or as a parameter. |
|
||||
|
||||
**Conversion constants (stored weights are always grams):**
|
||||
|
||||
| Unit | From Grams | Display Format |
|
||||
|------|-----------|----------------|
|
||||
| g (grams) | `x` | `${Math.round(x)}g` |
|
||||
| oz (ounces) | `x / 28.3495` | `${(x / 28.3495).toFixed(1)}oz` |
|
||||
| lb (pounds) | `x / 453.592` | `${(x / 453.592).toFixed(2)}lb` |
|
||||
| kg (kilograms) | `x / 1000` | `${(x / 1000).toFixed(2)}kg` |
|
||||
|
||||
**Key decision:** Store weights in grams always. Convert on display only. This avoids precision loss from repeated conversions and keeps the database canonical. The `formatWeight` function becomes the single conversion point.
|
||||
**Sort order persistence pattern:** On drag-end, send the full reordered array with new `sortOrder` values (0-based index positions). Backend replaces existing `sort_order` values atomically. This is the same delete-all + re-insert pattern used for `setupItems` but as an UPDATE instead.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
# Only new dependency for v1.2
|
||||
bun add react-minimal-pie-chart
|
||||
# No new packages. Zero.
|
||||
```
|
||||
|
||||
That is it. One package, under 2kB gzipped.
|
||||
All required capabilities are already installed.
|
||||
|
||||
## Schema Changes Summary
|
||||
## Alternatives Considered
|
||||
|
||||
These are the Drizzle schema modifications needed (no new tables, just column additions):
|
||||
### Drag and Drop: Why Not Add a Dedicated Library?
|
||||
|
||||
| Table | Change | Migration |
|
||||
|-------|--------|-----------|
|
||||
| `setup_items` | Add `weightClass: text("weight_class").notNull().default("base")` | `bun run db:generate && bun run db:push` |
|
||||
| `thread_candidates` | Add `status: text("status").notNull().default("researching")` | `bun run db:generate && bun run db:push` |
|
||||
| `settings` | No schema change (already key-value). Insert `weightUnit` row. | Seed via service or onboarding. |
|
||||
| Option | Version | React 19 Status | Verdict |
|
||||
|--------|---------|-----------------|---------|
|
||||
| `framer-motion` Reorder (already installed) | 12.37.0 | React 19 explicit peerDep (`^18.0.0 || ^19.0.0`) | USE THIS |
|
||||
| `@dnd-kit/core` + `@dnd-kit/sortable` | 6.3.1 | No React 19 support (stale ~1yr, open GitHub issue #1511) | AVOID |
|
||||
| `@dnd-kit/react` (new rewrite) | 0.3.2 | React 19 compatible | Pre-1.0, no maintainer ETA on stable |
|
||||
| `@hello-pangea/dnd` | 18.0.1 | No React 19 (stale ~1yr, peerDep `^18.0.0` only) | AVOID |
|
||||
| `pragmatic-drag-and-drop` | latest | Core is React-agnostic but some sub-packages missing React 19 | Overkill for a single sortable list |
|
||||
| Custom HTML5 DnD | N/A | N/A | 200+ lines of boilerplate, worse accessibility |
|
||||
|
||||
**Why framer-motion `Reorder` wins:** Already in the bundle. React 19 peer dep confirmed in lockfile. Handles the single use case (vertical sortable list) with 10 lines of code. Provides smooth layout animations at zero additional cost. The limitation (no cross-container drag, no multi-row grid) does not apply — candidate ranking is a single vertical list.
|
||||
|
||||
**Why not `@dnd-kit`:** The legacy `@dnd-kit/core@6.3.1` has no official React 19 support and has been unmaintained for ~1 year. The new `@dnd-kit/react@0.3.2` does support React 19 but is pre-1.0 with zero maintainer response on stability/roadmap questions (GitHub Discussion #1842 has 0 replies). Adding a pre-1.0 library when the project already has a working solution is unjustifiable.
|
||||
|
||||
### Setup Impact: Why Not Client-Side Calculation?
|
||||
|
||||
Client-side delta calculation (using cached React Query data) is simpler to implement but:
|
||||
- Requires loading both the full setup items list AND all candidates into the client
|
||||
- Introduces staleness bugs if setup items change in another tab
|
||||
- Is harder to test (service test vs. component test)
|
||||
|
||||
Server-side calculation in a service function is testable, authoritative, and consistent with the existing architecture (services compute aggregates, not components).
|
||||
|
||||
## What NOT to Add
|
||||
|
||||
| Avoid | Why | Use Instead |
|
||||
|-------|-----|-------------|
|
||||
| Recharts | 97kB for one chart type. React 19 edge-case issues. D3 dependency chain. | react-minimal-pie-chart (2kB) |
|
||||
| Chart.js / react-chartjs-2 | Canvas-based (harder to style with Tailwind). Open React 19 peer dep issues. Overkill. | react-minimal-pie-chart |
|
||||
| visx | Low-level D3 primitives. Steep learning curve. Have to build chart from scratch. Great for custom viz, overkill for a donut chart. | react-minimal-pie-chart |
|
||||
| Fuse.js or similar search library | Client-side fuzzy search adds bundle weight and complexity. SQLite LIKE is sufficient for name search on a single-user collection (hundreds of items, not millions). | Drizzle `like()` operator |
|
||||
| Full-text search (FTS5) | SQLite FTS5 is powerful but requires virtual tables and different query syntax. Overkill for simple name matching on small collections. | Drizzle `like()` operator |
|
||||
| i18n library for unit conversion | This is not internationalization. It is four conversion constants and a formatter function. A library would be absurd. | Custom `formatWeight()` function |
|
||||
| State machine library (XState) | Candidate status is a simple enum, not a complex state machine. Three values with no guards or side effects. | Zod enum + Drizzle text column |
|
||||
| New Zustand store for filters | Filter state should live in URL search params for shareability/bookmarkability. The collection page already uses this pattern for tabs. | TanStack Router search params |
|
||||
| `@dnd-kit/core` + `@dnd-kit/sortable` | No React 19 support, stale for ~1 year (latest 6.3.1 from 2024) | `framer-motion` Reorder (already installed) |
|
||||
| `@hello-pangea/dnd` | No React 19 support, peerDep `react: "^18.0.0"` only, stale | `framer-motion` Reorder |
|
||||
| `react-comparison-table` or similar component packages | Fragile third-party layouts for a simple table. Custom Tailwind table is trivial and design-consistent. | Custom Tailwind CSS table layout |
|
||||
| Modal/dialog library (Radix, Headless UI) | The project already has a hand-rolled modal pattern (`SlideOutPanel`, `ConfirmDialog`). Adding a library for one more dialog adds inconsistency. | Extend existing modal patterns |
|
||||
| Rich text editor for pros/cons | Markdown editors are overkill for a single-line annotation field. Users want a quick note, not a document. | Plain `<textarea>` with Tailwind styling |
|
||||
|
||||
## Existing Stack Version Compatibility
|
||||
## Stack Patterns by Variant
|
||||
|
||||
All existing dependencies remain unchanged. The only version consideration:
|
||||
**If the comparison view needs mobile scroll:**
|
||||
- Wrap comparison table in `overflow-x-auto`
|
||||
- Freeze the first column (attribute labels) with `sticky left-0 bg-white z-10`
|
||||
- This is pure CSS, no JavaScript or library needed
|
||||
|
||||
| New Package | Compatible With | Verified |
|
||||
|-------------|-----------------|----------|
|
||||
| react-minimal-pie-chart ^9.1.2 | React 19 (`peerDeps: "^16.8.0 \|\| ^17 \|\| ^18 \|\| ^19"`) | YES -- package.json on GitHub confirms. Dev deps test against React 19.0.0. |
|
||||
| react-minimal-pie-chart ^9.1.2 | TypeScript 5.x | YES -- library is TypeScript native (built with TS 3.8+). |
|
||||
| react-minimal-pie-chart ^9.1.2 | Bun bundler / Vite | YES -- pure ESM, no native dependencies, standard npm package. |
|
||||
**If the setup impact preview needs a setup picker:**
|
||||
- Use `useSetups()` (already exists) to populate a `<select>` dropdown
|
||||
- Store selected setup ID in local component state (not URL params — this is transient UI)
|
||||
- No new state management needed
|
||||
|
||||
**If pros/cons fields need to auto-save:**
|
||||
- Use a debounced mutation (300-500ms) that fires on `onChange`
|
||||
- Or save on `onBlur` (simpler, adequate for this use case)
|
||||
- Existing `useUpdateCandidate` hook already handles candidate mutations — extend schema only
|
||||
|
||||
## Version Compatibility
|
||||
|
||||
| Package | Version in Project | React 19 Compatible | Notes |
|
||||
|---------|-------------------|---------------------|-------|
|
||||
| `framer-motion` | 12.37.0 | YES — peerDeps `"^18.0.0 || ^19.0.0"` confirmed in lockfile | `Reorder` component available since v5 |
|
||||
| `drizzle-orm` | 0.45.1 | N/A (server-side) | ALTER TABLE or migration for new columns |
|
||||
| `zod` | 4.3.6 | N/A | Extend existing schemas |
|
||||
| `@tanstack/react-query` | 5.90.21 | YES | New hooks follow existing patterns |
|
||||
|
||||
## Sources
|
||||
|
||||
- [Drizzle ORM Filter Operators](https://orm.drizzle.team/docs/operators) -- `like`, `eq`, `and`, `or` operators for search/filter (HIGH confidence)
|
||||
- [Drizzle ORM Conditional Filters Guide](https://orm.drizzle.team/docs/guides/conditional-filters-in-query) -- dynamic filter composition pattern (HIGH confidence)
|
||||
- [react-minimal-pie-chart GitHub](https://github.com/toomuchdesign/react-minimal-pie-chart) -- version 9.1.2, React 19 peerDeps confirmed (HIGH confidence)
|
||||
- [react-minimal-pie-chart package.json](https://github.com/toomuchdesign/react-minimal-pie-chart/blob/master/package.json) -- React 19 in peerDependencies and devDependencies (HIGH confidence)
|
||||
- [Recharts npm](https://www.npmjs.com/package/recharts) -- v3.8.0, ~97kB bundle (HIGH confidence)
|
||||
- [Recharts React 19 issue #6857](https://github.com/recharts/recharts/issues/6857) -- rendering issues reported with React 19.2.3 (MEDIUM confidence -- may be project-specific)
|
||||
- [LighterPack weight classification model](https://lighterpack.com) -- base/worn/consumable terminology is industry standard for gear management (HIGH confidence)
|
||||
- [Pack Weight Calculator Guide](https://backpackpeek.com/blog/pack-weight-calculator-base-weight-guide) -- weight classification definitions (HIGH confidence)
|
||||
- [SQLite LIKE case sensitivity note](https://github.com/drizzle-team/drizzle-orm-docs/issues/239) -- LIKE is case-insensitive in SQLite, no need for ilike (MEDIUM confidence)
|
||||
- [framer-motion package lockfile entry] — peerDeps `react: "^18.0.0 || ^19.0.0"` confirmed (HIGH confidence, from project's `bun.lock`)
|
||||
- [Motion Reorder docs](https://motion.dev/docs/react-reorder) — `Reorder.Group`, `Reorder.Item`, `useDragControls` API, `onDragEnd` pattern for persisting order (HIGH confidence)
|
||||
- [Motion Changelog](https://motion.dev/changelog) — v12.37.0 actively maintained through Feb 2026 (HIGH confidence)
|
||||
- [@dnd-kit/core npm](https://www.npmjs.com/package/@dnd-kit/core) — v6.3.1, last published ~1 year ago, no React 19 support (HIGH confidence)
|
||||
- [dnd-kit React 19 issue #1511](https://github.com/clauderic/dnd-kit/issues/1511) — CLOSED but React 19 TypeScript issues confirmed (MEDIUM confidence)
|
||||
- [@dnd-kit/react roadmap discussion #1842](https://github.com/clauderic/dnd-kit/discussions/1842) — 0 maintainer replies on stability question (HIGH confidence — signals pre-1.0 risk)
|
||||
- [hello-pangea/dnd React 19 issue #864](https://github.com/hello-pangea/dnd/issues/864) — React 19 support still open as of Jan 2026 (HIGH confidence)
|
||||
- [Top 5 Drag-and-Drop Libraries for React 2026](https://puckeditor.com/blog/top-5-drag-and-drop-libraries-for-react) — ecosystem overview confirming dnd-kit and hello-pangea/dnd limitations (MEDIUM confidence)
|
||||
|
||||
---
|
||||
*Stack research for: GearBox v1.2 -- Collection Power-Ups*
|
||||
*Stack research for: GearBox v1.3 -- Research & Decision Tools*
|
||||
*Researched: 2026-03-16*
|
||||
|
||||
Reference in New Issue
Block a user