List View Component: Landscape Analysis
Date: 2026-03-16
Inventory of List and Grid Usage and Candidate Components
Section titled “Inventory of List and Grid Usage and Candidate Components”This analysis inventories all existing list and grid surfaces across the Arda front-end ecosystem to inform the scope of the List View Component project (GitHub #565). Three areas were surveyed:
- Production pages in
arda-frontend-appthat render entity lists. - Storybook stories in
ux-prototypethat demonstrate list or grid behavior. - Candidate components in
ux-prototypethat could serve as a basis for the new Canary-tier List View components.
The key finding is that two parallel grid implementations exist: a monolithic ArdaGrid wrapper in arda-frontend-app (85 KB) and a well-structured component hierarchy in ux-prototype/extras. The extras hierarchy already follows the Arda Component Design Guidelines (Static / Init / Runtime configuration, factory pattern) and has been exercised with two entity types (Items and Suppliers). However, all of this work lives in the Extras library and must not be referenced from the new Canary components per the project requirements.
The proposed Canary architecture defines five tiers. This project will deliver Tiers 1, 2, 3a, and 3b. Tier 4 (domain-specific grids) will be implemented later as part of individual domain stories.
1. Pages in arda-frontend-app That Display Entity Lists
Section titled “1. Pages in arda-frontend-app That Display Entity Lists”Six pages render collections of entities. Only the Items page uses AG Grid in production; the remaining pages use TanStack React Table, Shadcn table primitives, or plain .map() layouts.
| Page | Route | Entity | Grid Technology | Notes |
|---|---|---|---|---|
| Items | app/items/ | Inventory items | ArdaGrid (AG Grid) + legacy ItemTable (TanStack) | Primary grid — multi-select, sort, filter, pagination, cell editing. ItemTableAGGrid.tsx is ~75 KB. |
| Order Queue | app/order-queue/ | Orders to place | Custom .map() grouped layout | Grouped by order method and supplier. Not a tabular grid. |
| Receiving | app/receiving/ | Items in transit | Custom .map() grouped layout with tabs | Tabs: Waiting / Received / Recently Fulfilled. |
| Dashboard | app/dashboard/ | Recent orders | TanStack React Table + Shadcn primitives | Read-only summary table. |
| Company Settings | app/company-settings/ | Users | Custom .map() list | Avatar + role badge layout, not tabular. |
| Items Grid Test | app/items-grid-test/ | Items (mock) | ArdaGrid (AG Grid) | Non-production test page. |
Grid Infrastructure in arda-frontend-app
Section titled “Grid Infrastructure in arda-frontend-app”| File | Role |
|---|---|
/arda-frontend-app/src/components/table/ArdaGrid.tsx (~85 KB) | AG Grid forwardRef wrapper with sorting, filtering, pagination, cell editing, column persistence, and custom row actions. |
/arda-frontend-app/src/components/table/columnPresets.tsx | Column definition presets for Items and Orders. |
/arda-frontend-app/src/components/ui/table.tsx | Shadcn/Radix HTML table primitives (Table, TableHeader, TableBody, TableRow, TableCell). |
2. Stories in ux-prototype That Show Entity Lists
Section titled “2. Stories in ux-prototype That Show Entity Lists”Component Stories (Extras Section)
Section titled “Component Stories (Extras Section)”| Storybook Path | Component | Stories | Coverage |
|---|---|---|---|
Components/Extras/Molecules/DataGrid | ArdaDataGrid | 13 | Loading, empty, error, pagination, selection, cell editing, persistence, images |
Components/Extras/Organisms/Shared/Entity Data Grid | createArdaEntityDataGrid | 7 | Dirty tracking, column visibility, pagination, editing |
Components/Extras/Organisms/Reference/Items/Items Data Grid | ArdaItemsDataGrid | 6 | Item-specific columns, editing, selection |
Components/Extras/Organisms/Reference/Business Affiliates/Suppliers Data Grid | ArdaSupplierDataGrid | 6 | Supplier-specific columns, editing, selection |
Components/Extras/Molecules/Table | ArdaTable | 3 | Clickable rows, active state, empty state |
Use Case Stories
Section titled “Use Case Stories”| Use Case ID | Title | Component | Grid Component |
|---|---|---|---|
| BA-0001-0001 | View Suppliers List | SuppliersPage | ArdaGrid<BusinessAffiliateWithRoles> |
| BA-0001-0003 | Toggle Column Visibility | ToggleColumnsSuppliersPage | AG Grid + column visibility dropdown |
| BA-0001-0006 | Pagination | SuppliersPage | AG Grid with pagination |
| (Page) | Suppliers List View | SuppliersPage (with sidebar) | ArdaGrid<BusinessAffiliateWithRoles> |
Other Grid Stories
Section titled “Other Grid Stories”| Section | Story | Component |
|---|---|---|
Dev Witness/Reference/Items | Items Grid | ItemsPage (Next.js app route reproduction) |
Archive/Applications/Design | Items Data Grid | ArdaItemsDataGrid (legacy design explorations) |
3. Candidate Components for List View Implementation
Section titled “3. Candidate Components for List View Implementation”The ux-prototype Extras library contains a component hierarchy that, combined with the vendored ArdaGrid, informs the proposed five-tier Canary architecture.
Tier Overview
Section titled “Tier Overview”| Tier | Name | Atomic Level | Extras Source | Vendored Source | Role | In Scope |
|---|---|---|---|---|---|---|
| 1 | Cell Renderers | Atoms | ArdaTextCellDisplay, ArdaDateCellEditor, ArdaBooleanCellInteractive, etc. | — | Pluggable AG Grid cell components by data type. Each type provides Display, Editor, and Interactive variants. Priority subset: text, number, boolean, date, enum. | Yes |
| 2 | Data Grid | Molecule | ArdaDataGrid | — | Core AG Grid wrapper. Handles columns, selection, pagination, persistence, loading/error/empty overlays. Stays close to native AG Grid API. | Yes |
| 3a | Entity Data Grid (Base) | Organism (shared) | createArdaEntityDataGrid<T>() | — | Generic factory adding column visibility, entity-typed callbacks, and composable dirty tracking via hook. Returns { Component } per Arda factory convention. Includes selected enhancements from vendored grid (multi-sort, filtering, cell editing lifecycle). | Yes |
| 3b | Entity Data Grid (Full) | Organism (shared) | — | ArdaGrid<T> | Built on top of Tier 3a. Provides full compatibility with the current vendored ArdaGrid component — drop-in replacement or with minimal modifications. Adds row actions, row double-click, getRowClass, hasActiveSearch, selection convenience ref methods. | Yes |
| 4 | Domain Grids | Organism (domain) | ArdaItemsDataGrid, ArdaSupplierDataGrid | — | Concrete instances with pre-configured column definitions and domain-specific cell renderers. Implemented per domain story, not as part of this project. | No |
Tier Relationships
Section titled “Tier Relationships”- Tier 2 wraps AG Grid directly and exposes a minimal, idiomatic API.
- Tier 3a wraps Tier 2 via factory, adding entity-level orchestration and selected vendored features that belong at the entity level (multi-sort, filtering, cell editing lifecycle).
- Tier 3b wraps Tier 3a, layering on the remaining vendored
ArdaGridfeatures (row actions, row double-click,getRowClass,hasActiveSearch, selection convenience methods) to provide a migration-compatible component. - Tier 4 (out of scope) uses the Tier 3a or 3b factory to create domain-specific grid instances.
Configuration Pattern
Section titled “Configuration Pattern”All grid-tier components follow a three-part configuration structure:
- StaticConfig — design-time settings: column definitions, row height, selection mode, entity ID accessor.
- InitConfig — one-time initialization:
onGridReadycallback. - RuntimeConfig — per-render props:
rowData,loading, pagination state, event handlers.
Column Presets
Section titled “Column Presets”| Preset | Location |
|---|---|
| Items | /ux-prototype/src/components/extras/molecules/data-grid/presets/items/ |
| Suppliers | /ux-prototype/src/components/extras/molecules/data-grid/presets/suppliers/ |
| Common utilities | /ux-prototype/src/components/extras/molecules/data-grid/presets/common/ |
Complementary Components
Section titled “Complementary Components”| Component | Location | Role |
|---|---|---|
createArdaEntityViewer<T>() | /ux-prototype/src/components/extras/organisms/shared/entity-viewer/ | Detail/form view factory (tabbed or continuous-scroll layouts, edit/display modes, validation, dirty checking). Complements the data grid for list + detail patterns. |
ArdaTable | /ux-prototype/src/components/extras/molecules/table/ | Lightweight HTML table compound component (no AG Grid dependency). Suitable for simple, non-editable tabular displays. |
Vendored Reference
Section titled “Vendored Reference”A copy of the arda-frontend-app grid is vendored at /ux-prototype/src/vendored/arda-frontend/components/table/ArdaGrid.tsx and used by several use-case stories. This serves as a reference for feature parity but should not be the basis for new Canary components.
Canary Section Status
Section titled “Canary Section Status”The Canary section (/ux-prototype/src/components/canary/) contains only placeholder files. A detail-field atom is the only real implementation. The List View components would be among the first substantive Canary entries.
Resolved Questions
Section titled “Resolved Questions”| # | Question | Decision |
|---|---|---|
| 1 | Should the Canary List View replicate the full four-tier hierarchy from Extras, or start with fewer tiers? | Five tiers (1, 2, 3a, 3b, 4). This project delivers Tiers 1, 2, 3a, and 3b. Tier 3a corresponds to the Extras entity grid with selected enhancements. Tier 3b provides full vendored ArdaGrid compatibility. Tier 4 (domain grids) will be implemented later per domain story. |
| 2 | Should the vendored ArdaGrid from arda-frontend-app inform feature requirements, or should only the Extras hierarchy be considered? | Both. |
| 3 | How should column presets be organized — bundled with the grid component or separate? | Deferred. They will be located with the domain stories rather than in the library. |
| 4 | Is the ArdaTable (non-AG-Grid) in scope for this project, or only the AG Grid-based List View? | AG Grid only. |
| 5 | What is the migration path for arda-frontend-app pages currently using the monolithic ArdaGrid? | Out of scope of this project. |
Open Questions
Section titled “Open Questions”The following questions must be resolved before the design document can be finalized. Each question includes options with trade-offs and a recommendation.
Q6 — Feature Parity with Vendored ArdaGrid
Section titled “Q6 — Feature Parity with Vendored ArdaGrid”The vendored ArdaGrid (from arda-frontend-app) exposes features not present in the Extras ArdaDataGrid molecule. Since Decision 2 established that both implementations inform requirements, the question is which specific features the Canary Tier 2 molecule should absorb.
Features present in vendored ArdaGrid but absent from Extras ArdaDataGrid:
| Feature | Props | Purpose | AG Grid Best Practice | Decision |
|---|---|---|---|---|
| Multi-sort | enableMultiSort, onSortChanged | Allow sorting by multiple columns simultaneously (Ctrl+click). The vendored grid maps enableMultiSort to AG Grid’s multiSortKey: 'ctrl' and includes a custom SortMenuHeader dropdown. | Native support via multiSortKey prop. The custom sort-menu header is an Arda addition — AG Grid’s built-in header menu already supports multi-sort when multiSortKey is set. | Tier 3a |
| Filtering | enableFiltering, onFilterChanged | Enable per-column client-side filters. The vendored grid sets filter: true on defaultColDef and forwards onFilterChanged with the full filter model via api.getFilterModel(). | Native support. Set filter: true on defaultColDef for default text filters, or specify filter: 'agNumberColumnFilter' etc. per column. AG Grid manages filter UI and state natively. | Tier 3a |
| Row actions | enableRowActions, rowActions[] | Render a dropdown menu of actions (edit, delete, etc.) in a pinned-right column. Each action has a label, optional icon, and onClick(rowData) handler. | No native equivalent. This is a custom abstraction — a pinned column with a cellRenderer that renders React buttons. A common pattern in AG Grid apps but always requires custom implementation. | Tier 3b. Create ActionCellRenderer Atom or Molecule component that can be injected in 3a as a special column. 3b should use the component to support the vendored api |
| Row double-click | onRowDoubleClicked | Respond to double-click on a row (e.g., open detail view). Pure passthrough of AG Grid’s native event. | Native event. Pass onRowDoubleClicked directly to AgGridReact. No abstraction needed. | Tier 3b |
| Cell editing lifecycle | onCellEditingStarted, onCellEditingStopped, onCellFocused | Track when cells enter/exit edit mode and receive focus. All three are direct passthroughs of AG Grid native events with no wrapper logic. | Native events. Pass directly to AgGridReact. Useful for coordinating external state with in-cell editing, but most editing workflows can rely on onCellValueChanged alone. | Tier 3a |
| Row class callback | getRowClass | Apply dynamic CSS classes to rows based on row data (e.g., highlight rows with errors). The vendored grid conditionally enables this only when cell editing is active. | Native prop. Pass getRowClass directly to AgGridReact. The conditional gating to cell-editing mode is an Arda-specific choice, not an AG Grid requirement. | Tier 3a |
| Active search indicator | hasActiveSearch | Control which empty-state message is shown: “No items found” (when a search is active) vs. the default empty-state component. Has no interaction with AG Grid’s API. | No AG Grid equivalent. This is purely application-level UI state that determines which empty overlay to render. Could be implemented as a prop on any wrapper or handled by the consumer. | Tier 3b only (vendored compatibility shim). Not needed in Tier 3a — consumers use the existing emptyStateComponent prop (inherited from Tier 2) to pass whichever empty-state node they want. |
| Selection convenience (ref) | selectAll(), deselectAll(), getSelectedRows() | Imperative methods on the component ref for programmatic row selection. All delegate directly to gridApi.selectAll(), gridApi.deselectAll(), and gridApi.getSelectedRows(). | Thin wrappers over native GridApi methods. AG Grid’s own API is the canonical way to do this. Exposing them on a wrapper ref is a convenience — consumers can achieve the same via getGridApi(). | Tier 3b (ref extension) |
| Grid state initialization | initialState: GridState | Restore grid state (column widths, visibility, sort order, filters) at creation time. Pure passthrough of AG Grid v31+ initialState prop. | Native prop (AG Grid v31+). Pass directly to AgGridReact. This is AG Grid’s recommended approach for state restoration, replacing the older columnApi.applyColumnState() pattern. | Tier 3b |
Options:
- (a) Full parity — Absorb all vendored features into the Canary molecule.
- Pro: The Canary component becomes a drop-in replacement for any current grid usage.
- Con: Increases the molecule’s surface area significantly. Some features (filtering, row actions) may be better composed at a higher tier.
- (b) Core subset — Include multi-sort, filtering, row double-click,
getRowClass, andinitialState. Defer row actions, cell editing lifecycle callbacks, andhasActiveSearchto higher tiers or later iterations.- Pro: Keeps the molecule focused on data display concerns. Features like row actions are UI chrome that belong at organism level.
- Con: Consumers needing row actions must build their own wrapper or wait for Tier 3 support.
- (c) Minimal — match current Extras — Only add features when a concrete use case demands them.
- Pro: Smallest initial scope. Avoids speculative API surface.
- Con: Known production features would be missing from the start, requiring rework when
arda-frontend-appeventually migrates.
Recommendation: Superseded by the Tier 3a / 3b split. Per the feature-level decisions above: Tier 2 stays close to native AG Grid. Tier 3a absorbs multi-sort, filtering, and cell editing lifecycle. Tier 3b absorbs row actions, row double-click, getRowClass, hasActiveSearch, and selection convenience methods — providing full vendored ArdaGrid compatibility.
Q7 — AtomProps<V> Dependency for Cell Atoms
Section titled “Q7 — AtomProps<V> Dependency for Cell Atoms”Tier 1 interactive cell components (*CellInteractive) extend AtomProps<V> from lib/data-types/atom-types.ts. This interface provides mode: AtomMode, onChange(original, current), onComplete, onCancel, errors, label, and labelPosition. Adopting it in Canary creates a dependency on the broader atom type system.
Options:
- (a) Preserve
AtomProps<V>dependency — Canary cell atoms import and extend the existingAtomProps<V>interface.- Pro: Consistency with the existing atom system. Interactive cells and standalone form atoms share the same contract, enabling reuse in both grid and form contexts.
- Con: The List View library is coupled to the atom type system. Changes to
AtomProps<V>ripple into grid cells. Thelabel/labelPositionfields are irrelevant inside a grid context.
- (b) Define a grid-specific base type — Create a
GridCellProps<V>interface that contains only the fields relevant to grid cells (value,onChange,mode,errors,editable). Optionally make it structurally compatible withAtomProps<V>so the same component can satisfy both.- Pro: The grid library is self-contained. The interface is tailored to the grid context — no unused fields.
- Con: Two similar but distinct base types exist. Structural compatibility may drift over time without explicit enforcement.
- (c) No base type — each cell defines its own props — Remove the shared base entirely; each cell type defines exactly the props it needs.
- Pro: Maximum flexibility per cell type.
- Con: No guaranteed contract across cell types. Generic cell-agnostic logic (e.g., error display, mode switching) cannot rely on a common shape.
Recommendation: (b) Grid-specific base type. A GridCellProps<V> with value, onChange, mode, errors, and editable keeps the grid library self-contained while preserving a uniform contract across cell types. Structural compatibility with AtomProps<V> can be documented as a convention without creating an import dependency.
Q8 — Scope of Tier 1 Cell Types
Section titled “Q8 — Scope of Tier 1 Cell Types”The Extras library has 10 cell type directories (text, date, time, datetime, number, boolean, enum, url, image, custom), each with 3 variants (Display, Editor, Interactive) plus a factory helper. This totals approximately 30 components with tests and stories.
Options:
- (a) All 10 types — Deliver every cell type in the first pass.
- Pro: Complete from day one. No follow-up work needed for cell types.
- Con: Large scope — many types (time, datetime, custom) may not be exercised by any current use case. Risk of building untested API surface.
- (b) Priority subset of 5 — Deliver text, number, boolean, date, and enum. These cover the column types used in the Items and Suppliers grids. Add url, image, time, datetime, and custom in a later iteration.
- Pro: Covers all production use cases with half the component count. Remaining types can be added when a real consumer needs them.
- Con: Consumers needing URL or image columns must use AG Grid’s native renderers or custom components until the remaining types ship.
- (c) Priority subset of 3 — Deliver only text, number, and boolean. Minimal viable cell type set.
- Pro: Fastest delivery. Forces early validation of the cell type pattern before scaling.
- Con: Too limited for the Suppliers grid (which uses date and enum columns). Would block real use cases.
Recommendation: (b) Priority subset of 5. Text, number, boolean, date, and enum cover the two known domain grids (Items and Suppliers). This delivers a meaningful library while keeping scope bounded. The pattern established by these five types makes adding the remaining five straightforward.
Q9 — Dirty Tracking Location
Section titled “Q9 — Dirty Tracking Location”Dirty tracking (unsaved changes detection, draft save/discard) currently lives in Tier 3 (createArdaEntityDataGrid). The vendored ArdaGrid has no dirty tracking at all. This feature adds significant complexity to the factory: it clones row data, tracks per-cell edits, and exposes saveAllDrafts/discardAllDrafts on the ref.
Options:
- (a) Include in Canary Tier 3 — The
createEntityDataGridfactory provides dirty tracking as it does today.- Pro: Consistent with the Extras design. Any entity grid gets dirty tracking automatically.
- Con: Consumers who do not need dirty tracking (read-only grids, server-side-save grids) still carry the complexity. The factory becomes harder to understand and test.
- (b) Extract as a composable hook — Move dirty tracking into a standalone
useDirtyTracking<T>()hook that can be optionally composed with the Tier 3 factory or used independently.- Pro: Tier 3 stays focused on entity-grid orchestration. Dirty tracking becomes opt-in. The hook is testable in isolation.
- Con: Consumers who want dirty tracking must wire it up themselves instead of getting it for free.
- (c) Defer to Tier 4 (domain grids) — Remove dirty tracking from the shared library entirely. Each domain grid decides whether to implement it.
- Pro: Simplest Tier 3. Domain grids own their editing lifecycle.
- Con: Dirty tracking logic will be duplicated across domain grids. The pattern was already generalized in Extras, so pushing it back to domain level is a regression.
Recommendation: (b) Composable hook. A useDirtyTracking<T>() hook keeps the Tier 3 factory lean while making dirty tracking easy to adopt. The Tier 3 factory can document a “with dirty tracking” composition example. This avoids forcing the feature on read-only consumers and avoids duplicating it across domain grids.
Q10 — Ref API Surface Per Tier
Section titled “Q10 — Ref API Surface Per Tier”The two existing implementations expose different ref APIs:
| Method | Vendored ArdaGrid | Extras ArdaDataGrid | Extras Tier 3 | Proposed Tier |
|---|---|---|---|---|
getGridApi() | Yes | Yes | (via Tier 2) | 2 |
exportDataAsCsv() | Yes | Yes | (via Tier 2) | 2 |
refreshData() | Yes | — | — | 3b |
getSelectedRows() | Yes | — | — | 3b |
selectAll() | Yes | — | — | 3b |
deselectAll() | Yes | — | — | 3b |
saveAllDrafts() | — | — | Yes | Hook |
getHasUnsavedChanges() | — | — | Yes | Hook |
discardAllDrafts() | — | — | Yes | Hook |
Options:
- (a) Rich ref at Tier 2 — Include
getGridApi,exportDataAsCsv,getSelectedRows,selectAll,deselectAll, andrefreshDataon the molecule ref. Tier 3a/3b extend with additional methods.- Pro: Convenience methods available at the lowest level. Matches vendored
ArdaGridbehavior. - Con:
selectAll/deselectAll/getSelectedRowsare trivially achieved viagetGridApi(). Adding them to the ref creates redundant API surface that must be maintained.
- Pro: Convenience methods available at the lowest level. Matches vendored
- (b) Minimal ref at Tier 2, extended at Tier 3b — Tier 2 exposes only
getGridApi()andexportDataAsCsv(). Tier 3a inherits the Tier 2 ref unchanged. Tier 3b adds selection convenience methods (selectAll,deselectAll,getSelectedRows,refreshData) for vendoredArdaGridcompatibility. Dirty tracking methods live on theuseDirtyTrackinghook return value, not on the component ref.- Pro: Small, stable ref at Tier 2. Tier 3b provides the full convenience API expected by
ArdaGridconsumers. Clean separation of concerns. - Con: Consumers using Tier 3a who want
selectAllmust usegetGridApi().
- Pro: Small, stable ref at Tier 2. Tier 3b provides the full convenience API expected by
- (c) No ref at Tier 2 — Use only callback props for all interactions. No imperative API.
- Pro: Purely declarative component. Easier to reason about in React.
- Con: Some operations (CSV export, programmatic selection) are inherently imperative and awkward to express as props. Breaks from AG Grid’s own imperative patterns.
Recommendation: (b) Minimal ref at Tier 2, extended at Tier 3b. getGridApi() plus exportDataAsCsv() at Tier 2 gives consumers full power without bloating the ref surface. Tier 3b adds the vendored convenience methods for migration compatibility. Dirty tracking methods (per Q9) live on the hook, not on the ref.
Decision Summary
Section titled “Decision Summary”| # | Summary | Recommendation | Decision |
|---|---|---|---|
| Q6 | Feature parity with vendored ArdaGrid | Superseded by Tier 3a/3b split. Tier 2 stays native. Tier 3a adds multi-sort, filtering, cell editing lifecycle. Tier 3b adds row actions, double-click, getRowClass, hasActiveSearch. | See per-feature decisions in Q6 table. |
| Q7 | AtomProps<V> dependency for cell atoms | Grid-specific GridCellProps<V> base type, structurally compatible with AtomProps<V> but no import dependency. | Deferred. GridCellProps<V> is not needed in this project — CellInteractive (the only consumer) is out of scope. See Cell Editing Paths Analysis. To be revisited when Entity Viewer is ported. |
| Q8 | Scope of Tier 1 cell types | Priority subset of 5: text, number, boolean, date, enum. Add remaining 5 later. | Agreed. Additional deliverable of a project plan to add the rest of cell variants based on the state at the end of the project. Design the overall component structure to support easy extensibility of cell types in the library or by consumers of Tier 2 & Tier 3 components. |
| Q9 | Dirty tracking location | Composable useDirtyTracking<T>() hook, separate from Tier 3a factory. | Agreed. |
| Q10 | Ref API surface per tier | Minimal Tier 2 ref (getGridApi, exportDataAsCsv). Tier 3a inherits unchanged. Tier 3b extends with vendored convenience methods. Dirty tracking on hook, not ref. | Agreed. See detailed references in Q6 table. |
Cell Editing Paths Analysis
Section titled “Cell Editing Paths Analysis”During the design review, an apparent dependency between {Type}CellInteractive and {Type}CellEditor was investigated. The finding is that these are two independent editing mechanisms used in completely separate contexts. They never interact and cannot conflict.
Path 1: AG Grid Native Cell Editing (CellEditor)
Section titled “Path 1: AG Grid Native Cell Editing (CellEditor)”Used inside the Data Grid molecule (Tier 2) and entity data grid factories (Tiers 3a/3b).
- Trigger: User double-clicks a cell in the AG Grid.
- Mechanism: AG Grid replaces the cell renderer with the
cellEditorcomponent. The editor implements agetValue()ref handle. When editing ends (blur, Enter, Escape), AG Grid callsgetValue()and firesonCellValueChanged. - Configuration:
enableCellEditingprop onDataGrid<T>sets AG Grid options (singleClickEdit: false,stopEditingWhenCellsLoseFocus: true). TheenhanceEditableColumnDefs()function setseditable: true,valueGetter,valueSetter, andcellEditoron individual columns. - Editor components:
{Type}CellEditor(e.g.,ArdaTextCellEditor), plus domain-specific editors likeSelectCellEditorandTypeaheadCellEditor. - Scope: In scope for this project (Tiers 1-3b).
Path 2: Mode-Based Inline Editing (CellInteractive)
Section titled “Path 2: Mode-Based Inline Editing (CellInteractive)”Used inside the Entity Viewer organism — a form/detail panel, not a grid.
- Trigger: Parent component (Entity Viewer shell) sets
mode: 'edit'on the field. - Mechanism:
{Type}CellInteractiveextendsAtomProps<V>and manages its own display/edit state. In display mode it renders{Type}CellDisplay; in edit mode it renders an internal{Type}CellInlineEditorfunction (not the AG GridCellEditor). UsesonComplete/onCancelcallbacks for edit lifecycle. - Configuration: The Entity Viewer’s field descriptor specifies a
componentproperty pointing to aCellInteractivecomponent. - Scope: Out of scope for this project. The Entity Viewer is a separate deliverable.
Key Findings
Section titled “Key Findings”CellInteractiveis never used as acellRendererin any AG Grid column definition. A codebase search confirmed zero usages.CellInteractivedoes not import or delegate toCellEditor. It has its own internal inline editor.- The two paths are architecturally isolated: AG Grid editing operates within the grid’s cell lifecycle; mode-based editing operates within the Entity Viewer’s form lifecycle.
GridCellProps<V>(the proposed canary base type for Interactive cells) is only needed byCellInteractive, which has no consumer in this project.
Impact on Project Scope
Section titled “Impact on Project Scope”Since CellInteractive has no consumer within the grid context (Tiers 1-3b), it should be deferred to the Entity Viewer project. This reduces Tier 1 from 3 variants per type (Display, Editor, Interactive) to 2 variants (Display, Editor), and eliminates the need for GridCellProps<V> in this project.
Vendored Memo and Color Cell Reference
Section titled “Vendored Memo and Color Cell Reference”During implementation planning, the vendored codebase was inspected for existing memo/notes and color cell implementations that can serve as the basis for the new canary atoms.
Memo/Notes — Vendored Pattern
Section titled “Memo/Notes — Vendored Pattern”Three vendored components form the notes editing pattern:
NotesCell(~90 lines,columnPresets.tsxlines 883-976): A cell renderer that shows a chat bubble icon (HiOutlineChatBubbleBottomCenterText) when notes exist, or a dash button when empty. Clicking opensNoteModalviacreatePortaltodocument.body. ReceivesonNotesSavecallback viaparams.context. Event propagation stopped to prevent grid row selection.CardNotesCell(~90 lines,columnPresets.tsxlines 979-1072): Identical pattern toNotesCellbut foritem.cardNotesDefaultfield.NoteModal(~138 lines,vendored/.../common/NoteModal.tsx): Full-screen overlay modal (500px, centered, dark backdrop). Props:isOpen,editable,initialValue,onSave,title. Textarea with min-height 100px, resizable. Done button saves; X button closes.
The existing TextCellDisplay in extras also has a truncation pattern: value.slice(0, maxLength) + '…' with CSS truncate class.
Canary approach: Three memo components cover both new and vendored-compatible patterns:
MemoCellDisplay— truncated text + Radix HoverCard hover overlay (new pattern)MemoCellEditor— AG Grid textarea editor, draws fromNoteModaltextarea patternMemoButtonCell— vendored-compatible icon-button + modal pattern, withonSavecallback (framework-agnostic). AcreateMemoButtonCellEditor()factory wraps it for AG Grid.
Color — Vendored Pattern
Section titled “Color — Vendored Pattern”Two vendored implementations:
ColorCellEditor(~125 lines,ItemTableAGGrid.tsxlines 157-282): Class-based AG Grid editor using raw DOM (not React). Implements fullICellEditorParamslifecycle. Native<select>with 10 options. Auto-opens dropdown on focus. Commits and stops editing on selection change.- Color renderer (~30 lines,
columnPresets.tsxlines 1787-1817): 4x4px rounded swatch (backgroundColor: hex) + label. HardcodedcolorMap:
RED: #EF4444, GREEN: #22C55E, BLUE: #3B82F6, YELLOW: #FDE047,ORANGE: #F97316, PURPLE: #A855F7, PINK: #EC4899, GRAY: #6B7280,BLACK: #000000, WHITE: #FFFFFFcolorOptions(8 entries inconstants.ts): Missing BLACK and WHITE vs the editor’s 10.
Canary approach: React components replacing raw-DOM vendored code:
ColorCellDisplay— replicates vendored swatch + label patternColorCellEditor— ReactforwardRefwith shadcn/RadixSelectorPopover, configurablecolors: ColorOption[]prop, vendored 10-color map as default
Follow-Up Actions
Section titled “Follow-Up Actions”- Resolve Q6–Q10 decisions before proceeding to the design document.
- Review the Extras hierarchy in the Storybook site to assess visual and behavioral completeness.
- Define acceptance criteria for the first Canary List View deliverable.
Copyright: © Arda Systems 2025-2026, All rights reserved