@rowakit/table 0.2.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -12,8 +12,12 @@ RowaKit Table is a React table component designed for real-world internal applic
12
12
  ✅ **Escape hatch** - `col.custom()` for any rendering need
13
13
  ✅ **Action buttons** - Built-in support for row actions with confirmation
14
14
  ✅ **7 column types** - Text, Date, Boolean, Badge, Number, Actions, Custom
15
- ✅ **Column modifiers** - Width, align, truncate support (v0.2.0+)
15
+ ✅ **Column modifiers** - Width, align, truncate, minWidth, maxWidth (v0.2.0+)
16
16
  ✅ **Server-side filters** - Type-specific filter UI with auto-generated inputs (v0.2.0+)
17
+ ✅ **Column resizing** - Drag-to-resize handles with constraints (v0.4.0+)
18
+ ✅ **Saved views** - Save/load table state with localStorage persistence (v0.4.0+)
19
+ ✅ **URL state sync** - Share URLs with exact table configuration (v0.4.0+)
20
+ ✅ **Number range filters** - Min/max filtering for numeric columns (v0.4.0+)
17
21
  ✅ **State management** - Automatic loading, error, and empty states
18
22
  ✅ **Smart fetching** - Retry on error, stale request handling
19
23
 
@@ -852,6 +856,165 @@ col.actions([
852
856
  - Keyboard accessible (Tab to focus, Enter/Space to activate)
853
857
  - Actions column is never sortable
854
858
 
859
+ ---
860
+
861
+ ## Advanced Features (v0.4.0+)
862
+
863
+ ### Column Resizing (C-01)
864
+
865
+ Enable users to resize columns by dragging the right edge of column headers.
866
+
867
+ **Basic Usage:**
868
+
869
+ ```typescript
870
+ <RowaKitTable
871
+ fetcher={fetchData}
872
+ columns={[
873
+ col.text('name', {
874
+ minWidth: 100, // Minimum width (default: 80)
875
+ maxWidth: 400 // Maximum width (optional)
876
+ }),
877
+ col.number('price', {
878
+ minWidth: 80
879
+ })
880
+ ]}
881
+ enableColumnResizing={true} // Enable resize feature
882
+ />
883
+ ```
884
+
885
+ **Features:**
886
+ - **Auto-width by default** - Columns automatically size based on header text
887
+ - **Drag to resize** - Drag the blue handle on the right edge of column headers
888
+ - **Double-click to auto-fit** - Double-click the resize handle to auto-fit content width (measures visible header + cells)
889
+ - **Min/max constraints** - Enforced in real-time during drag
890
+ - **Smooth performance** - RAF throttling prevents lag during resize
891
+ - **Large hitbox** - 12px wide invisible zone (1px visible line) makes dragging easy
892
+ - **State persistence** - Widths stored in-memory (or persisted via URL sync/saved views)
893
+
894
+ **Interaction:**
895
+ - **Hover** - Resize handle appears as a blue vertical line
896
+ - **Drag** - Click and drag to resize column width
897
+ - **Double-click** - Auto-fits to content (max 600px by default)
898
+ - Text selection is disabled during drag for smooth UX
899
+
900
+ ### Saved Views + URL State Sync (C-02)
901
+
902
+ Save and restore table configurations, and share URLs with exact table state.
903
+
904
+ **Basic Usage:**
905
+
906
+ ```typescript
907
+ <RowaKitTable
908
+ fetcher={fetchData}
909
+ columns={columns}
910
+ syncToUrl={true} // Sync to URL query string
911
+ enableSavedViews={true} // Show save/load view buttons
912
+ />
913
+ ```
914
+
915
+ **Features:**
916
+
917
+ 1. **URL Sync** - Automatically saves table state to URL query parameters:
918
+ ```
919
+ ?page=2&pageSize=20&sortField=name&sortDirection=asc&filters=...&columnWidths=...
920
+ ```
921
+ - Share URLs to preserve exact table configuration
922
+ - State automatically restored on page load
923
+ - Works with browser back/forward buttons
924
+
925
+ 2. **Saved Views** - Save current table state as named presets:
926
+ ```
927
+ [Save View] button → Name your view → State saved to localStorage
928
+ [My View] button → Click to restore saved state
929
+ × button → Delete saved view
930
+ [Reset] button → Clear all state
931
+ ```
932
+
933
+ **Synced State:**
934
+ - Page number and size
935
+ - Sort field and direction
936
+ - All active filters
937
+ - Column widths (if resizing enabled)
938
+
939
+ **Example:**
940
+
941
+ ```typescript
942
+ // User filters to "active users" and resizes columns
943
+ // They click "Save View" and name it "Active"
944
+ // Later, they apply different filters
945
+ // They click "Active" button to instantly restore previous state
946
+
947
+ // Or they copy the URL and send it to a colleague
948
+ // The colleague sees the exact same filters and layout
949
+ ```
950
+
951
+ ### Advanced Number Range Filters (C-03)
952
+
953
+ Number columns support min/max range filtering with optional value transformation.
954
+
955
+ **Basic Range Filter:**
956
+
957
+ ```typescript
958
+ col.number('price', {
959
+ label: 'Price',
960
+ width: 100
961
+ })
962
+
963
+ // UI shows two inputs: [Min] [Max]
964
+ // User enters: min=100, max=500
965
+ // Backend receives: { op: 'range', value: { from: 100, to: 500 } }
966
+ ```
967
+
968
+ **With Filter Transform:**
969
+
970
+ ```typescript
971
+ col.number('discount', {
972
+ label: 'Discount %',
973
+ // Transform percentage input to fraction for backend
974
+ filterTransform: (percentageInput) => {
975
+ // User enters "15" (15%)
976
+ // Backend receives "0.15" (fraction)
977
+ if (percentageInput > 1) {
978
+ return percentageInput / 100;
979
+ }
980
+ return percentageInput;
981
+ }
982
+ })
983
+ ```
984
+
985
+ **Features:**
986
+ - Min and max inputs can be filled independently
987
+ - Example: "at least 50" (min only), "up to 100" (max only), or "50-100" (both)
988
+ - Optional `filterTransform` to adapt filter values before sending to server
989
+ - Useful for unit conversion, percentage ↔ decimal, etc.
990
+
991
+ **Handling Range Filters in Fetcher:**
992
+
993
+ ```typescript
994
+ const fetchProducts: Fetcher<Product> = async (query) => {
995
+ let filtered = [...allProducts];
996
+
997
+ if (query.filters) {
998
+ for (const [field, filter] of Object.entries(query.filters)) {
999
+ if (filter?.op === 'range') {
1000
+ const { from, to } = filter.value as { from?: number; to?: number };
1001
+ filtered = filtered.filter(item => {
1002
+ const val = item[field as keyof Product];
1003
+ if (from !== undefined && val < from) return false;
1004
+ if (to !== undefined && val > to) return false;
1005
+ return true;
1006
+ });
1007
+ }
1008
+ }
1009
+ }
1010
+
1011
+ return {
1012
+ items: filtered.slice(0, query.pageSize),
1013
+ total: filtered.length
1014
+ };
1015
+ };
1016
+ ```
1017
+
855
1018
  ## Examples
856
1019
 
857
1020
  ### Basic Table
@@ -1292,7 +1455,7 @@ Full TypeScript support. Your data model drives type checking throughout.
1292
1455
 
1293
1456
  ## Roadmap
1294
1457
 
1295
- **Stage A - MVP 0.1** ✅ Complete (2024-12-31)
1458
+ **Stage A - MVP (v0.1)** ✅ Complete (2024-12-31)
1296
1459
  - ✅ A-01: Repo scaffold
1297
1460
  - ✅ A-02: Core types (Fetcher, ColumnDef, ActionDef)
1298
1461
  - ✅ A-03: Column helpers (col.*)
@@ -1304,19 +1467,28 @@ Full TypeScript support. Your data model drives type checking throughout.
1304
1467
  - ✅ A-09: Minimal styling tokens (CSS variables, responsive, className)
1305
1468
  - ✅ A-10: Documentation & examples (4 complete examples, CHANGELOG, CONTRIBUTING)
1306
1469
 
1307
- **Stage B - Production Ready (v0.2.2)** Production release 2026-01-02
1308
- - Column visibility toggle
1309
- - Bulk actions
1310
- - Search/text filter
1311
- - Export (CSV, Excel)
1312
- - Dense/comfortable view modes
1313
- - Additional column types (badge, number)
1314
-
1315
- **Stage C - Advanced (Demand-Driven)** (Future)
1316
- - Multi-column sorting
1317
- - Advanced filters
1318
- - Column resizing
1319
- - Saved views
1470
+ **Stage B - Production Ready (v0.2.0-0.2.2)** Complete (2026-01-02)
1471
+ - Badge column type with visual tones (neutral, success, warning, danger)
1472
+ - Number column type with Intl formatting (currency, percentages, decimals)
1473
+ - Server-side header filter UI (type-specific inputs)
1474
+ - Column modifiers (width, align, truncate)
1475
+ - Fixed numeric filter value coercion
1476
+ - Production hardening and comprehensive documentation
1477
+
1478
+ **Stage C - Advanced Features (v0.4.0)** ✅ Complete (2026-01-03)
1479
+ - ✅ C-01: Column resizing with drag handles (minWidth/maxWidth constraints)
1480
+ - C-02: Saved views with localStorage persistence
1481
+ - C-02: URL state sync (page, pageSize, sort, filters, columnWidths)
1482
+ - C-03: Number range filters with optional filterTransform
1483
+
1484
+ **Stage D - Polish + Correctness (v0.4.0)** ✅ Complete (2026-01-05)
1485
+ - ✅ D-01: Prevent accidental sort while resizing (stopPropagation, suppression window)
1486
+ - ✅ D-02: Pointer Events resizing (mouse, touch, pen) with pointer capture and cleanup
1487
+ - ✅ D-03: Column width model hardening (apply widths to th+td, fixed layout, truncation)
1488
+ - ✅ D-04: Saved views persistence (index, hydration, corruption-safe)
1489
+ - ✅ D-05: URL sync hardening (validation, debounce, backward compatible)
1490
+
1491
+ See [ROADMAP.md](./docs/ROADMAP.md) and `docs/ROWAKIT_STAGE_D_ISSUES_v3.md` for implementation details and rationale.
1320
1492
 
1321
1493
  ## Changelog
1322
1494