Skip to content

Reduce non-serializable assignableAttributes #24

@bemky

Description

@bemky

Problem

The assignableAttributes system supports non-serializable types (objects, arrays, functions) via a _ref manifest pattern — generating ref IDs, storing values in a global KompElement.manifest Map, writing opaque foo_ref="komp-ref-42" attributes to the DOM, and using a FinalizationRegistry for cleanup. This is complex and unconventional.

Since the primary use case is programmatic (new Dropdown({anchor: el})), most non-serializable values don't need DOM representation. Many can be replaced with serializable alternatives, events, or removed from the public API entirely.

Audit

27 non-serializable attributes found across the library:

Callbacks — replace with events

These are function attributes that duplicate what addEventListener already does.

Component Attribute Description Alternative
Floater onShow Called when floater becomes visible Already fires shown event — remove attribute
Floater onHide Called when floater hides Already fires hidden event — remove attribute
ContentArea onchange Called on blur after content edited Fire a change event with {detail: {value, oldValue}}
Dropzone onFileDrop Called per file dropped Already fires filedrop event — remove attribute

Transform/render functions

These define how something renders or transforms data.

Component Attribute Description Alternative
Input dump Transforms input value before storing to target String key into a named-transforms registry (e.g. "number", "date")
Input load Transforms target value for display Same registry approach
Select dump Transforms selected value before storing Same as Input
Select load Transforms target value for display Same as Input
SearchField search Async function performing the search URL string — component fetches and parses JSON
SearchField result Renders a single result item HTML template string with ${field} interpolation
SearchField input Factory for the input element Object config passed to createElement
SearchField empty Content when no results (when fn) Already supports string — drop function variant
SearchField loader Content while loading (when fn) Already supports string — drop function variant
Resizer bounds Returns {top,right,bottom,left} constraints JSON object or keyword string ("parent", "viewport")
TableColumn header Renders header cell (when fn) Already supports string — sufficient
TableColumn render Renders cell content Template string with field interpolation
SpreadsheetColumn input Factory for the edit input element String type key looked up in a registry
SpreadsheetColumn copy Converts cell value to clipboard format Built-in default covers most cases
SpreadsheetColumn paste Converts clipboard data to cell value Same as copy

Internal object references — remove from public API

These are parent-child references passed during construction. They shouldn't be assignableAttributes at all — they're internal wiring.

Component Attribute Description Alternative
Input target Data object to bind input value to Pass internally, remove from public API
Select target Data object to bind selection to Same as Input
TableRow table Ref to parent Table this.closest('komp-table') or parent injection
TableCell table Ref to parent Table Same — DOM traversal or parent injection
TableCell column Ref to TableColumn config Column index (number) + lookup from table
TableCell record Data row (when fn) Already supports plain object — drop function variant

Already handled well

  • Floater anchor — has a load() that resolves selector strings
  • Floater container — already accepts strings

Recommendations

  1. Callbacks (4): Remove — all redundant with existing events
  2. Internal references (6): Remove from public assignableAttributes, use DOM traversal or internal injection
  3. Transform/render functions (15): Consider a registry + template string approach for common cases, keep programmatic escape hatch
  4. Simplify the ref system: Once the above are addressed, evaluate whether the manifest/FinalizationRegistry/_ref pattern is still needed

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions