@toclocoinc/lattice-grid 1.67.0 → 1.68.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.
Files changed (163) hide show
  1. package/README.md +1 -1
  2. package/angular/package.json +1 -1
  3. package/docs/API.html +21 -16
  4. package/docs/api-detail.html +40 -5
  5. package/lattice-grid.d.ts +12 -2
  6. package/lattice-grid.esm.min.js +27 -7
  7. package/lattice-grid.min.cjs +27 -7
  8. package/lattice-grid.min.js +27 -7
  9. package/modules/ai.d.ts +1 -1
  10. package/modules/ai.esm.min.js +3 -3
  11. package/modules/ai.min.cjs +3 -3
  12. package/modules/ai.min.js +3 -3
  13. package/modules/angular.d.ts +1 -1
  14. package/modules/angular.esm.min.js +3 -3
  15. package/modules/angular.min.cjs +3 -3
  16. package/modules/angular.min.js +3 -3
  17. package/modules/chart-alluvial.d.ts +1 -1
  18. package/modules/chart-alluvial.esm.min.js +1 -1
  19. package/modules/chart-alluvial.min.cjs +1 -1
  20. package/modules/chart-alluvial.min.js +1 -1
  21. package/modules/chart-arc.d.ts +1 -1
  22. package/modules/chart-arc.esm.min.js +1 -1
  23. package/modules/chart-arc.min.cjs +1 -1
  24. package/modules/chart-arc.min.js +1 -1
  25. package/modules/chart-bubblemap.d.ts +1 -1
  26. package/modules/chart-bubblemap.esm.min.js +1 -1
  27. package/modules/chart-bubblemap.min.cjs +1 -1
  28. package/modules/chart-bubblemap.min.js +1 -1
  29. package/modules/chart-bump.d.ts +1 -1
  30. package/modules/chart-bump.esm.min.js +1 -1
  31. package/modules/chart-bump.min.cjs +1 -1
  32. package/modules/chart-bump.min.js +1 -1
  33. package/modules/chart-calendar.d.ts +1 -1
  34. package/modules/chart-calendar.esm.min.js +1 -1
  35. package/modules/chart-calendar.min.cjs +1 -1
  36. package/modules/chart-calendar.min.js +1 -1
  37. package/modules/chart-decomposition.d.ts +1 -1
  38. package/modules/chart-decomposition.esm.min.js +1 -1
  39. package/modules/chart-decomposition.min.cjs +1 -1
  40. package/modules/chart-decomposition.min.js +1 -1
  41. package/modules/chart-diverging.d.ts +1 -1
  42. package/modules/chart-diverging.esm.min.js +1 -1
  43. package/modules/chart-diverging.min.cjs +1 -1
  44. package/modules/chart-diverging.min.js +1 -1
  45. package/modules/chart-dumbbell.d.ts +1 -1
  46. package/modules/chart-dumbbell.esm.min.js +1 -1
  47. package/modules/chart-dumbbell.min.cjs +1 -1
  48. package/modules/chart-dumbbell.min.js +1 -1
  49. package/modules/chart-fan.d.ts +1 -1
  50. package/modules/chart-fan.esm.min.js +1 -1
  51. package/modules/chart-fan.min.cjs +1 -1
  52. package/modules/chart-fan.min.js +1 -1
  53. package/modules/chart-hexbin.d.ts +1 -1
  54. package/modules/chart-hexbin.esm.min.js +1 -1
  55. package/modules/chart-hexbin.min.cjs +1 -1
  56. package/modules/chart-hexbin.min.js +1 -1
  57. package/modules/chart-hexmap.d.ts +1 -1
  58. package/modules/chart-hexmap.esm.min.js +1 -1
  59. package/modules/chart-hexmap.min.cjs +1 -1
  60. package/modules/chart-hexmap.min.js +1 -1
  61. package/modules/chart-icicle.d.ts +1 -1
  62. package/modules/chart-icicle.esm.min.js +1 -1
  63. package/modules/chart-icicle.min.cjs +1 -1
  64. package/modules/chart-icicle.min.js +1 -1
  65. package/modules/chart-markermap.d.ts +1 -1
  66. package/modules/chart-markermap.esm.min.js +1 -1
  67. package/modules/chart-markermap.min.cjs +1 -1
  68. package/modules/chart-markermap.min.js +1 -1
  69. package/modules/chart-parallel.d.ts +1 -1
  70. package/modules/chart-parallel.esm.min.js +1 -1
  71. package/modules/chart-parallel.min.cjs +1 -1
  72. package/modules/chart-parallel.min.js +1 -1
  73. package/modules/chart-ridgeline.d.ts +1 -1
  74. package/modules/chart-ridgeline.esm.min.js +1 -1
  75. package/modules/chart-ridgeline.min.cjs +1 -1
  76. package/modules/chart-ridgeline.min.js +1 -1
  77. package/modules/chart-roc.d.ts +1 -1
  78. package/modules/chart-roc.esm.min.js +1 -1
  79. package/modules/chart-roc.min.cjs +1 -1
  80. package/modules/chart-roc.min.js +1 -1
  81. package/modules/chart-slope.d.ts +1 -1
  82. package/modules/chart-slope.esm.min.js +1 -1
  83. package/modules/chart-slope.min.cjs +1 -1
  84. package/modules/chart-slope.min.js +1 -1
  85. package/modules/chart-splom.d.ts +1 -1
  86. package/modules/chart-splom.esm.min.js +1 -1
  87. package/modules/chart-splom.min.cjs +1 -1
  88. package/modules/chart-splom.min.js +1 -1
  89. package/modules/chart-waffle.d.ts +1 -1
  90. package/modules/chart-waffle.esm.min.js +1 -1
  91. package/modules/chart-waffle.min.cjs +1 -1
  92. package/modules/chart-waffle.min.js +1 -1
  93. package/modules/charts.d.ts +1 -1
  94. package/modules/charts.esm.min.js +1376 -1249
  95. package/modules/charts.min.cjs +1376 -1249
  96. package/modules/charts.min.js +1376 -1249
  97. package/modules/data-router.d.ts +1 -1
  98. package/modules/data-router.esm.min.js +204 -8
  99. package/modules/data-router.min.cjs +204 -8
  100. package/modules/data-router.min.js +204 -8
  101. package/modules/devtools.d.ts +1 -1
  102. package/modules/devtools.esm.min.js +1 -1
  103. package/modules/devtools.min.cjs +1 -1
  104. package/modules/devtools.min.js +1 -1
  105. package/modules/dhtmlx-compat.d.ts +1 -1
  106. package/modules/dhtmlx-compat.esm.min.js +3 -3
  107. package/modules/dhtmlx-compat.min.cjs +3 -3
  108. package/modules/dhtmlx-compat.min.js +3 -3
  109. package/modules/gantt.d.ts +1 -1
  110. package/modules/gantt.esm.min.js +32 -7
  111. package/modules/gantt.min.cjs +32 -7
  112. package/modules/gantt.min.js +32 -7
  113. package/modules/geo-europe-nuts.d.ts +1 -1
  114. package/modules/geo-europe-nuts.esm.min.js +1 -1
  115. package/modules/geo-uk.d.ts +1 -1
  116. package/modules/geo-uk.esm.min.js +1 -1
  117. package/modules/geo-us-states.d.ts +1 -1
  118. package/modules/geo-us-states.esm.min.js +1 -1
  119. package/modules/geo-world-110m.d.ts +1 -1
  120. package/modules/geo-world-110m.esm.min.js +1 -1
  121. package/modules/geo-world-50m.d.ts +1 -1
  122. package/modules/geo-world-50m.esm.min.js +1 -1
  123. package/modules/htmx.d.ts +1 -1
  124. package/modules/htmx.esm.min.js +27 -7
  125. package/modules/htmx.min.cjs +27 -7
  126. package/modules/htmx.min.js +27 -7
  127. package/modules/kanban.d.ts +1 -1
  128. package/modules/kanban.esm.min.js +3 -3
  129. package/modules/kanban.min.cjs +3 -3
  130. package/modules/kanban.min.js +3 -3
  131. package/modules/kpi.d.ts +26 -8
  132. package/modules/kpi.esm.min.js +31 -6
  133. package/modules/kpi.min.cjs +31 -6
  134. package/modules/kpi.min.js +31 -6
  135. package/modules/layout.d.ts +1 -1
  136. package/modules/layout.esm.min.js +3 -3
  137. package/modules/layout.min.cjs +3 -3
  138. package/modules/layout.min.js +3 -3
  139. package/modules/mock-socket.d.ts +1 -1
  140. package/modules/mock-socket.esm.min.js +1 -1
  141. package/modules/mock-socket.min.cjs +1 -1
  142. package/modules/mock-socket.min.js +1 -1
  143. package/modules/react.d.ts +1 -1
  144. package/modules/react.esm.min.js +3 -3
  145. package/modules/react.min.cjs +3 -3
  146. package/modules/react.min.js +3 -3
  147. package/modules/svelte.d.ts +1 -1
  148. package/modules/svelte.esm.min.js +3 -3
  149. package/modules/svelte.min.cjs +3 -3
  150. package/modules/svelte.min.js +3 -3
  151. package/modules/tabs.d.ts +1 -1
  152. package/modules/tabs.esm.min.js +13 -14
  153. package/modules/tabs.min.cjs +13 -14
  154. package/modules/tabs.min.js +13 -14
  155. package/modules/vue.d.ts +1 -1
  156. package/modules/vue.esm.min.js +3 -3
  157. package/modules/vue.min.cjs +3 -3
  158. package/modules/vue.min.js +3 -3
  159. package/modules/webcomponent.d.ts +1 -1
  160. package/modules/webcomponent.esm.min.js +27 -7
  161. package/modules/webcomponent.min.cjs +27 -7
  162. package/modules/webcomponent.min.js +27 -7
  163. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Lattice Grid 1.67.0, data-router module type declarations
2
+ * Lattice Grid 1.68.0, data-router module type declarations
3
3
  * Copyright (c) 2026 TOCLOCO Inc. All rights reserved.
4
4
  * https://latticegrid.dev
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Lattice Grid 1.67.0, data-router module
2
+ * Lattice Grid 1.68.0, data-router module
3
3
  * Copyright (c) 2026 TOCLOCO Inc. All rights reserved.
4
4
  * https://latticegrid.dev
5
5
  */
@@ -52,12 +52,12 @@ Object.defineProperty(__exports,"frameBatched",{enumerable:true,get:function(){r
52
52
  Object.defineProperty(__exports,"settleDebounce",{enumerable:true,get:function(){return settleDebounce;}});
53
53
  Object.defineProperty(__exports,"whenIdle",{enumerable:true,get:function(){return whenIdle;}});
54
54
  Object.defineProperty(__exports,"uid",{enumerable:true,get:function(){return uid;}});
55
- const STAMPED_VERSION="1.67.0";
55
+ const STAMPED_VERSION="1.68.0";
56
56
  async function resolveVersion(){
57
57
  if(STAMPED_VERSION!=='0.0.0-source')return STAMPED_VERSION;
58
58
  return STAMPED_VERSION;
59
59
  }
60
- const VERSION="1.67.0";
60
+ const VERSION="1.68.0";
61
61
  const warned=new Set();
62
62
  const WARNED_LIMIT=2000;
63
63
  function rememberWarned(key){
@@ -1544,6 +1544,180 @@ grandTotals:()=>lastGrand,
1544
1544
  };
1545
1545
  }
1546
1546
  });
1547
+ __def("packages/core/src/model/rowkey.js",function(__exports,__req){
1548
+ 'use strict';
1549
+ Object.defineProperty(__exports,"KEY_DEPENDENT_FEATURES",{enumerable:true,get:function(){return KEY_DEPENDENT_FEATURES;}});
1550
+ Object.defineProperty(__exports,"compositeKey",{enumerable:true,get:function(){return compositeKey;}});
1551
+ Object.defineProperty(__exports,"createRowKey",{enumerable:true,get:function(){return createRowKey;}});
1552
+ Object.defineProperty(__exports,"warnMissingKeys",{enumerable:true,get:function(){return warnMissingKeys;}});
1553
+ Object.defineProperty(__exports,"groupPathKey",{enumerable:true,get:function(){return groupPathKey;}});
1554
+ Object.defineProperty(__exports,"splitPathKey",{enumerable:true,get:function(){return splitPathKey;}});
1555
+ const __m0=__req("packages/core/src/internal/util.js");
1556
+ const warnOnce=__m0["warnOnce"];
1557
+ const pathGetter=__m0["pathGetter"];
1558
+ const isFunction=__m0["isFunction"];
1559
+ const isBlank=__m0["isBlank"];
1560
+ const KEY_DEPENDENT_FEATURES=[
1561
+ 'changes (rows.apply / rows.queue)',
1562
+ 'streaming dedupe',
1563
+ 'selection persistence',
1564
+ 'remote reload',
1565
+ 'cell comments',
1566
+ ];
1567
+ const SEP='\u001f';
1568
+ function part(value){
1569
+ if(value===null)return'\u0000n';
1570
+ if(value===undefined)return'\u0000u';
1571
+ const t=typeof value;
1572
+ if(t==='string')return value;
1573
+ if(t==='number'||t==='bigint'||t==='boolean')return String(value);
1574
+ if(value instanceof Date)return`\u0000d${value.getTime()}`;
1575
+ try{
1576
+ return`\u0000o${JSON.stringify(value)}`;
1577
+ }catch{
1578
+ return'\u0000o?';
1579
+ }
1580
+ }
1581
+ function compositeKey(parts){
1582
+ if(parts.length===1)return part(parts[0]);
1583
+ let out='';
1584
+ for(let i=0;i<parts.length;i++){
1585
+ if(i)out+=SEP;
1586
+ out+=part(parts[i]);
1587
+ }
1588
+ return out;
1589
+ }
1590
+ function createRowKey(spec,opts={}){
1591
+ const warn=opts.warn!==false;
1592
+ if(isFunction(spec)){
1593
+ const fn=(spec);
1594
+ return{
1595
+ stable:true,
1596
+ fields:[],
1597
+ disabled:[],
1598
+ key(data,index){
1599
+ try{
1600
+ const value=fn(data);
1601
+ return Array.isArray(value)?compositeKey(value):part(value);
1602
+ }catch(err){
1603
+ warnOnce('rowKey.throw','rowKey function threw; falling back to index identity for the affected rows.',err);
1604
+ return`#${index??-1}`;
1605
+ }
1606
+ },
1607
+ keyEmpty(data){
1608
+ try{
1609
+ const value=fn(data);
1610
+ return Array.isArray(value)?value.length===0||value.some(isBlank):isBlank(value);
1611
+ }catch{
1612
+ return false;
1613
+ }
1614
+ },
1615
+ missingFields(){return[];},
1616
+ };
1617
+ }
1618
+ if(Array.isArray(spec)&&spec.length>0){
1619
+ const fields=spec.filter((f)=>typeof f==='string');
1620
+ const getters=fields.map((f)=>pathGetter(f));
1621
+ const n=getters.length;
1622
+ return{
1623
+ stable:true,
1624
+ fields,
1625
+ disabled:[],
1626
+ key(data){
1627
+ const parts=new Array(n);
1628
+ for(let i=0;i<n;i++)parts[i]=getters[i](data);
1629
+ return compositeKey(parts);
1630
+ },
1631
+ keyEmpty(data){
1632
+ for(let i=0;i<n;i++)if(isBlank(getters[i](data)))return true;
1633
+ return false;
1634
+ },
1635
+ missingFields(data){
1636
+ const out=[];
1637
+ for(let i=0;i<n;i++)if(isBlank(getters[i](data)))out.push(fields[i]);
1638
+ return out;
1639
+ },
1640
+ };
1641
+ }
1642
+ if(typeof spec==='string'&&spec.length>0){
1643
+ const get=pathGetter(spec);
1644
+ return{
1645
+ stable:true,
1646
+ fields:[spec],
1647
+ disabled:[],
1648
+ key(data){
1649
+ return part(get(data));
1650
+ },
1651
+ keyEmpty(data){
1652
+ return isBlank(get(data));
1653
+ },
1654
+ missingFields(data){
1655
+ return isBlank(get(data))?[spec]:[];
1656
+ },
1657
+ };
1658
+ }
1659
+ if(warn){
1660
+ warnOnce(
1661
+ 'rowKey.missing',
1662
+ `no rowKey configured, so rows are identified by object identity. This disables: ${KEY_DEPENDENT_FEATURES.join(', ')}. Set rowKey to a field name, an array of field names, or a function.`,
1663
+ );
1664
+ }
1665
+ return{
1666
+ stable:false,
1667
+ fields:[],
1668
+ disabled:KEY_DEPENDENT_FEATURES.slice(),
1669
+ key(data,index){
1670
+ if(data===null||typeof data!=='object'){
1671
+ return`#${index??0}:${String(data)}`;
1672
+ }
1673
+ let assigned=autoKeys.get(data);
1674
+ if(assigned===undefined){
1675
+ assigned=`#${autoKeySeq++}`;
1676
+ autoKeys.set(data,assigned);
1677
+ }
1678
+ return assigned;
1679
+ },
1680
+ };
1681
+ }
1682
+ const autoKeys=new WeakMap();
1683
+ let autoKeySeq=0;
1684
+ function warnMissingKeys(resolver,rows){
1685
+ if(!resolver||resolver.stable===false||!isFunction(resolver.keyEmpty))return;
1686
+ if(!Array.isArray(rows)||rows.length===0)return;
1687
+ let missing=0;
1688
+ let sampleFields=null;
1689
+ let sampleData;
1690
+ for(let i=0;i<rows.length;i++){
1691
+ const data=rows[i];
1692
+ if(!resolver.keyEmpty(data))continue;
1693
+ missing++;
1694
+ if(sampleFields===null){
1695
+ sampleFields=isFunction(resolver.missingFields)?resolver.missingFields(data):[];
1696
+ sampleData=data;
1697
+ }
1698
+ }
1699
+ if(missing===0)return;
1700
+ const dedupFields=resolver.fields.length?resolver.fields.join(','):'(function)';
1701
+ const named=sampleFields&&sampleFields.length
1702
+ ?sampleFields.join(', ')
1703
+ :(resolver.fields.length?resolver.fields.join(', '):'the rowKey function');
1704
+ const present=sampleData!==null&&typeof sampleData==='object'
1705
+ ?(Object.keys((sampleData)).join(', ')||'(no fields)')
1706
+ :String(sampleData);
1707
+ warnOnce(
1708
+ `rowKey.emptyValue:${dedupFields}`,
1709
+ `rowKey ${named} is missing on ${missing} of ${rows.length} rows; the first such row has: ${present}. `
1710
+ +'Rows without a key value collapse onto one key, so selection, edits and rows.apply updates land on '
1711
+ +'whichever row now shares it. Set rowKey to a field present on every row, or fix the source data.',
1712
+ );
1713
+ }
1714
+ function groupPathKey(path){
1715
+ return compositeKey(path);
1716
+ }
1717
+ function splitPathKey(key){
1718
+ return key.split(SEP);
1719
+ }
1720
+ });
1547
1721
  __def("packages/modules/data-router/devtools.js",function(__exports,__req){
1548
1722
  'use strict';
1549
1723
  Object.defineProperty(__exports,"mountRouterDevtools",{enumerable:true,get:function(){return mountRouterDevtools;}});
@@ -1629,8 +1803,10 @@ const warnOnce=__m0["warnOnce"];
1629
1803
  const __m1=__req("packages/core/src/source/pushdown.js");
1630
1804
  const planQuery=__m1["planQuery"];
1631
1805
  const capabilitiesOf=__m1["capabilitiesOf"];
1632
- const __m2=__req("packages/modules/data-router/devtools.js");
1633
- const mountRouterDevtools=__m2["mountRouterDevtools"];
1806
+ const __m2=__req("packages/core/src/model/rowkey.js");
1807
+ const compositeKey=__m2["compositeKey"];
1808
+ const __m3=__req("packages/modules/data-router/devtools.js");
1809
+ const mountRouterDevtools=__m3["mountRouterDevtools"];
1634
1810
  function resolver(spec,fallback){
1635
1811
  if(typeof spec==='function')return spec;
1636
1812
  if(typeof spec==='string')return(row)=>row[spec];
@@ -1683,6 +1859,8 @@ const maxLag=(Number.isFinite(spec.maxLag)&&spec.maxLag>=0)?Math.floor(Number(sp
1683
1859
  if(minInterval===0&&sample===1&&maxLag===null)return null;
1684
1860
  return{minInterval,sample,maxLag};
1685
1861
  }
1862
+ let routeSeq=0;
1863
+ function nextRouteId(){routeSeq+=1;return`r${routeSeq}`;}
1686
1864
  function grouper(groupBy){
1687
1865
  const specs=Array.isArray(groupBy)?groupBy:[groupBy];
1688
1866
  const parts=specs.map((s)=>({name:typeof s==='string'?s:null,get:resolver(s,()=>undefined)}));
@@ -1694,7 +1872,7 @@ const v=part.get(row);
1694
1872
  vals.push(v);
1695
1873
  if(part.name)fields[part.name]=v;
1696
1874
  }
1697
- return{key:vals.map((v)=>String(v)).join('\u0001'),fields};
1875
+ return{key:compositeKey(vals),fields};
1698
1876
  };
1699
1877
  }
1700
1878
  function aggregateOne(spec,rows){
@@ -1863,10 +2041,25 @@ return fallbackRoute?[fallbackRoute]:[];
1863
2041
  };
1864
2042
  const applyChange=(route,change)=>{
1865
2043
  if(change.add.length||change.update.length||change.remove.length){
1866
- route.sink(change);
2044
+ const result=route.sink(change);
2045
+ warnRejectedRemovals(route,result);
1867
2046
  }
1868
2047
  return{added:change.add.length,updated:change.update.length,removed:change.remove.length};
1869
2048
  };
2049
+ const warnRejectedRemovals=(route,result)=>{
2050
+ const rejected=(result)?.rejected;
2051
+ if(!Array.isArray(rejected)||!rejected.length)return;
2052
+ const removals=rejected.filter((r)=>r&&r.operation==='remove');
2053
+ if(!removals.length)return;
2054
+ const name=route.label||`route ${route.routeId}`;
2055
+ warnOnce(
2056
+ `data-router:remove-rejected:${route.routeId}`,
2057
+ `route "${name}" asked its target to remove ${removals.length} row(s) the target does not have`
2058
+ +` (for example ${JSON.stringify(String(removals[0].id))}). The rows are still on screen.`
2059
+ +' This is a key mismatch: the key the route derives for a row is not the key the grid derives'
2060
+ +' for it. Check that the route\'s `rowKey` names the same value as the grid\'s.',
2061
+ );
2062
+ };
1870
2063
  const passes=(route,row)=>{
1871
2064
  for(const link of links){
1872
2065
  if(link.to!==route.grid)continue;
@@ -1904,7 +2097,9 @@ shown=new Map(summaries.map((s)=>[s.gkey,s.row]));
1904
2097
  let rows=kept;
1905
2098
  if(route.sort)rows=rows.slice().sort(route.sort);
1906
2099
  shown=new Map();
1907
- for(const row of rows)shown.set(String(route.keyOf(row)),route.transform?route.transform(row):row);
2100
+ for(const row of rows){
2101
+ shown.set(compositeKey([route.keyOf(row)]),route.transform?route.transform(row):row);
2102
+ }
1908
2103
  }
1909
2104
  const add=[];
1910
2105
  const update=[];
@@ -2053,6 +2248,7 @@ return()=>{};
2053
2248
  };
2054
2249
  const makeRoute=(grid,match,o)=>({
2055
2250
  grid,
2251
+ routeId:nextRouteId(),
2056
2252
  sink:targetSink(grid),
2057
2253
  match,
2058
2254
  keyOf:resolver(assertRowKeySpec(o.rowKey,'routes'),defaultKeyOf),
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Lattice Grid 1.67.0, data-router module
2
+ * Lattice Grid 1.68.0, data-router module
3
3
  * Copyright (c) 2026 TOCLOCO Inc. All rights reserved.
4
4
  * https://latticegrid.dev
5
5
  */
@@ -54,12 +54,12 @@ Object.defineProperty(__exports,"frameBatched",{enumerable:true,get:function(){r
54
54
  Object.defineProperty(__exports,"settleDebounce",{enumerable:true,get:function(){return settleDebounce;}});
55
55
  Object.defineProperty(__exports,"whenIdle",{enumerable:true,get:function(){return whenIdle;}});
56
56
  Object.defineProperty(__exports,"uid",{enumerable:true,get:function(){return uid;}});
57
- const STAMPED_VERSION="1.67.0";
57
+ const STAMPED_VERSION="1.68.0";
58
58
  async function resolveVersion(){
59
59
  if(STAMPED_VERSION!=='0.0.0-source')return STAMPED_VERSION;
60
60
  return STAMPED_VERSION;
61
61
  }
62
- const VERSION="1.67.0";
62
+ const VERSION="1.68.0";
63
63
  const warned=new Set();
64
64
  const WARNED_LIMIT=2000;
65
65
  function rememberWarned(key){
@@ -1546,6 +1546,180 @@ grandTotals:()=>lastGrand,
1546
1546
  };
1547
1547
  }
1548
1548
  });
1549
+ __def("packages/core/src/model/rowkey.js",function(__exports,__req){
1550
+ 'use strict';
1551
+ Object.defineProperty(__exports,"KEY_DEPENDENT_FEATURES",{enumerable:true,get:function(){return KEY_DEPENDENT_FEATURES;}});
1552
+ Object.defineProperty(__exports,"compositeKey",{enumerable:true,get:function(){return compositeKey;}});
1553
+ Object.defineProperty(__exports,"createRowKey",{enumerable:true,get:function(){return createRowKey;}});
1554
+ Object.defineProperty(__exports,"warnMissingKeys",{enumerable:true,get:function(){return warnMissingKeys;}});
1555
+ Object.defineProperty(__exports,"groupPathKey",{enumerable:true,get:function(){return groupPathKey;}});
1556
+ Object.defineProperty(__exports,"splitPathKey",{enumerable:true,get:function(){return splitPathKey;}});
1557
+ const __m0=__req("packages/core/src/internal/util.js");
1558
+ const warnOnce=__m0["warnOnce"];
1559
+ const pathGetter=__m0["pathGetter"];
1560
+ const isFunction=__m0["isFunction"];
1561
+ const isBlank=__m0["isBlank"];
1562
+ const KEY_DEPENDENT_FEATURES=[
1563
+ 'changes (rows.apply / rows.queue)',
1564
+ 'streaming dedupe',
1565
+ 'selection persistence',
1566
+ 'remote reload',
1567
+ 'cell comments',
1568
+ ];
1569
+ const SEP='\u001f';
1570
+ function part(value){
1571
+ if(value===null)return'\u0000n';
1572
+ if(value===undefined)return'\u0000u';
1573
+ const t=typeof value;
1574
+ if(t==='string')return value;
1575
+ if(t==='number'||t==='bigint'||t==='boolean')return String(value);
1576
+ if(value instanceof Date)return`\u0000d${value.getTime()}`;
1577
+ try{
1578
+ return`\u0000o${JSON.stringify(value)}`;
1579
+ }catch{
1580
+ return'\u0000o?';
1581
+ }
1582
+ }
1583
+ function compositeKey(parts){
1584
+ if(parts.length===1)return part(parts[0]);
1585
+ let out='';
1586
+ for(let i=0;i<parts.length;i++){
1587
+ if(i)out+=SEP;
1588
+ out+=part(parts[i]);
1589
+ }
1590
+ return out;
1591
+ }
1592
+ function createRowKey(spec,opts={}){
1593
+ const warn=opts.warn!==false;
1594
+ if(isFunction(spec)){
1595
+ const fn=(spec);
1596
+ return{
1597
+ stable:true,
1598
+ fields:[],
1599
+ disabled:[],
1600
+ key(data,index){
1601
+ try{
1602
+ const value=fn(data);
1603
+ return Array.isArray(value)?compositeKey(value):part(value);
1604
+ }catch(err){
1605
+ warnOnce('rowKey.throw','rowKey function threw; falling back to index identity for the affected rows.',err);
1606
+ return`#${index??-1}`;
1607
+ }
1608
+ },
1609
+ keyEmpty(data){
1610
+ try{
1611
+ const value=fn(data);
1612
+ return Array.isArray(value)?value.length===0||value.some(isBlank):isBlank(value);
1613
+ }catch{
1614
+ return false;
1615
+ }
1616
+ },
1617
+ missingFields(){return[];},
1618
+ };
1619
+ }
1620
+ if(Array.isArray(spec)&&spec.length>0){
1621
+ const fields=spec.filter((f)=>typeof f==='string');
1622
+ const getters=fields.map((f)=>pathGetter(f));
1623
+ const n=getters.length;
1624
+ return{
1625
+ stable:true,
1626
+ fields,
1627
+ disabled:[],
1628
+ key(data){
1629
+ const parts=new Array(n);
1630
+ for(let i=0;i<n;i++)parts[i]=getters[i](data);
1631
+ return compositeKey(parts);
1632
+ },
1633
+ keyEmpty(data){
1634
+ for(let i=0;i<n;i++)if(isBlank(getters[i](data)))return true;
1635
+ return false;
1636
+ },
1637
+ missingFields(data){
1638
+ const out=[];
1639
+ for(let i=0;i<n;i++)if(isBlank(getters[i](data)))out.push(fields[i]);
1640
+ return out;
1641
+ },
1642
+ };
1643
+ }
1644
+ if(typeof spec==='string'&&spec.length>0){
1645
+ const get=pathGetter(spec);
1646
+ return{
1647
+ stable:true,
1648
+ fields:[spec],
1649
+ disabled:[],
1650
+ key(data){
1651
+ return part(get(data));
1652
+ },
1653
+ keyEmpty(data){
1654
+ return isBlank(get(data));
1655
+ },
1656
+ missingFields(data){
1657
+ return isBlank(get(data))?[spec]:[];
1658
+ },
1659
+ };
1660
+ }
1661
+ if(warn){
1662
+ warnOnce(
1663
+ 'rowKey.missing',
1664
+ `no rowKey configured, so rows are identified by object identity. This disables: ${KEY_DEPENDENT_FEATURES.join(', ')}. Set rowKey to a field name, an array of field names, or a function.`,
1665
+ );
1666
+ }
1667
+ return{
1668
+ stable:false,
1669
+ fields:[],
1670
+ disabled:KEY_DEPENDENT_FEATURES.slice(),
1671
+ key(data,index){
1672
+ if(data===null||typeof data!=='object'){
1673
+ return`#${index??0}:${String(data)}`;
1674
+ }
1675
+ let assigned=autoKeys.get(data);
1676
+ if(assigned===undefined){
1677
+ assigned=`#${autoKeySeq++}`;
1678
+ autoKeys.set(data,assigned);
1679
+ }
1680
+ return assigned;
1681
+ },
1682
+ };
1683
+ }
1684
+ const autoKeys=new WeakMap();
1685
+ let autoKeySeq=0;
1686
+ function warnMissingKeys(resolver,rows){
1687
+ if(!resolver||resolver.stable===false||!isFunction(resolver.keyEmpty))return;
1688
+ if(!Array.isArray(rows)||rows.length===0)return;
1689
+ let missing=0;
1690
+ let sampleFields=null;
1691
+ let sampleData;
1692
+ for(let i=0;i<rows.length;i++){
1693
+ const data=rows[i];
1694
+ if(!resolver.keyEmpty(data))continue;
1695
+ missing++;
1696
+ if(sampleFields===null){
1697
+ sampleFields=isFunction(resolver.missingFields)?resolver.missingFields(data):[];
1698
+ sampleData=data;
1699
+ }
1700
+ }
1701
+ if(missing===0)return;
1702
+ const dedupFields=resolver.fields.length?resolver.fields.join(','):'(function)';
1703
+ const named=sampleFields&&sampleFields.length
1704
+ ?sampleFields.join(', ')
1705
+ :(resolver.fields.length?resolver.fields.join(', '):'the rowKey function');
1706
+ const present=sampleData!==null&&typeof sampleData==='object'
1707
+ ?(Object.keys((sampleData)).join(', ')||'(no fields)')
1708
+ :String(sampleData);
1709
+ warnOnce(
1710
+ `rowKey.emptyValue:${dedupFields}`,
1711
+ `rowKey ${named} is missing on ${missing} of ${rows.length} rows; the first such row has: ${present}. `
1712
+ +'Rows without a key value collapse onto one key, so selection, edits and rows.apply updates land on '
1713
+ +'whichever row now shares it. Set rowKey to a field present on every row, or fix the source data.',
1714
+ );
1715
+ }
1716
+ function groupPathKey(path){
1717
+ return compositeKey(path);
1718
+ }
1719
+ function splitPathKey(key){
1720
+ return key.split(SEP);
1721
+ }
1722
+ });
1549
1723
  __def("packages/modules/data-router/devtools.js",function(__exports,__req){
1550
1724
  'use strict';
1551
1725
  Object.defineProperty(__exports,"mountRouterDevtools",{enumerable:true,get:function(){return mountRouterDevtools;}});
@@ -1631,8 +1805,10 @@ const warnOnce=__m0["warnOnce"];
1631
1805
  const __m1=__req("packages/core/src/source/pushdown.js");
1632
1806
  const planQuery=__m1["planQuery"];
1633
1807
  const capabilitiesOf=__m1["capabilitiesOf"];
1634
- const __m2=__req("packages/modules/data-router/devtools.js");
1635
- const mountRouterDevtools=__m2["mountRouterDevtools"];
1808
+ const __m2=__req("packages/core/src/model/rowkey.js");
1809
+ const compositeKey=__m2["compositeKey"];
1810
+ const __m3=__req("packages/modules/data-router/devtools.js");
1811
+ const mountRouterDevtools=__m3["mountRouterDevtools"];
1636
1812
  function resolver(spec,fallback){
1637
1813
  if(typeof spec==='function')return spec;
1638
1814
  if(typeof spec==='string')return(row)=>row[spec];
@@ -1685,6 +1861,8 @@ const maxLag=(Number.isFinite(spec.maxLag)&&spec.maxLag>=0)?Math.floor(Number(sp
1685
1861
  if(minInterval===0&&sample===1&&maxLag===null)return null;
1686
1862
  return{minInterval,sample,maxLag};
1687
1863
  }
1864
+ let routeSeq=0;
1865
+ function nextRouteId(){routeSeq+=1;return`r${routeSeq}`;}
1688
1866
  function grouper(groupBy){
1689
1867
  const specs=Array.isArray(groupBy)?groupBy:[groupBy];
1690
1868
  const parts=specs.map((s)=>({name:typeof s==='string'?s:null,get:resolver(s,()=>undefined)}));
@@ -1696,7 +1874,7 @@ const v=part.get(row);
1696
1874
  vals.push(v);
1697
1875
  if(part.name)fields[part.name]=v;
1698
1876
  }
1699
- return{key:vals.map((v)=>String(v)).join('\u0001'),fields};
1877
+ return{key:compositeKey(vals),fields};
1700
1878
  };
1701
1879
  }
1702
1880
  function aggregateOne(spec,rows){
@@ -1865,10 +2043,25 @@ return fallbackRoute?[fallbackRoute]:[];
1865
2043
  };
1866
2044
  const applyChange=(route,change)=>{
1867
2045
  if(change.add.length||change.update.length||change.remove.length){
1868
- route.sink(change);
2046
+ const result=route.sink(change);
2047
+ warnRejectedRemovals(route,result);
1869
2048
  }
1870
2049
  return{added:change.add.length,updated:change.update.length,removed:change.remove.length};
1871
2050
  };
2051
+ const warnRejectedRemovals=(route,result)=>{
2052
+ const rejected=(result)?.rejected;
2053
+ if(!Array.isArray(rejected)||!rejected.length)return;
2054
+ const removals=rejected.filter((r)=>r&&r.operation==='remove');
2055
+ if(!removals.length)return;
2056
+ const name=route.label||`route ${route.routeId}`;
2057
+ warnOnce(
2058
+ `data-router:remove-rejected:${route.routeId}`,
2059
+ `route "${name}" asked its target to remove ${removals.length} row(s) the target does not have`
2060
+ +` (for example ${JSON.stringify(String(removals[0].id))}). The rows are still on screen.`
2061
+ +' This is a key mismatch: the key the route derives for a row is not the key the grid derives'
2062
+ +' for it. Check that the route\'s `rowKey` names the same value as the grid\'s.',
2063
+ );
2064
+ };
1872
2065
  const passes=(route,row)=>{
1873
2066
  for(const link of links){
1874
2067
  if(link.to!==route.grid)continue;
@@ -1906,7 +2099,9 @@ shown=new Map(summaries.map((s)=>[s.gkey,s.row]));
1906
2099
  let rows=kept;
1907
2100
  if(route.sort)rows=rows.slice().sort(route.sort);
1908
2101
  shown=new Map();
1909
- for(const row of rows)shown.set(String(route.keyOf(row)),route.transform?route.transform(row):row);
2102
+ for(const row of rows){
2103
+ shown.set(compositeKey([route.keyOf(row)]),route.transform?route.transform(row):row);
2104
+ }
1910
2105
  }
1911
2106
  const add=[];
1912
2107
  const update=[];
@@ -2055,6 +2250,7 @@ return()=>{};
2055
2250
  };
2056
2251
  const makeRoute=(grid,match,o)=>({
2057
2252
  grid,
2253
+ routeId:nextRouteId(),
2058
2254
  sink:targetSink(grid),
2059
2255
  match,
2060
2256
  keyOf:resolver(assertRowKeySpec(o.rowKey,'routes'),defaultKeyOf),