@jielga/tmdatagrid 2.0.0-beta.1 → 2.0.0-beta.2

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.
Files changed (36) hide show
  1. package/dist/index.d.ts +60 -23
  2. package/dist/index.js +2020 -1704
  3. package/dist/index.js.map +1 -1
  4. package/dist/styles.css +1 -1
  5. package/package.json +1 -1
  6. package/skills/appearance/SKILL.md +1 -1
  7. package/skills/cell-selection/SKILL.md +1 -1
  8. package/skills/columns/SKILL.md +2 -2
  9. package/skills/data/SKILL.md +1 -1
  10. package/skills/editing/SKILL.md +68 -213
  11. package/skills/editing/references/common-mistakes.md +177 -0
  12. package/skills/editing/references/editing-api.md +39 -13
  13. package/skills/editing/references/editors-and-validation.md +5 -2
  14. package/skills/filtering/SKILL.md +1 -1
  15. package/skills/getting-started/SKILL.md +1 -1
  16. package/skills/grouping/SKILL.md +1 -1
  17. package/skills/options/SKILL.md +2 -2
  18. package/skills/rows/SKILL.md +1 -1
  19. package/skills/rows/references/rows-api.md +1 -1
  20. package/skills/server-side/SKILL.md +1 -1
  21. package/skills/testing/SKILL.md +3 -2
  22. package/src/tmdatagrid/components/TMDataGrid.module.css +7 -0
  23. package/src/tmdatagrid/components/TMDataGridCellEditor.tsx +20 -8
  24. package/src/tmdatagrid/components/TMDataGridEditActions.tsx +1 -1
  25. package/src/tmdatagrid/components/TMDataGridEditColumn.tsx +242 -86
  26. package/src/tmdatagrid/components/TMDataGridEntryRows.tsx +176 -77
  27. package/src/tmdatagrid/components/TMDataGridTable.module.css +47 -3
  28. package/src/tmdatagrid/components/TMDataGridTable.tsx +44 -4
  29. package/src/tmdatagrid/components/icons.ts +1 -0
  30. package/src/tmdatagrid/core/capabilities.ts +10 -0
  31. package/src/tmdatagrid/core/draftCellContext.ts +68 -0
  32. package/src/tmdatagrid/core/editEngine.ts +106 -32
  33. package/src/tmdatagrid/core/labels.ts +13 -1
  34. package/src/tmdatagrid/core/labelsSv.ts +4 -0
  35. package/src/tmdatagrid/index.ts +1 -1
  36. package/src/tmdatagrid/useTMDataGrid.tsx +39 -20
package/dist/styles.css CHANGED
@@ -1,2 +1,2 @@
1
- ._root_ed4g_8[data-size=xs]{--dg-row-height:34px;--dg-header-height:32px;--dg-font-size:var(--mantine-font-size-xs);--dg-padding:6px}._root_ed4g_8[data-size=sm]{--dg-row-height:42px;--dg-header-height:38px;--dg-font-size:var(--mantine-font-size-sm);--dg-padding:8px}._root_ed4g_8[data-size=md]{--dg-row-height:52px;--dg-header-height:44px;--dg-font-size:var(--mantine-font-size-sm);--dg-padding:10px}._root_ed4g_8[data-size=lg]{--dg-row-height:62px;--dg-header-height:52px;--dg-font-size:var(--mantine-font-size-md);--dg-padding:14px}._root_ed4g_8[data-size=xl]{--dg-row-height:72px;--dg-header-height:60px;--dg-font-size:var(--mantine-font-size-lg);--dg-padding:18px}._root_ed4g_8{--dg-radius:var(--mantine-radius-md);--dg-row-height:52px;--dg-header-height:44px;--dg-font-size:var(--mantine-font-size-sm);--dg-padding:10px;--dg-row-selected-bg:var(--mantine-primary-color-light);--dg-row-highlight-bg:var(--mantine-primary-color-light-hover);--dg-row-group-bg:var(--mantine-color-body);--dg-row-striped-bg:color-mix(in srgb, var(--mantine-color-text) 3.5%, var(--mantine-color-body));--dg-z-pinned-cell:2;--dg-z-focused-cell:3;--dg-z-pinned-row:4;--dg-z-pinned-row-pinned-cell:5;--dg-z-summary-row:4;--dg-z-summary-pinned-cell:5;--dg-z-header:6;--dg-z-header-pinned-cell:7;text-align:left;border:1px solid var(--mantine-color-default-border);border-radius:var(--dg-radius);background-color:var(--mantine-color-body);flex-direction:column;min-height:0;display:flex;overflow:hidden}._columnsPanel_1492o_1{flex-direction:column;width:280px;display:flex}._columnsPanelSearch_1492o_7{padding:var(--mantine-spacing-sm)}._columnsPanelList_1492o_11{gap:var(--mantine-spacing-sm);padding:0 var(--mantine-spacing-sm) var(--mantine-spacing-sm);flex-direction:column;display:flex}._columnsPanelFooter_1492o_18{justify-content:space-between;align-items:center;gap:var(--mantine-spacing-sm);padding:var(--mantine-spacing-sm);border-top:1px solid var(--mantine-color-default-border);display:flex}._detailsToggle_n39tz_3{width:100%;height:100%;color:inherit;justify-content:center;align-items:center;display:flex}._detailsToggle_n39tz_3:hover ._chevron_n39tz_12{color:var(--mantine-color-text)}._chevron_n39tz_12{color:var(--mantine-color-dimmed);align-items:center;transition:transform .12s;display:flex}._chevron_n39tz_12[data-expanded=true]{transform:rotate(90deg)}@media (prefers-reduced-motion:reduce){._chevron_n39tz_12{transition:none}}._groupToggle_1954o_4{width:100%;min-width:0;font-size:var(--dg-font-size);color:inherit;align-items:center;gap:6px;display:flex}._chevron_1954o_14{color:var(--mantine-color-dimmed);flex:none;align-items:center;transition:transform .12s;display:flex}._chevron_1954o_14[data-expanded=true]{transform:rotate(90deg)}@media (prefers-reduced-motion:reduce){._chevron_1954o_14{transition:none}}._groupLabel_1954o_34{white-space:nowrap;text-overflow:ellipsis;min-width:0;font-weight:600;overflow:hidden}._groupCount_1954o_44{color:var(--mantine-color-dimmed);font-variant-numeric:tabular-nums;flex:none}._filterPanel_izakx_4{top:calc(var(--dg-header-height) + 2px);left:var(--mantine-spacing-md);z-index:5;padding:var(--mantine-spacing-sm);border-radius:var(--mantine-radius-md);border:1px solid var(--mantine-color-default-border);background-color:var(--mantine-color-body);box-shadow:var(--mantine-shadow-md);position:absolute}._filterRow_izakx_16{align-items:flex-end;gap:var(--mantine-spacing-xs);display:flex}._filterPanelHeader_izakx_22{justify-content:space-between;align-items:center;gap:var(--mantine-spacing-md);padding-bottom:var(--mantine-spacing-xs);display:flex}._filterPanelFooter_izakx_30{justify-content:space-between;align-items:center;gap:var(--mantine-spacing-md);display:flex}._filterPills_14wl0_3{align-items:center;gap:var(--mantine-spacing-xs);flex-wrap:wrap;display:flex}._filterPills_14wl0_3 ._pill_14wl0_15{background-color:var(--lightningcss-light,var(--mantine-color-gray-1))var(--lightningcss-dark,var(--mantine-color-dark-5));color:var(--lightningcss-light,var(--mantine-color-black))var(--lightningcss-dark,var(--mantine-color-dark-0));border:1px solid var(--lightningcss-light,var(--mantine-color-gray-3))var(--lightningcss-dark,var(--mantine-color-dark-3))}._pillLabel_14wl0_27{font:inherit;color:inherit;cursor:pointer}._pillLabel_14wl0_27:hover{text-decoration:underline}._footer_te0a3_1{justify-content:flex-end;align-items:center;gap:var(--mantine-spacing-lg);padding:4px var(--mantine-spacing-sm);border-top:1px solid var(--mantine-color-default-border);flex-shrink:0;min-height:48px;display:flex}._footer_te0a3_1[data-paging-suspended=true]{opacity:.55}._tableWrapper_15qzd_2{flex-direction:column;flex:1;min-height:0;display:flex;position:relative}._scrollContainer_15qzd_10{flex:1;min-height:0;position:relative;overflow:auto;container-type:inline-size}._grid_15qzd_21{display:grid}._headerRow_15qzd_27{grid-column:1/-1;grid-template-columns:subgrid;z-index:var(--dg-z-header,6);display:grid;position:sticky;top:0}._headerRow_15qzd_27[data-dg-header-last]:after{content:"";pointer-events:none;background:linear-gradient(to bottom, var(--dg-header-shadow-color,#00000024), transparent);opacity:0;height:6px;position:absolute;inset:100% 0 auto}@supports (animation-timeline:scroll()){._headerRow_15qzd_27[data-dg-header-last]:after{animation:linear both _dg-header-shadow_15qzd_1;animation-timeline:scroll();animation-range:0 24px}}@keyframes _dg-header-shadow_15qzd_1{0%{opacity:0}to{opacity:1}}._bodyRow_15qzd_76{--row-bg:var(--mantine-color-body);grid-column:1/-1;grid-template-columns:subgrid;align-items:stretch;display:grid}._bodyRow_15qzd_76[data-striped=true]{--row-bg:var(--dg-row-striped-bg)}._bodyRow_15qzd_76:hover{--row-bg:var(--mantine-color-default-hover)}._bodyRow_15qzd_76[data-grouped=true]{--row-bg:var(--dg-row-group-bg)}._bodyRow_15qzd_76[data-context-menu=true]{--row-bg:var(--mantine-color-default-hover)}._bodyRow_15qzd_76[data-selected-bg=true]{--row-bg:var(--dg-row-selected-bg)}._bodyRow_15qzd_76[data-highlighted=true]{--row-bg:var(--dg-row-highlight-bg)}._bodyRow_15qzd_76[data-selects-on-click=true]{-webkit-user-select:none;user-select:none}._bodyRow_15qzd_76:focus-visible{outline:2px solid var(--mantine-primary-color-filled);outline-offset:-2px}._bodyCell_15qzd_143{padding:0 var(--dg-padding);border-bottom:1px solid var(--mantine-color-default-border);background-color:var(--row-bg);font-size:var(--dg-font-size);align-items:center;display:flex}._bodyCell_15qzd_143[data-control-column=true]{padding:0}._grid_15qzd_21[data-range-dragging]{-webkit-user-select:none;user-select:none}._bodyCell_15qzd_143[data-selected=true]{background-color:color-mix(in srgb, var(--mantine-primary-color-filled) 14%, var(--row-bg));--dg-edge-top:transparent;--dg-edge-bottom:transparent;--dg-edge-left:transparent;--dg-edge-right:transparent;box-shadow:inset 0 1px 0 0 var(--dg-edge-top), inset 0 -1px 0 0 var(--dg-edge-bottom), inset 1px 0 0 0 var(--dg-edge-left), inset -1px 0 0 0 var(--dg-edge-right)}._bodyCell_15qzd_143[data-edge-top=true]{--dg-edge-top:var(--mantine-primary-color-filled)}._bodyCell_15qzd_143[data-edge-bottom=true]{--dg-edge-bottom:var(--mantine-primary-color-filled)}._bodyCell_15qzd_143[data-edge-left=true]{--dg-edge-left:var(--mantine-primary-color-filled)}._bodyCell_15qzd_143[data-edge-right=true]{--dg-edge-right:var(--mantine-primary-color-filled)}._bodyCell_15qzd_143[data-focused=true]{outline:2px solid var(--mantine-primary-color-filled);outline-offset:-2px}._cellContent_15qzd_141{white-space:nowrap;text-overflow:ellipsis;min-width:0;overflow:hidden}._bodyCell_15qzd_143[data-editing]{padding:0 calc(var(--dg-padding) / 2)}._cellEditor_15qzd_243{align-items:center;gap:2px;width:100%;min-width:0;display:flex}._cellEditorActions_15qzd_252{flex:none;align-items:center;display:flex}._bodyCell_15qzd_143[data-dirty],._bodyCell_15qzd_143[data-invalid]{position:relative}._bodyCell_15qzd_143[data-dirty]:after,._bodyCell_15qzd_143[data-invalid]:after{content:"";border:5px solid #0000;border-top-color:var(--mantine-primary-color-filled);border-right-color:var(--mantine-primary-color-filled);position:absolute;top:0;right:0}._bodyCell_15qzd_143[data-invalid]:after{border-top-color:var(--mantine-color-error);border-right-color:var(--mantine-color-error)}._bodyCell_15qzd_143[data-align=right]{justify-content:flex-end}._bodyCell_15qzd_143[data-align=center]{justify-content:center}._bodyCell_15qzd_143[data-align=left] ._cellContent_15qzd_141{flex:auto}._detailsCell_15qzd_303{border-bottom:1px solid var(--mantine-color-default-border);background-color:var(--row-bg);padding:var(--dg-padding);-webkit-user-select:text;user-select:text;cursor:auto;grid-column:1/-1}._messageRow_15qzd_15{justify-content:center;justify-self:start;align-items:center;gap:var(--mantine-spacing-xs);width:100cqi;padding:var(--mantine-spacing-xl);flex-direction:column;grid-column:1/-1;display:flex;position:sticky;left:0}._bodyRow_15qzd_76[data-deleted=true]{opacity:.55;pointer-events:none;text-decoration:line-through}._entryBlock_15qzd_347{grid-column:1/-1;grid-template-columns:subgrid;top:var(--dg-header-height,0px);z-index:var(--dg-z-pinned-row,4);display:grid;position:sticky}._entryRow_15qzd_356{grid-column:1/-1;grid-template-columns:subgrid;display:grid}._pinnedTopBlock_15qzd_369{grid-column:1/-1;grid-template-columns:subgrid;top:calc(var(--dg-header-height,0px) + var(--dg-entry-height,0px));z-index:var(--dg-z-pinned-row,4);display:grid;position:sticky}._pinnedTopBlock_15qzd_369>:last-child>[role=cell]{border-bottom:2px solid var(--mantine-color-default-border)}._pinnedBottomBlock_15qzd_382{grid-column:1/-1;grid-template-columns:subgrid;bottom:var(--dg-summary-height,0px);z-index:var(--dg-z-pinned-row,4);display:grid;position:sticky}._pinnedBottomBlock_15qzd_382>:first-child>[role=cell]{border-top:2px solid var(--mantine-color-default-border)}._entryCell_15qzd_395{padding:0 calc(var(--dg-padding) / 2);border-bottom:2px solid var(--mantine-primary-color-filled);background-color:var(--mantine-color-body);font-size:var(--dg-font-size);align-items:center;display:flex}._entryCell_15qzd_395[data-control-column=true]{justify-content:center;padding:0}._entryCell_15qzd_395[data-align=right]{justify-content:flex-end}._entryCell_15qzd_395[data-align=center]{justify-content:center}._matchHighlight_15qzd_422{background-color:var(--dg-match-highlight-bg,var(--lightningcss-light,var(--mantine-color-yellow-2))var(--lightningcss-dark,#fab00559));color:inherit;border-radius:2px}._summaryRow_15qzd_434{grid-column:1/-1;grid-template-columns:subgrid;z-index:var(--dg-z-summary-row,4);display:grid;position:sticky;bottom:0}._summaryCell_15qzd_443{padding:0 var(--dg-padding);border-top:1px solid var(--mantine-color-default-border);background-color:var(--mantine-color-body);font-size:var(--dg-font-size);align-items:center;font-weight:600;display:flex}._summaryCell_15qzd_443[data-control-column=true]{padding:0}._summaryCell_15qzd_443[data-align=right]{justify-content:flex-end}._summaryCell_15qzd_443[data-align=center]{justify-content:center}._stickyLeft_1vw51_16:after,._stickyRight_1vw51_17:after{content:"";pointer-events:none;width:8px;position:absolute;top:0;bottom:0}._stickyLeft_1vw51_16:after{background:linear-gradient(90deg,var(--lightningcss-light,#00000012)var(--lightningcss-dark,#00000042),var(--lightningcss-light,#00000006)var(--lightningcss-dark,#00000017) 45%,#0000);left:100%}._stickyRight_1vw51_17:after{background:linear-gradient(270deg,var(--lightningcss-light,#00000012)var(--lightningcss-dark,#00000042),var(--lightningcss-light,#00000006)var(--lightningcss-dark,#00000017) 45%,#0000);right:100%}@supports (animation-timeline:scroll()){._stickyLeft_1vw51_16:after,._stickyRight_1vw51_17:after{--dg-sticky-edge-range:20px;opacity:0;animation-timing-function:linear;animation-fill-mode:both;animation-timeline:scroll(inline)}._stickyLeft_1vw51_16:after{animation-name:_stickyEdgeIn_1vw51_1;animation-range:0 var(--dg-sticky-edge-range)}._stickyRight_1vw51_17:after{animation-name:_stickyEdgeOut_1vw51_1;animation-range:calc(100% - var(--dg-sticky-edge-range)) 100%}}@keyframes _stickyEdgeIn_1vw51_1{0%{opacity:0}to{opacity:1}}@keyframes _stickyEdgeOut_1vw51_1{0%{opacity:1}to{opacity:0}}._headerCell_188ed_1{padding:0 var(--dg-padding);min-width:0;min-height:var(--dg-header-height);font-weight:600;font-size:var(--dg-font-size);background-color:var(--mantine-color-body);border-bottom:1px solid var(--mantine-color-default-border);-webkit-user-select:none;user-select:none;align-items:center;gap:2px;display:flex;position:relative}._headerCell_188ed_1[data-align=right]{justify-content:flex-end}._headerCell_188ed_1[data-align=center]{justify-content:center}._headerCell_188ed_1[data-control-column=true]{padding:0}._headerCellFiltered_188ed_35 ._headerTitle_188ed_35{color:var(--mantine-primary-color-filled)}._headerTitle_188ed_35{text-overflow:ellipsis;white-space:nowrap;flex:auto;min-width:0;overflow:hidden}._headerCell_188ed_1[data-align=right] ._headerTitle_188ed_35{text-align:right}._headerCell_188ed_1[data-align=center] ._headerTitle_188ed_35{justify-content:center;display:flex}._headerActions_188ed_58{flex-shrink:0;align-items:center;gap:0;margin-left:auto;display:flex}._headerCell_188ed_1[data-align=right] ._headerActions_188ed_58{order:-1;margin-left:0;margin-right:auto}._headerAction_188ed_58{display:none}._headerCell_188ed_1:hover ._headerAction_188ed_58,._headerCell_188ed_1:focus-within ._headerAction_188ed_58,._headerAction_188ed_58[data-pinned-visible=true]{display:flex}._headerCellSortable_188ed_87{cursor:pointer}._sortAction_188ed_93[data-sorted=false]{opacity:.55}._sortAction_188ed_93[data-sorted=false]:hover{opacity:1}._sortIndex_188ed_103{color:var(--mantine-color-dimmed);text-align:center;min-width:10px;font-size:10px;font-weight:600;line-height:1}._headerCellDragging_188ed_115{opacity:.4}._headerCellDropBefore_188ed_119:before,._headerCellDropAfter_188ed_120:before{content:"";background-color:var(--mantine-primary-color-filled);z-index:5;pointer-events:none;width:2px;position:absolute;top:0;bottom:0}._headerCellDropBefore_188ed_119:before{left:0}._headerCellDropAfter_188ed_120:before{right:0}._columnSeparator_188ed_140{z-index:1;justify-content:center;width:10px;height:50%;display:flex;position:absolute;top:25%;right:0;transform:translate(50%)}._columnSeparatorResizable_188ed_152{cursor:col-resize;touch-action:none}._columnSeparator_188ed_140:after{content:"";background-color:#0000;width:1px;height:100%;transition:background-color .12s,width .12s}._headerCell_188ed_1:hover ._columnSeparator_188ed_140:after,._headerCell_188ed_1:focus-within ._columnSeparator_188ed_140:after{background-color:var(--mantine-color-default-border)}._columnSeparatorResizable_188ed_152:hover:after,._columnSeparatorActive_188ed_175:after{background-color:var(--mantine-primary-color-filled);width:2px}._menuItemActive_188ed_181{background-color:var(--mantine-color-default-hover);font-weight:600}._toolbar_4my8t_1{align-items:center;gap:var(--mantine-spacing-xs);padding:6px var(--mantine-spacing-xs);flex-shrink:0;min-height:42px;display:flex}._toolbarSpacer_4my8t_10{flex:1}
1
+ ._root_1wvkg_8[data-size=xs]{--dg-row-height:34px;--dg-header-height:32px;--dg-font-size:var(--mantine-font-size-xs);--dg-padding:6px}._root_1wvkg_8[data-size=sm]{--dg-row-height:42px;--dg-header-height:38px;--dg-font-size:var(--mantine-font-size-sm);--dg-padding:8px}._root_1wvkg_8[data-size=md]{--dg-row-height:52px;--dg-header-height:44px;--dg-font-size:var(--mantine-font-size-sm);--dg-padding:10px}._root_1wvkg_8[data-size=lg]{--dg-row-height:62px;--dg-header-height:52px;--dg-font-size:var(--mantine-font-size-md);--dg-padding:14px}._root_1wvkg_8[data-size=xl]{--dg-row-height:72px;--dg-header-height:60px;--dg-font-size:var(--mantine-font-size-lg);--dg-padding:18px}._root_1wvkg_8{--dg-radius:var(--mantine-radius-md);--dg-row-height:52px;--dg-header-height:44px;--dg-font-size:var(--mantine-font-size-sm);--dg-padding:10px;--dg-row-selected-bg:var(--mantine-primary-color-light);--dg-row-highlight-bg:var(--mantine-primary-color-light-hover);--dg-row-group-bg:var(--mantine-color-body);--dg-row-striped-bg:color-mix(in srgb, var(--mantine-color-text) 3.5%, var(--mantine-color-body));--dg-row-new-bg:color-mix(in srgb, var(--mantine-color-green-6) 8%, var(--mantine-color-body));--dg-z-pinned-cell:2;--dg-z-focused-cell:3;--dg-z-pinned-row:4;--dg-z-pinned-row-pinned-cell:5;--dg-z-summary-row:4;--dg-z-summary-pinned-cell:5;--dg-z-header:6;--dg-z-header-pinned-cell:7;text-align:left;border:1px solid var(--mantine-color-default-border);border-radius:var(--dg-radius);background-color:var(--mantine-color-body);flex-direction:column;min-height:0;display:flex;overflow:hidden}._columnsPanel_1492o_1{flex-direction:column;width:280px;display:flex}._columnsPanelSearch_1492o_7{padding:var(--mantine-spacing-sm)}._columnsPanelList_1492o_11{gap:var(--mantine-spacing-sm);padding:0 var(--mantine-spacing-sm) var(--mantine-spacing-sm);flex-direction:column;display:flex}._columnsPanelFooter_1492o_18{justify-content:space-between;align-items:center;gap:var(--mantine-spacing-sm);padding:var(--mantine-spacing-sm);border-top:1px solid var(--mantine-color-default-border);display:flex}._detailsToggle_n39tz_3{width:100%;height:100%;color:inherit;justify-content:center;align-items:center;display:flex}._detailsToggle_n39tz_3:hover ._chevron_n39tz_12{color:var(--mantine-color-text)}._chevron_n39tz_12{color:var(--mantine-color-dimmed);align-items:center;transition:transform .12s;display:flex}._chevron_n39tz_12[data-expanded=true]{transform:rotate(90deg)}@media (prefers-reduced-motion:reduce){._chevron_n39tz_12{transition:none}}._tableWrapper_uqiy9_2{flex-direction:column;flex:1;min-height:0;display:flex;position:relative}._scrollContainer_uqiy9_10{flex:1;min-height:0;position:relative;overflow:auto;container-type:inline-size}._grid_uqiy9_21{display:grid}._headerRow_uqiy9_27{grid-column:1/-1;grid-template-columns:subgrid;z-index:var(--dg-z-header,6);display:grid;position:sticky;top:0}._headerRow_uqiy9_27[data-dg-header-last]:after{content:"";pointer-events:none;background:linear-gradient(to bottom, var(--dg-header-shadow-color,#00000024), transparent);opacity:0;height:6px;position:absolute;inset:100% 0 auto}@supports (animation-timeline:scroll()){._headerRow_uqiy9_27[data-dg-header-last]:after{animation:linear both _dg-header-shadow_uqiy9_1;animation-timeline:scroll();animation-range:0 24px}}@keyframes _dg-header-shadow_uqiy9_1{0%{opacity:0}to{opacity:1}}._bodyRow_uqiy9_76{--row-bg:var(--mantine-color-body);grid-column:1/-1;grid-template-columns:subgrid;align-items:stretch;display:grid}._bodyRow_uqiy9_76[data-striped=true]{--row-bg:var(--dg-row-striped-bg)}._bodyRow_uqiy9_76:hover{--row-bg:var(--mantine-color-default-hover)}._bodyRow_uqiy9_76[data-grouped=true]{--row-bg:var(--dg-row-group-bg)}._bodyRow_uqiy9_76[data-context-menu=true]{--row-bg:var(--mantine-color-default-hover)}._bodyRow_uqiy9_76[data-selected-bg=true]{--row-bg:var(--dg-row-selected-bg)}._bodyRow_uqiy9_76[data-highlighted=true]{--row-bg:var(--dg-row-highlight-bg)}._bodyRow_uqiy9_76[data-selects-on-click=true]{-webkit-user-select:none;user-select:none}._bodyRow_uqiy9_76:focus-visible{outline:2px solid var(--mantine-primary-color-filled);outline-offset:-2px}._bodyCell_uqiy9_143{padding:0 var(--dg-padding);border-bottom:1px solid var(--mantine-color-default-border);background-color:var(--row-bg);font-size:var(--dg-font-size);align-items:center;display:flex}._bodyCell_uqiy9_143[data-control-column=true]{padding:0}._grid_uqiy9_21[data-range-dragging]{-webkit-user-select:none;user-select:none}._bodyCell_uqiy9_143[data-selected=true]{background-color:color-mix(in srgb, var(--mantine-primary-color-filled) 14%, var(--row-bg));--dg-edge-top:transparent;--dg-edge-bottom:transparent;--dg-edge-left:transparent;--dg-edge-right:transparent;box-shadow:inset 0 1px 0 0 var(--dg-edge-top), inset 0 -1px 0 0 var(--dg-edge-bottom), inset 1px 0 0 0 var(--dg-edge-left), inset -1px 0 0 0 var(--dg-edge-right)}._bodyCell_uqiy9_143[data-edge-top=true]{--dg-edge-top:var(--mantine-primary-color-filled)}._bodyCell_uqiy9_143[data-edge-bottom=true]{--dg-edge-bottom:var(--mantine-primary-color-filled)}._bodyCell_uqiy9_143[data-edge-left=true]{--dg-edge-left:var(--mantine-primary-color-filled)}._bodyCell_uqiy9_143[data-edge-right=true]{--dg-edge-right:var(--mantine-primary-color-filled)}._bodyCell_uqiy9_143[data-focused=true]{outline:2px solid var(--mantine-primary-color-filled);outline-offset:-2px}._cellContent_uqiy9_141{white-space:nowrap;text-overflow:ellipsis;min-width:0;overflow:hidden}._bodyCell_uqiy9_143[data-editing]{padding:0 calc(var(--dg-padding) / 2)}._cellEditor_uqiy9_243{align-items:center;gap:2px;width:100%;min-width:0;display:flex}._cellEditorActions_uqiy9_252{flex:none;align-items:center;display:flex}._bodyCell_uqiy9_143[data-dirty],._bodyCell_uqiy9_143[data-invalid]{position:relative}._bodyCell_uqiy9_143[data-dirty]:after,._bodyCell_uqiy9_143[data-invalid]:after{content:"";border:5px solid #0000;border-top-color:var(--mantine-primary-color-filled);border-right-color:var(--mantine-primary-color-filled);position:absolute;top:0;right:0}._bodyCell_uqiy9_143[data-invalid]:after{border-top-color:var(--mantine-color-error);border-right-color:var(--mantine-color-error)}._bodyCell_uqiy9_143[data-align=right]{justify-content:flex-end}._bodyCell_uqiy9_143[data-align=center]{justify-content:center}._bodyCell_uqiy9_143[data-align=left] ._cellContent_uqiy9_141{flex:auto}._detailsCell_uqiy9_303{border-bottom:1px solid var(--mantine-color-default-border);background-color:var(--row-bg);padding:var(--dg-padding);-webkit-user-select:text;user-select:text;cursor:auto;grid-column:1/-1}._messageRow_uqiy9_15{justify-content:center;justify-self:start;align-items:center;gap:var(--mantine-spacing-xs);width:100cqi;padding:var(--mantine-spacing-xl);flex-direction:column;grid-column:1/-1;display:flex;position:sticky;left:0}._bodyRow_uqiy9_76[data-deleted=true]{opacity:.55;text-decoration:line-through}._bodyRow_uqiy9_76[data-deleted=true] ._bodyCell_uqiy9_143:not([data-control-column=true]){pointer-events:none}._entryBlock_uqiy9_353{grid-column:1/-1;grid-template-columns:subgrid;top:var(--dg-header-height,0px);z-index:var(--dg-z-pinned-row,4);display:grid;position:sticky}._entryRow_uqiy9_362,._entryFlowBlock_uqiy9_371{grid-column:1/-1;grid-template-columns:subgrid;display:grid}._pinnedTopBlock_uqiy9_384{grid-column:1/-1;grid-template-columns:subgrid;top:calc(var(--dg-header-height,0px) + var(--dg-entry-height,0px));z-index:var(--dg-z-pinned-row,4);display:grid;position:sticky}._pinnedTopBlock_uqiy9_384>:last-child>[role=cell]{border-bottom:2px solid var(--mantine-color-default-border)}._pinnedBottomBlock_uqiy9_397{grid-column:1/-1;grid-template-columns:subgrid;bottom:var(--dg-summary-height,0px);z-index:var(--dg-z-pinned-row,4);display:grid;position:sticky}._pinnedBottomBlock_uqiy9_397>:first-child>[role=cell]{border-top:2px solid var(--mantine-color-default-border)}._entryCell_uqiy9_410{padding:0 calc(var(--dg-padding) / 2);border-bottom:2px solid var(--mantine-primary-color-filled);background-color:var(--mantine-color-body);font-size:var(--dg-font-size);align-items:center;display:flex}._entryCell_uqiy9_410[data-control-column=true]{justify-content:center;padding:0}._entryRow_uqiy9_362[data-confirmed=true] ._entryCell_uqiy9_410{padding:0 var(--dg-padding);border-bottom:1px solid var(--mantine-color-default-border);background-color:var(--dg-row-new-bg,var(--mantine-color-body))}._entryRow_uqiy9_362[data-confirmed=true] ._entryCell_uqiy9_410[data-control-column=true]{padding:0}._rowStateIndicator_uqiy9_440{width:22px;height:22px;color:var(--mantine-color-dimmed);flex:none;justify-content:center;align-items:center;display:inline-flex}._rowStateIndicator_uqiy9_440[data-error]{color:var(--mantine-color-error)}._entryCell_uqiy9_410[data-align=right]{justify-content:flex-end}._entryCell_uqiy9_410[data-align=center]{justify-content:center}._matchHighlight_uqiy9_466{background-color:var(--dg-match-highlight-bg,var(--lightningcss-light,var(--mantine-color-yellow-2))var(--lightningcss-dark,#fab00559));color:inherit;border-radius:2px}._summaryRow_uqiy9_478{grid-column:1/-1;grid-template-columns:subgrid;z-index:var(--dg-z-summary-row,4);display:grid;position:sticky;bottom:0}._summaryCell_uqiy9_487{padding:0 var(--dg-padding);border-top:1px solid var(--mantine-color-default-border);background-color:var(--mantine-color-body);font-size:var(--dg-font-size);align-items:center;font-weight:600;display:flex}._summaryCell_uqiy9_487[data-control-column=true]{padding:0}._summaryCell_uqiy9_487[data-align=right]{justify-content:flex-end}._summaryCell_uqiy9_487[data-align=center]{justify-content:center}._groupToggle_1954o_4{width:100%;min-width:0;font-size:var(--dg-font-size);color:inherit;align-items:center;gap:6px;display:flex}._chevron_1954o_14{color:var(--mantine-color-dimmed);flex:none;align-items:center;transition:transform .12s;display:flex}._chevron_1954o_14[data-expanded=true]{transform:rotate(90deg)}@media (prefers-reduced-motion:reduce){._chevron_1954o_14{transition:none}}._groupLabel_1954o_34{white-space:nowrap;text-overflow:ellipsis;min-width:0;font-weight:600;overflow:hidden}._groupCount_1954o_44{color:var(--mantine-color-dimmed);font-variant-numeric:tabular-nums;flex:none}._filterPanel_izakx_4{top:calc(var(--dg-header-height) + 2px);left:var(--mantine-spacing-md);z-index:5;padding:var(--mantine-spacing-sm);border-radius:var(--mantine-radius-md);border:1px solid var(--mantine-color-default-border);background-color:var(--mantine-color-body);box-shadow:var(--mantine-shadow-md);position:absolute}._filterRow_izakx_16{align-items:flex-end;gap:var(--mantine-spacing-xs);display:flex}._filterPanelHeader_izakx_22{justify-content:space-between;align-items:center;gap:var(--mantine-spacing-md);padding-bottom:var(--mantine-spacing-xs);display:flex}._filterPanelFooter_izakx_30{justify-content:space-between;align-items:center;gap:var(--mantine-spacing-md);display:flex}._filterPills_14wl0_3{align-items:center;gap:var(--mantine-spacing-xs);flex-wrap:wrap;display:flex}._filterPills_14wl0_3 ._pill_14wl0_15{background-color:var(--lightningcss-light,var(--mantine-color-gray-1))var(--lightningcss-dark,var(--mantine-color-dark-5));color:var(--lightningcss-light,var(--mantine-color-black))var(--lightningcss-dark,var(--mantine-color-dark-0));border:1px solid var(--lightningcss-light,var(--mantine-color-gray-3))var(--lightningcss-dark,var(--mantine-color-dark-3))}._pillLabel_14wl0_27{font:inherit;color:inherit;cursor:pointer}._pillLabel_14wl0_27:hover{text-decoration:underline}._footer_te0a3_1{justify-content:flex-end;align-items:center;gap:var(--mantine-spacing-lg);padding:4px var(--mantine-spacing-sm);border-top:1px solid var(--mantine-color-default-border);flex-shrink:0;min-height:48px;display:flex}._footer_te0a3_1[data-paging-suspended=true]{opacity:.55}._stickyLeft_1vw51_16:after,._stickyRight_1vw51_17:after{content:"";pointer-events:none;width:8px;position:absolute;top:0;bottom:0}._stickyLeft_1vw51_16:after{background:linear-gradient(90deg,var(--lightningcss-light,#00000012)var(--lightningcss-dark,#00000042),var(--lightningcss-light,#00000006)var(--lightningcss-dark,#00000017) 45%,#0000);left:100%}._stickyRight_1vw51_17:after{background:linear-gradient(270deg,var(--lightningcss-light,#00000012)var(--lightningcss-dark,#00000042),var(--lightningcss-light,#00000006)var(--lightningcss-dark,#00000017) 45%,#0000);right:100%}@supports (animation-timeline:scroll()){._stickyLeft_1vw51_16:after,._stickyRight_1vw51_17:after{--dg-sticky-edge-range:20px;opacity:0;animation-timing-function:linear;animation-fill-mode:both;animation-timeline:scroll(inline)}._stickyLeft_1vw51_16:after{animation-name:_stickyEdgeIn_1vw51_1;animation-range:0 var(--dg-sticky-edge-range)}._stickyRight_1vw51_17:after{animation-name:_stickyEdgeOut_1vw51_1;animation-range:calc(100% - var(--dg-sticky-edge-range)) 100%}}@keyframes _stickyEdgeIn_1vw51_1{0%{opacity:0}to{opacity:1}}@keyframes _stickyEdgeOut_1vw51_1{0%{opacity:1}to{opacity:0}}._headerCell_188ed_1{padding:0 var(--dg-padding);min-width:0;min-height:var(--dg-header-height);font-weight:600;font-size:var(--dg-font-size);background-color:var(--mantine-color-body);border-bottom:1px solid var(--mantine-color-default-border);-webkit-user-select:none;user-select:none;align-items:center;gap:2px;display:flex;position:relative}._headerCell_188ed_1[data-align=right]{justify-content:flex-end}._headerCell_188ed_1[data-align=center]{justify-content:center}._headerCell_188ed_1[data-control-column=true]{padding:0}._headerCellFiltered_188ed_35 ._headerTitle_188ed_35{color:var(--mantine-primary-color-filled)}._headerTitle_188ed_35{text-overflow:ellipsis;white-space:nowrap;flex:auto;min-width:0;overflow:hidden}._headerCell_188ed_1[data-align=right] ._headerTitle_188ed_35{text-align:right}._headerCell_188ed_1[data-align=center] ._headerTitle_188ed_35{justify-content:center;display:flex}._headerActions_188ed_58{flex-shrink:0;align-items:center;gap:0;margin-left:auto;display:flex}._headerCell_188ed_1[data-align=right] ._headerActions_188ed_58{order:-1;margin-left:0;margin-right:auto}._headerAction_188ed_58{display:none}._headerCell_188ed_1:hover ._headerAction_188ed_58,._headerCell_188ed_1:focus-within ._headerAction_188ed_58,._headerAction_188ed_58[data-pinned-visible=true]{display:flex}._headerCellSortable_188ed_87{cursor:pointer}._sortAction_188ed_93[data-sorted=false]{opacity:.55}._sortAction_188ed_93[data-sorted=false]:hover{opacity:1}._sortIndex_188ed_103{color:var(--mantine-color-dimmed);text-align:center;min-width:10px;font-size:10px;font-weight:600;line-height:1}._headerCellDragging_188ed_115{opacity:.4}._headerCellDropBefore_188ed_119:before,._headerCellDropAfter_188ed_120:before{content:"";background-color:var(--mantine-primary-color-filled);z-index:5;pointer-events:none;width:2px;position:absolute;top:0;bottom:0}._headerCellDropBefore_188ed_119:before{left:0}._headerCellDropAfter_188ed_120:before{right:0}._columnSeparator_188ed_140{z-index:1;justify-content:center;width:10px;height:50%;display:flex;position:absolute;top:25%;right:0;transform:translate(50%)}._columnSeparatorResizable_188ed_152{cursor:col-resize;touch-action:none}._columnSeparator_188ed_140:after{content:"";background-color:#0000;width:1px;height:100%;transition:background-color .12s,width .12s}._headerCell_188ed_1:hover ._columnSeparator_188ed_140:after,._headerCell_188ed_1:focus-within ._columnSeparator_188ed_140:after{background-color:var(--mantine-color-default-border)}._columnSeparatorResizable_188ed_152:hover:after,._columnSeparatorActive_188ed_175:after{background-color:var(--mantine-primary-color-filled);width:2px}._menuItemActive_188ed_181{background-color:var(--mantine-color-default-hover);font-weight:600}._toolbar_4my8t_1{align-items:center;gap:var(--mantine-spacing-xs);padding:6px var(--mantine-spacing-xs);flex-shrink:0;min-height:42px;display:flex}._toolbarSpacer_4my8t_10{flex:1}
2
2
  /*$vite$:1*/
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jielga/tmdatagrid",
3
- "version": "2.0.0-beta.1",
3
+ "version": "2.0.0-beta.2",
4
4
  "description": "A React data grid built on TanStack Table v9 and Mantine - always virtualized, with resizable, reorderable, sortable, filterable, hideable and pinnable columns.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -16,7 +16,7 @@ description: >
16
16
  metadata:
17
17
  type: core
18
18
  library: '@jielga/tmdatagrid'
19
- library_version: '2.0.0-beta.1'
19
+ library_version: '2.0.0-beta.2'
20
20
  sources:
21
21
  - 'Jielga/TMDataGrid:src/docs/styling.md'
22
22
  - 'Jielga/TMDataGrid:src/docs/toolbar.md'
@@ -14,7 +14,7 @@ description: >
14
14
  metadata:
15
15
  type: core
16
16
  library: '@jielga/tmdatagrid'
17
- library_version: '2.0.0-beta.1'
17
+ library_version: '2.0.0-beta.2'
18
18
  sources:
19
19
  - 'Jielga/TMDataGrid:src/docs/cell-selection.md'
20
20
  - 'Jielga/TMDataGrid:src/tmdatagrid/core/cellNavigation.ts'
@@ -16,7 +16,7 @@ description: >
16
16
  metadata:
17
17
  type: core
18
18
  library: '@jielga/tmdatagrid'
19
- library_version: '2.0.0-beta.1'
19
+ library_version: '2.0.0-beta.2'
20
20
  sources:
21
21
  - 'Jielga/TMDataGrid:src/docs/columns.md'
22
22
  - 'Jielga/TMDataGrid:src/docs/column-layout.md'
@@ -246,7 +246,7 @@ asks for it.
246
246
  | Checkbox | `SELECT_COLUMN_ID` | Selection is on and the mode has checkboxes |
247
247
  | Tree | `GROUP_COLUMN_ID` | A column is grouped |
248
248
  | Details | `DETAILS_COLUMN_ID` | `renderDetails` is set |
249
- | Edit | `EDIT_COLUMN_ID` | Row mode, `editing.onRowDelete`, or batch with `editing.onCommitBatch` |
249
+ | Edit | `EDIT_COLUMN_ID` | Row mode, draft mode, or `editing.onRowDelete` |
250
250
 
251
251
  They are structural: fixed width, no column menu, and they cannot be sorted,
252
252
  filtered, resized, re-pinned or moved. The checkbox lane anchors the left pinned
@@ -15,7 +15,7 @@ description: >
15
15
  metadata:
16
16
  type: core
17
17
  library: '@jielga/tmdatagrid'
18
- library_version: '2.0.0-beta.1'
18
+ library_version: '2.0.0-beta.2'
19
19
  sources:
20
20
  - 'Jielga/TMDataGrid:src/docs/pagination.md'
21
21
  - 'Jielga/TMDataGrid:src/docs/scrolling.md'
@@ -2,8 +2,8 @@
2
2
  name: editing
3
3
  description: >
4
4
  Edit cells and rows in TMDataGrid. Covers the editing option with its four
5
- mode policies (cell, cellConfirm, row, batch), the required getRowId,
6
- editing.onCommit and editing.onCommitBatch, why the grid never mutates data,
5
+ mode policies (cell, cellConfirm, row, draft), the required getRowId,
6
+ editing.onCommit and editing.onCommitDrafts, why the grid never mutates data,
7
7
  per-column gating with meta.edit.enabled and meta.edit.field, the six built-in
8
8
  editors picked by meta.type, custom editors through meta.edit.editor,
9
9
  per-keystroke value mapping with meta.edit.mapValue, field validation with
@@ -17,7 +17,7 @@ description: >
17
17
  metadata:
18
18
  type: core
19
19
  library: '@jielga/tmdatagrid'
20
- library_version: '2.0.0-beta.1'
20
+ library_version: '2.0.0-beta.2'
21
21
  sources:
22
22
  - 'Jielga/TMDataGrid:src/docs/editing.md'
23
23
  - 'Jielga/TMDataGrid:src/docs/query-builder.md'
@@ -69,8 +69,8 @@ const grid = useTMDataGrid({
69
69
  ```
70
70
 
71
71
  Two rules are compile errors, not options that silently do nothing: `editing`
72
- requires `getRowId`, and `editing.onCommitBatch` exists only under
73
- `editing.mode: "batch"`. Batch _without_ `onCommitBatch` is fine: `submitAll`
72
+ requires `getRowId`, and `editing.onCommitDrafts` exists only under
73
+ `editing.mode: "draft"`. Draft _without_ `onCommitDrafts` is fine: `submitAll`
74
74
  falls back to the per-row `editing.onCommit` loop.
75
75
 
76
76
  ## The four modes
@@ -83,16 +83,17 @@ as a commit, and which controls trigger it.
83
83
  | `"cell"` | Enter, Tab, blur | Escape | none |
84
84
  | `"cellConfirm"` | ✓ or Enter; blur keeps the draft | ✕ or Escape | ✓ / ✕ beside the input |
85
85
  | `"row"` | Save in the edit lane, or Ctrl+Enter | Cancel, or Escape | generated edit lane |
86
- | `"batch"` | `edit.submitAll()` | `edit.cancelAll()` | `TMDataGrid.EditActions` |
86
+ | `"draft"` | `edit.submitAll()` | `edit.cancelAll()`, or per row in the lane | `TMDataGrid.EditActions` + the edit lane |
87
87
 
88
88
  Which to pick: `"cell"` for saved-as-you-go spreadsheet feel; `"cellConfirm"`
89
89
  when a stray click must not fire a request; `"row"` when the row is the unit of
90
- the save or a rule spans two columns; `"batch"` for many edits sent as one
90
+ the save or a rule spans two columns; `"draft"` for many edits sent as one
91
91
  transaction.
92
92
 
93
93
  An editor opens on double-click, or with the cell cursor on the cell: Enter, F2,
94
94
  or typing, where the first character replaces the value. Delete or Backspace
95
- clears the value and commits without opening an editor. Editing implies cell
95
+ clears the value and commits without opening an editor; under `"draft"` the
96
+ cleared value is held with the other drafts instead. Editing implies cell
96
97
  selection: `cellSelection` defaults to `"single"` while `editing` is set. The
97
98
  grid places the caret in the cell that was opened, and `edit.addRow()` places it
98
99
  in the new row's first editable cell, so a `meta.edit.editor` receives focus
@@ -103,13 +104,26 @@ the cell clicked, opens every editable cell of the row, and ✓ saves them as on
103
104
  commit. Rows accumulate: opening a second row leaves the first open, and each
104
105
  row's ✓ and ✕ act on that row alone.
105
106
 
106
- Under `"batch"` nothing leaves the grid until `submitAll`. Enter and Tab park
107
- the draft, dirty-marked, Escape drops that one draft, and drafts accumulate
108
- across rows. `submitAll` then commits every open row: through the per-row
109
- `editing.onCommit` loop by default, or through one
110
- `editing.onCommitBatch({ rows, added, deleted })` call when that is set. Rows
111
- failing validation stay open either way, and a rejected batch keeps every
112
- draft.
107
+ Under `"draft"` nothing reaches a callback until `submitAll`. Enter and Tab hold
108
+ the draft, Tab moving on to the next editable cell, Escape drops that one draft,
109
+ and drafts accumulate across rows, surviving filters, sorts and scrolling.
110
+ `edit.commit(rowId)` validates and holds the draft too, so there is no per-row
111
+ escape hatch to the consumer. A held draft is displayed: the cell renders the
112
+ draft value through the column's own `cell` renderer, with the blue corner
113
+ marking it dirty and `data-dirty` on the row.
114
+
115
+ The edit lane is the change indicator and the per-row undo: an edited row shows
116
+ a pencil icon and Revert, which drops that row's draft; a new row a plus icon, a
117
+ pencil that reopens it, and ✕; a row marked for deletion a trash icon and
118
+ Restore. A row holding a dirty draft hides the trash - revert first, then
119
+ delete. A row blocked by validation turns its icon red with the message in the
120
+ tooltip.
121
+
122
+ `submitAll` then commits every pending change: through the per-row
123
+ `editing.onCommit` / `editing.onRowAdd` / `editing.onRowDelete` loop by default,
124
+ or through one `editing.onCommitDrafts({ rows, added, deleted })` call when that
125
+ is set. Rows failing validation stay open either way, and a rejected save keeps
126
+ every draft.
113
127
 
114
128
  ## What a commit receives
115
129
 
@@ -169,7 +183,7 @@ import { z } from "zod";
169
183
  // Field level, on the column. A bare schema means { onChange: schema }.
170
184
  meta: { edit: { validate: z.string().min(2, "At least two characters") } }
171
185
 
172
- // Form level, inside `editing`. Cross-field rules, under "row" or "batch".
186
+ // Form level, inside `editing`. Cross-field rules, under "row" or "draft".
173
187
  rowValidators: {
174
188
  onSubmit: z
175
189
  .object({ salary: z.number().positive(), status: z.string() })
@@ -197,8 +211,17 @@ Detail for all three: [references/editors-and-validation.md](references/editors-
197
211
 
198
212
  `edit.addRow()` opens an entry row in a sticky block under the header, seeded
199
213
  from `editing.newRowDefaults`. Enter, or the lane's ✓, commits the add through
200
- `editing.onRowAdd` under the immediate modes; batch parks it for `submitAll`.
201
- Escape, or ✕, discards it.
214
+ `editing.onRowAdd` under the immediate modes; under draft mode it enters the
215
+ row, which is validated, held with the other drafts, and reported in
216
+ `submitAll`'s `added`. Escape, or ✕, discards the entry.
217
+
218
+ Under `"draft"` an entered row renders as a value row with no inputs, marked
219
+ `data-new` and `data-confirmed` and tinted with `--dg-row-new-bg`. By default it
220
+ joins the scrolling flow above the body rows; `editing.newRowsSticky: true`
221
+ keeps entered rows pinned in the entry block until Save all. Double-click, or
222
+ the lane's pencil, reopens it; ✕ removes it. To limit how many entry rows are
223
+ open at once, gate the Add button on
224
+ `useSelector(grid.edit.store, (s) => s.newRows.some((n) => !n.confirmed))`.
202
225
 
203
226
  ```tsx
204
227
  const grid = useTMDataGrid({
@@ -206,9 +229,9 @@ const grid = useTMDataGrid({
206
229
  columns,
207
230
  getRowId: (row) => String(row.id),
208
231
  editing: {
209
- mode: "batch",
232
+ mode: "draft",
210
233
  newRowDefaults: () => ({ id: 0, firstName: "", salary: 30_000 }),
211
- onCommitBatch: async ({ rows, added, deleted }) => {
234
+ onCommitDrafts: async ({ rows, added, deleted }) => {
212
235
  await api.saveBatch({ rows, added, deleted });
213
236
  },
214
237
  },
@@ -223,21 +246,23 @@ const grid = useTMDataGrid({
223
246
 
224
247
  `edit.deleteRow(rowId)` calls `editing.onRowDelete({ rowId, row })` immediately
225
248
  under the immediate modes, so put any confirmation inside that callback. Under
226
- batch it toggles a mark instead: the row renders struck through and inert
227
- (`data-deleted`), the lane's trash becomes a restore, and `submitAll` reports
228
- the ids in `deleted`. You apply adds and deletes, the same as edits. The
229
- engine's `tempId` (`__new__1`, …) does not need to become a real id.
249
+ draft mode it toggles a mark instead: the row renders struck through and inert
250
+ (`data-deleted`), the lane shows Restore, and `submitAll` reports the ids in
251
+ `deleted`. You apply adds and deletes, the same as edits. The engine's `tempId`
252
+ (`__new__1`, …) does not need to become a real id.
230
253
 
231
254
  ## The built-in controls
232
255
 
233
256
  The generated edit lane (`EDIT_COLUMN_ID`, pinned right) appears when
234
- `editing.mode` is `"row"`, or `editing.onRowDelete` is set, or `editing.mode` is
235
- `"batch"` with `editing.onCommitBatch` set. Nothing else adds it, and `"cell"`
236
- mode renders no controls of its own.
257
+ `editing.mode` is `"row"` or `"draft"`, or when `editing.onRowDelete` is set.
258
+ Nothing else adds it, and `"cell"` mode renders no controls of its own. Under
259
+ `"row"` it holds Save and Cancel while a row is open; under `"draft"` it holds
260
+ the row-state marker with Revert and Restore, and Save and Cancel never appear.
261
+ Every control carries a tooltip from the labels.
237
262
 
238
263
  `TMDataGrid.EditActions` is Save with the pending count plus Discard. It greys
239
264
  out while nothing is pending, spins while a submit is in flight, renders nothing
240
- while editing is off, and works under any mode, not only batch.
265
+ while editing is off, and works under any mode, not only draft.
241
266
 
242
267
  `renderActions` replaces the pair and hands over its pieces:
243
268
 
@@ -286,192 +311,20 @@ the form cannot see a draft.
286
311
 
287
312
  ## Common mistakes
288
313
 
289
- ### CRITICAL Expecting the grid to write into `data`
314
+ Each one compiles and raises no warning. The reason and the fix for every entry
315
+ are in [references/common-mistakes.md](references/common-mistakes.md).
290
316
 
291
- The grid holds no copy of the rows. Without `editing.onCommit` an edit commits,
292
- the draft clears, and the cell reverts to the value in `data`.
293
-
294
- Wrong:
295
-
296
- ```tsx
297
- useTMDataGrid({
298
- data: employees,
299
- columns,
300
- getRowId,
301
- editing: { mode: "cell" },
302
- });
303
- ```
304
-
305
- Correct: wire `editing.onCommit` to apply the change where the data lives, as
306
- in [Setup](#setup).
307
-
308
- Source: `src/docs/editing.md`, `src/tmdatagrid/core/editEngine.ts`.
309
-
310
- ### CRITICAL `getRowId` built from the row index
311
-
312
- `getRowId` accepts any string, so an index-based id compiles. Drafts are keyed
313
- by it, so after a sort or a filter the draft is applied to whichever record now
314
- sits at that index.
315
-
316
- Wrong:
317
-
318
- ```tsx
319
- getRowId: (row, index) => String(index),
320
- ```
321
-
322
- Correct:
323
-
324
- ```tsx
325
- getRowId: (row) => String(row.id),
326
- ```
327
-
328
- Source: `src/tmdatagrid/useTMDataGrid.tsx` (`TMDataGridEditingCallbacks`).
329
-
330
- ### HIGH A cell editor defined inside the component
331
-
332
- `meta.edit.editor` is rendered as JSX, so its identity is its component type. An
333
- inline arrow function is a new type on every render, which unmounts the open
334
- editor and discards what was being typed.
335
-
336
- Wrong:
337
-
338
- ```tsx
339
- meta: { edit: { editor: ({ field }) => <Slider value={field.state.value} /> } },
340
- ```
341
-
342
- Correct:
343
-
344
- ```tsx
345
- // Module scope, referenced by name.
346
- const SalaryEditor: TMDataGridEditorComponent = ({ field, commit }) => (
347
- <Slider
348
- value={Number(field.state.value ?? 0)}
349
- onChange={(next) => field.handleChange(next)}
350
- onChangeEnd={() => void commit()}
351
- />
352
- );
353
-
354
- meta: { edit: { editor: SalaryEditor } },
355
- ```
356
-
357
- Source: `src/docs/editors.md`, `src/tmdatagrid/core/editEngine.ts`.
358
-
359
- ### HIGH A cross-field rule under `editing.mode: "cell"`
360
-
361
- Under `"cell"` each cell commits on its own, so a rule spanning two columns
362
- cannot be satisfied by either one: the first cell edited is rejected against the
363
- other column's old value, and the row cannot be saved.
364
-
365
- Wrong:
366
-
367
- ```tsx
368
- useTMDataGrid({
369
- editing: { mode: "cell", rowValidators: { onSubmit: endAfterStart } },
370
- });
371
- ```
372
-
373
- Correct:
374
-
375
- ```tsx
376
- // "row" (or "batch") validates the whole row in one commit.
377
- useTMDataGrid({
378
- editing: { mode: "row", rowValidators: { onSubmit: endAfterStart } },
379
- });
380
- ```
381
-
382
- Source: `src/docs/editors.md` (Validation).
383
-
384
- ### HIGH An `accessorFn` column that never opens an editor
385
-
386
- Editability follows the data path, not the column. A column built on an accessor
387
- function has no `accessorKey`, so it maps to nothing and stays read-only while
388
- every other column edits. No warning is raised.
389
-
390
- Wrong:
391
-
392
- ```tsx
393
- columnHelper.accessor((row) => `${row.firstName} ${row.lastName}`, {
394
- id: "fullName",
395
- header: "Full name",
396
- });
397
- ```
398
-
399
- Correct:
400
-
401
- ```tsx
402
- columnHelper.accessor((row) => `${row.firstName} ${row.lastName}`, {
403
- id: "fullName",
404
- header: "Full name",
405
- meta: { label: "Full name", edit: { field: "lastName" } },
406
- });
407
- ```
408
-
409
- Source: `src/docs/editing.md` (Which cells edit).
410
-
411
- ### HIGH Swallowing the error in `editing.onCommit`
412
-
413
- The draft is dropped when `editing.onCommit` resolves. A `try/catch` that logs
414
- the failure resolves it, so a save that failed on the server clears the editor
415
- and the grid shows the old value as though nothing happened.
416
-
417
- Wrong:
418
-
419
- ```tsx
420
- onCommit: async ({ rowId, changes }) => {
421
- try {
422
- await api.patch(rowId, changes);
423
- } catch (error) {
424
- console.error(error);
425
- }
426
- },
427
- ```
428
-
429
- Correct: no `catch` - let the rejection propagate, and the form stays open
430
- with the error on the row.
431
-
432
- Source: `src/tmdatagrid/useTMDataGrid.tsx` (`TMDataGridEditingCallbacks`).
433
-
434
- ### HIGH Submitting an outer form while the grid holds a draft
435
-
436
- The outer form's array contains only committed rows. Under any mode a mid-edit
437
- row is invisible to it, and under `"batch"` every edit is until `submitAll()`,
438
- so a form submit saves stale rows and collection rules skip pending values.
439
-
440
- Correct:
441
-
442
- ```tsx
443
- const hasOpenDraft = useSelector(grid.edit.store, (s) => s.openRowIds.length > 0);
444
-
445
- <Button type="submit" disabled={!canSubmit || hasOpenDraft}>Save</Button>
446
- // or flush instead of blocking:
447
- const flushed = await grid.edit.submitAll();
448
- if (flushed) await form.handleSubmit();
449
- ```
450
-
451
- Source: `src/docs/query-builder.md` (Which mode, Submitting).
452
-
453
- ### MEDIUM Reading a commit's result as the saved value
454
-
455
- `edit.commit(rowId)` and `edit.submitAll()` resolve to a `boolean` saying
456
- whether the form closed, and resolve `false` when validation or a rejected save
457
- kept it open. Ignoring the result reports a save that did not happen.
458
-
459
- ```tsx
460
- const saved = await grid.edit.submitAll();
461
- notifications.show({ message: saved ? "Saved" : "Some rows need attention" });
462
- ```
463
-
464
- Source: `src/tmdatagrid/core/editEngine.ts` (`TMDataGridEditApi`).
465
-
466
- ### MEDIUM Expecting `editing.onRowDelete` to fire under batch
467
-
468
- Under the immediate modes `edit.deleteRow` calls `editing.onRowDelete` at once.
469
- Under `"batch"` it only toggles a deletion mark, and the ids arrive later in
470
- `submitAll`'s `deleted`, so a batch grid that deletes through
471
- `editing.onRowDelete` alone never removes anything. Handle `deleted` in
472
- `editing.onCommitBatch`.
473
-
474
- Source: `src/docs/editing.md` (Adding and deleting rows).
317
+ | Severity | Mistake |
318
+ | --- | --- |
319
+ | CRITICAL | Expecting the grid to write into `data` - without `editing.onCommit` the cell reverts |
320
+ | CRITICAL | `getRowId` built from the row index - drafts follow the index, not the record |
321
+ | HIGH | A cell editor defined inside the component - a new type per render unmounts the editor |
322
+ | HIGH | A cross-field rule under `mode: "cell"` - `rowValidators` needs `"row"` or `"draft"` |
323
+ | HIGH | An `accessorFn` column with no `meta.edit.field` - it maps to nothing and stays read-only |
324
+ | HIGH | Swallowing the error in `editing.onCommit` - a resolved catch drops the draft |
325
+ | HIGH | Submitting an outer form while the grid holds a draft - it saves stale rows |
326
+ | MEDIUM | Reading a commit's result as the saved value - it is a `boolean` about the form |
327
+ | MEDIUM | Expecting `editing.onRowDelete` to fire under draft - the mark waits for `submitAll` |
475
328
 
476
329
  ## References
477
330
 
@@ -480,6 +333,8 @@ Source: `src/docs/editing.md` (Adding and deleting rows).
480
333
  validators, server-side errors.
481
334
  - [Editing API](references/editing-api.md) - every option, callback, column meta
482
335
  field, export, CSS variable and data attribute belonging to editing.
336
+ - [Common mistakes](references/common-mistakes.md) - the failure modes above,
337
+ each with its wrong and correct form.
483
338
 
484
339
  See also: the `columns` skill for `meta.type` and the shared `meta.options`
485
340
  source, and the `testing` skill for driving editors from a test.