@marktiderman/genesis-ui 2.10.1 → 2.12.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 (32) hide show
  1. package/SKILL.md +59 -1
  2. package/dist/AppShell-DpQdcLE-.d.ts +347 -0
  3. package/dist/{chunk-C7PQ54JI.js → chunk-3TWCZYZY.js} +43 -13
  4. package/dist/chunk-3TWCZYZY.js.map +1 -0
  5. package/dist/{chunk-WGMEVX3Y.js → chunk-KC43CNMA.js} +2 -2
  6. package/dist/{chunk-WGMEVX3Y.js.map → chunk-KC43CNMA.js.map} +1 -1
  7. package/dist/{chunk-UYI3GLFJ.js → chunk-SZMXNC5Q.js} +722 -159
  8. package/dist/chunk-SZMXNC5Q.js.map +1 -0
  9. package/dist/{chunk-OITWCIG2.js → chunk-XGG5RUDE.js} +3 -3
  10. package/dist/{chunk-OITWCIG2.js.map → chunk-XGG5RUDE.js.map} +1 -1
  11. package/dist/components/data/index.d.ts +5 -5
  12. package/dist/components/data/index.js +32 -6
  13. package/dist/components/data/index.js.map +1 -1
  14. package/dist/components/layout/index.d.ts +2 -2
  15. package/dist/components/layout/index.js +3 -2
  16. package/dist/components/rich-text/rich-text-editor.js +1 -1
  17. package/dist/hooks/index.d.ts +2 -2
  18. package/dist/hooks/index.js +3 -3
  19. package/dist/hooks/use-data-filters.d.ts +1 -1
  20. package/dist/hooks/use-data-filters.js +2 -2
  21. package/dist/hooks/use-resource-url-state.d.ts +1 -1
  22. package/dist/index.d.ts +1 -1
  23. package/dist/index.js +2 -2
  24. package/dist/{navigation-Bha0R3Fu.d.ts → navigation-By1DrzaM.d.ts} +24 -0
  25. package/dist/router/react-router.d.ts +1 -1
  26. package/dist/router/tanstack-router.d.ts +1 -1
  27. package/dist/router/tanstack-router.js +1 -1
  28. package/dist/{use-resource-table-DCVf_lEG.d.ts → use-resource-table-DrTkD5O1.d.ts} +32 -3
  29. package/package.json +4 -3
  30. package/dist/AppShell-BVr4V0UK.d.ts +0 -174
  31. package/dist/chunk-C7PQ54JI.js.map +0 -1
  32. package/dist/chunk-UYI3GLFJ.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/data/undo-toast.ts","../src/components/data/use-resource-table.ts"],"names":[],"mappings":";;;;;;;;;;AAGA,IAAM,IAAA,GAA8C;AAAA,EAClD,MAAA,EAAQ,UAAA;AAAA,EACR,MAAA,EAAQ,QAAA;AAAA,EACR,MAAA,EAAQ;AACV,CAAA;AAOO,SAAS,cAAc,KAAA,EAA4B;AACxD,EAAA,KAAA,CAAM,IAAA,CAAK,KAAA,CAAM,IAAI,CAAA,EAAG;AAAA,IACtB,UAAU,KAAA,CAAM,OAAA;AAAA,IAChB,MAAA,EAAQ;AAAA,MACN,KAAA,EAAO,MAAA;AAAA,MACP,SAAS,MAAM;AACb,QAAA,KAAK,KAAA,CAAM,IAAA,EAAK,CAAE,IAAA,CAAK,CAAC,MAAA,KAAW;AAEjC,UAAA,IAAI,CAAC,MAAA,IAAU,KAAA,CAAM,QAAA,KAAa,OAAA,EAAS;AACzC,YAAA,KAAA,CAAM,4CAA4C,CAAA;AAAA,UACpD;AAAA,QACF,CAAC,CAAA;AAAA,MACH;AAAA;AACF,GACD,CAAA;AACH;AAGO,SAAS,oBAAoB,KAAA,EAAoB;AACtD,EAAA,KAAA,CAAM,KAAA,CAAM,KAAA,CAAM,OAAA,IAAW,gCAAgC,CAAA;AAC/D;AAOO,SAAS,gBAAA,CACd,iBACA,YAAA,EAC8G;AAC9G,EAAA,MAAM,IAAA,GAAO,eAAA,EAAiB,YAAA,IAAgB,YAAA,IAAgB,aAAA;AAC9D,EAAA,OAAO;AAAA,IACL,YAAA,EAAc,IAAA;AAAA,IACd,UAAA,EAAY,iBAAiB,UAAA,IAAc,aAAA;AAAA,IAC3C,OAAA,EAAS,eAAA,EAAiB,OAAA,KAAY,IAAA,KAAS,gBAAgB,MAAA,GAAY,mBAAA;AAAA,GAC7E;AACF;ACXO,SAAS,sBAEd,KAAA,EAA6B;AAC7B,EAAA,MAAM;AAAA,IACJ,QAAA,EAAU,YAAA;AAAA,IACV,IAAA,EAAM,QAAA;AAAA,IACN,KAAA,EAAO,SAAA;AAAA,IACP,UAAA,GAAa,QAAA;AAAA,IACb,cAAA,GAAiB,GAAA;AAAA,IACjB,KAAA;AAAA,IACA,QAAA;AAAA,IACA,IAAA;AAAA,IACA,OAAA,EAAS,WAAA;AAAA,IACT,MAAA,EAAQ,UAAA;AAAA,IACR,MAAA,GAAS,OAAA;AAAA,IACT,WAAA,GAAc,IAAA;AAAA,IACd,UAAA,EAAY,cAAA;AAAA,IACZ,aAAA,EAAe,iBAAA;AAAA,IACf,QAAA;AAAA,IACA,WAAA;AAAA,IACA,YAAA,EAAc,gBAAA;AAAA,IACd,YAAA;AAAA,IACA,YAAA;AAAA,IACA,YAAA;AAAA,IACA,iBAAA;AAAA,IACA,cAAA;AAAA,IACA,eAAA;AAAA,IACA,OAAA,EAAS,WAAA;AAAA,IACT,IAAA,EAAM,QAAA;AAAA,IACN,OAAA,EAAS,WAAA;AAAA,IACT,YAAA;AAAA,IACA,eAAA;AAAA,IACA,YAAA;AAAA,IACA,cAAA;AAAA,IACA,OAAA,EAAS,WAAA;AAAA,IACT,KAAA,EAAO,SAAA;AAAA,IACP,YAAA;AAAA,IACA,OAAA,EAAS,WAAA;AAAA,IACT,UAAA;AAAA,IACA,UAAA;AAAA,IACA,UAAA;AAAA,IACA,YAAA;AAAA,IACA,YAAA;AAAA,IACA,gBAAA;AAAA,IACA,mBAAA;AAAA,IACA,gBAAA;AAAA,IACA,SAAA;AAAA,IACA,YAAA;AAAA,IACA,iBAAA;AAAA,IACA,eAAA;AAAA,IACA,QAAA;AAAA,IACA,MAAA;AAAA,IACA,QAAA;AAAA,IACA,GAAA;AAAA,IACA,WAAA;AAAA,IACA,WAAA,GAAc,KAAA;AAAA,IACd,OAAA;AAAA,IACA,SAAA;AAAA,IACA,WAAA;AAAA,IACA,aAAA;AAAA,IACA,SAAA;AAAA,IACA,gBAAA;AAAA,IACA,WAAA;AAAA,IACA,SAAA;AAAA,IACA,UAAA;AAAA,IACA,UAAA,EAAY,cAAA;AAAA,IACZ,QAAA;AAAA,IACA,SAAA;AAAA,IACA,UAAA,EAAY,cAAA;AAAA,IACZ,YAAA,EAAc,gBAAA;AAAA,IACd,WAAA;AAAA,IACA,UAAA,EAAY,cAAA;AAAA,IACZ,eAAA,GAAkB,KAAA;AAAA,IAClB,WAAA,EAAa,eAAA;AAAA,IACb,QAAA,EAAU,YAAA;AAAA,IACV,kBAAA,GAAqB,IAAA;AAAA,IACrB,YAAA;AAAA,IACA,OAAA;AAAA,IACA,UAAA;AAAA,IACA,SAAA;AAAA,IACA,YAAA;AAAA,IACA,gBAAA;AAAA,IACA,QAAQ,UAAA,GAAa,MAAA;AAAA,IACrB,eAAA;AAAA,IACA,QAAA,EAAU,YAAA;AAAA,IACV,WAAA,GAAc,OAAA;AAAA,IACd,UAAA,GAAa,eAAA;AAAA,IACb,eAAA,EAAiB,mBAAA;AAAA,IACjB,KAAA;AAAA,IACA,SAAA;AAAA,IACA;AAAA,GACF,GAAI,KAAA;AAGJ,EAAA,MAAM,YAAA,GAAe,CAAC,CAAC,YAAA;AAWvB,EAAA,MAAM,oBAAA,GAAuB,gBAAgB,UAAA,KAAe,QAAA;AAI5D,EAAA,MAAM,GAAA,GAAM,mBAAA;AAAA,IACV,eACI,iBAAA,IAAqB,YAAA,GACnB,EAAE,YAAA,EAAc,YAAA,KAChB,YAAA,GACF;AAAA,GACN;AAEA,EAAA,MAAM,CAAC,OAAO,CAAA,GAAI,QAAA,CAAS,MAAM;AAC/B,IAAA,IAAI,CAAC,KAAK,OAAO,IAAA;AAGjB,IAAA,MAAM,WACJ,CAAC,GAAA,CAAI,QAAQ,CAAC,WAAA,GACV,OACA,WAAA,CAAY,IAAA;AAAA,MAAK,CAAC,GAAA,KAChB,OAAO,GAAA,KAAQ,WACX,GAAA,KAAQ,GAAA,CAAI,IAAA,CAAM,KAAA,GAClB,IAAI,GAAA,KAAQ,GAAA,CAAI,IAAA,CAAM,KAAA,IAAS,IAAI,QAAA,KAAa;AAAA,KACtD;AACN,IAAA,OAAO,EAAE,CAAA,EAAG,GAAA,CAAI,CAAA,EAAG,IAAA,EAAM,QAAA,GAAW,GAAA,CAAI,IAAA,GAAO,IAAA,EAAM,IAAA,EAAM,GAAA,CAAI,IAAA,EAAK;AAAA,EACtE,CAAC,CAAA;AAED,EAAA,MAAM,OAAA,GAAU,MAAA,KAAW,OAAA,IAAW,MAAA,KAAW,UAAU,GAAA,GAAM,MAAA;AACjE,EAAA,MAAM,UAAA,GAAa,OAAA,EAAS,IAAA,GACxB,CAAA,EAAG,OAAA,CAAQ,IAAA,CAAK,KAAK,CAAA,CAAA,EAAI,OAAA,CAAQ,IAAA,CAAK,KAAK,CAAA,CAAA,GAC3C,EAAA;AAEJ,EAAA,MAAM,kBAAA,GACJ,oBAAA,IACA,QAAA,KAAa,MAAA,IACb,WAAA,KAAgB,MAAA,IAChB,YAAA,KAAiB,MAAA,IACjB,eAAA,KAAoB,MAAA,IACpB,YAAA,KAAiB,MAAA,IACjB,cAAA,KAAmB,MAAA;AAErB,EAAA,MAAM,eAAA,GACJ,uBACA,YAAA,IACA,KAAA,CAAM,aAAY,CAAE,OAAA,CAAQ,QAAQ,GAAG,CAAA;AACzC,EAAA,MAAM,EAAE,QAAA,EAAU,aAAA,EAAc,GAAI,gBAAgB,eAAe,CAAA;AAInE,EAAA,MAAM,kBAAA,GAAqB,iBAAiB,YAAA,IAAgB,YAAA;AAO5D,EAAA,MAAM,YAAA,GAAe,WAAA;AAAA,IACnB,YAAA,IAAgB,UAAA;AAAA,IAChB,YAAA,GACI;AAAA,MACE,GAAG,eAAA;AAAA;AAAA;AAAA;AAAA,MAIH,gBACE,eAAA,EAAiB,cAAA,KAChB,oBAAA,GACI,WAAA,IAAe,SAAS,QAAA,GACzB,cAAA,CAAA;AAAA,MACN,YAAA,EAAc,oBAAA,GACV,kBAAA,GACA,eAAA,EAAiB,YAAA;AAAA;AAAA;AAAA,MAGrB,gBAAA,EACE,iBAAiB,gBAAA,IAAoB,oBAAA;AAAA;AAAA;AAAA,MAGvC,GAAI,wBAAwB,OAAA,GACxB;AAAA,QACE,eAAe,OAAA,CAAQ,CAAA;AAAA,QACvB,GAAI,QAAQ,IAAA,GAAO,EAAE,aAAa,OAAA,CAAQ,IAAA,KAAS,EAAC;AAAA,QACpD,GAAI,QAAQ,IAAA,GAAO,EAAE,aAAa,OAAA,CAAQ,IAAA,KAAS;AAAC,UAEtD,EAAC;AAAA,MACL,GAAG,gBAAA,CAAiB,eAAA,EAAiB,gBAAgB;AAAA,KACvD,GACA,EAAE,OAAA,EAAS,KAAA;AAAM,GACvB;AAGA,EAAA,MAAM,iBAAA,GAAoB,uBACrB,YAAA,CAAa,MAAA,CAAO,YAAY,OAAA,IAAW,QAAA,CAAS,QAAA,GACpD,WAAA,IAAe,QAAA,CAAS,QAAA;AAG7B,EAAA,MAAM,WAAA,GAAmB,eACpB,YAAA,CAAa,IAAA,CAAK,MAAM,IAAA,IAAQ,EAAC,GACjC,QAAA,IAAY,EAAC;AAClB,EAAA,MAAM,eAAuB,YAAA,GACxB,YAAA,CAAa,KAAK,IAAA,EAAM,KAAA,IAAS,IACjC,SAAA,IAAa,CAAA;AAIlB,EAAA,MAAM,SAAA,GAAY,YAAA,GACd,YAAA,CAAa,IAAA,CAAK,YACjB,WAAA,IAAe,KAAA;AACpB,EAAA,MAAM,QAAA,GAAW,YAAA,GACb,YAAA,CAAa,IAAA,CAAK,UACjB,SAAA,IAAa,KAAA;AAGlB,EAAA,MAAM,OAAO,eAAA,CAAmB;AAAA,IAC9B,QAAA,EAAU,YAAA;AAAA,IACV,IAAA,EAAM,WAAA;AAAA,IACN,KAAA,EAAO,YAAA;AAAA,IACP,OAAA,EAAS,WAAA;AAAA,IACT,YAAA;AAAA,IACA,YAAA;AAAA,IACA,gBACE,cAAA,KACC,OAAA,KAAY,OAAA,CAAQ,CAAA,IAAK,QAAQ,IAAA,CAAA,GAC9B;AAAA,MACE,GAAI,OAAA,CAAQ,CAAA,GACR,CAAC,EAAE,KAAA,EAAO,YAAA,EAAc,QAAA,EAAU,UAAA,EAAqB,KAAA,EAAO,OAAA,CAAQ,CAAA,EAAG,IACzE,EAAC;AAAA,MACL,GAAI,OAAA,CAAQ,IAAA,GACR,CAAC,EAAE,KAAA,EAAO,UAAA,EAAY,QAAA,EAAU,IAAA,EAAe,KAAA,EAAO,UAAA,EAAY,IAClE;AAAC,KACP,GACA,MAAA,CAAA;AAAA,IACN,eAAA;AAAA,IACA,WAAA;AAAA;AAAA;AAAA,IAGA,OAAA,EAAS,eAAA;AAAA,IACT,MAAA;AAAA,IACA,UAAA,EAAY,cAAA;AAAA,IACZ,aAAA,EAAe,iBAAA;AAAA,IACf,UAAA,EAAY;AAAA,GACb,CAAA;AAOD,EAAA,MAAM;AAAA,IACJ,SAAA,EAAW,iBAAA;AAAA,IACX,OAAA,EAAS,eAAA;AAAA,IACT,UAAA,EAAY;AAAA,GACd,GAAI,YAAA;AAEJ,EAAA,MAAM,kBAAkB,MAAA,CAAO,oBAAA,GAAwB,OAAA,EAAS,CAAA,IAAK,KAAM,EAAE,CAAA;AAC7E,EAAA,MAAM,kBAAA,GAAqB,OAAO,KAAK,CAAA;AACvC,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,oBAAA,EAAsB;AAC3B,IAAA,MAAM,QAAA,GAAW,CAAC,kBAAA,CAAmB,OAAA;AACrC,IAAA,kBAAA,CAAmB,OAAA,GAAU,IAAA;AAC7B,IAAA,IAAI,IAAA,CAAK,MAAA,KAAW,eAAA,CAAgB,OAAA,EAAS;AAC7C,IAAA,MAAM,OAAO,MAAM;AACjB,MAAA,eAAA,CAAgB,UAAU,IAAA,CAAK,MAAA;AAC/B,MAAA,iBAAA,CAAkB,KAAK,MAAM,CAAA;AAAA,IAC/B,CAAA;AAKA,IAAA,IAAI,QAAA,IAAY,IAAA,CAAK,MAAA,KAAW,EAAA,EAAI;AAClC,MAAA,IAAA,EAAK;AACL,MAAA;AAAA,IACF;AACA,IAAA,MAAM,KAAA,GAAQ,UAAA,CAAW,IAAA,EAAM,GAAG,CAAA;AAClC,IAAA,OAAO,MAAM,aAAa,KAAK,CAAA;AAAA,EACjC,GAAG,CAAC,oBAAA,EAAsB,IAAA,CAAK,MAAA,EAAQ,iBAAiB,CAAC,CAAA;AAEzD,EAAA,MAAM,cAAc,eAAA,EAAiB,WAAA;AACrC,EAAA,MAAM,aAAA,GAAgB,MAAA,CAAe,oBAAA,GAAuB,UAAA,GAAa,EAAE,CAAA;AAC3E,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,oBAAA,EAAsB;AAC3B,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,IAAA,GAAO,CAAA,EAAG,IAAA,CAAK,IAAA,CAAK,KAAK,CAAA,CAAA,EAAI,IAAA,CAAK,IAAA,CAAK,KAAK,CAAA,CAAA,GAAK,EAAA;AAClE,IAAA,IAAI,GAAA,KAAQ,cAAc,OAAA,EAAS;AACnC,IAAA,aAAA,CAAc,OAAA,GAAU,GAAA;AAGxB,IAAA,eAAA,CAAgB,IAAA,CAAK,QAAQ,WAAW,CAAA;AAAA,EAC1C,GAAG,CAAC,oBAAA,EAAsB,KAAK,IAAA,EAAM,WAAA,EAAa,eAAe,CAAC,CAAA;AAElE,EAAA,MAAM,cAAc,YAAA,GAChB,OAAO,iBAAiB,QAAA,GACtB,YAAA,GACA,aAAa,KAAA,GACf,MAAA;AACJ,EAAA,MAAM,iBAAiB,eAAA,EAAiB,cAAA;AACxC,EAAA,MAAM,eAAA,GAAkB,OAAe,EAAE,CAAA;AACzC,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,oBAAA,IAAwB,CAAC,WAAA,EAAa;AAI3C,IAAA,MAAM,GAAA,GAAM,KAAK,SAAA,CAAU,CAAC,KAAK,WAAA,EAAa,cAAA,IAAkB,IAAI,CAAC,CAAA;AACrE,IAAA,IAAI,GAAA,KAAQ,gBAAgB,OAAA,EAAS;AACrC,IAAA,eAAA,CAAgB,OAAA,GAAU,GAAA;AAC1B,IAAA,kBAAA,CAAmB;AAAA,MACjB,GAAI,kBAAkB,EAAC;AAAA,MACvB,GAAI,IAAA,CAAK,WAAA,CAAY,MAAA,GAAS,CAAA,GAC1B,CAAC,EAAE,KAAA,EAAO,WAAA,EAAa,QAAA,EAAU,MAAe,KAAA,EAAO,IAAA,CAAK,WAAA,EAAa,IACzE;AAAC,KACN,CAAA;AAAA,EACH,CAAA,EAAG;AAAA,IACD,oBAAA;AAAA,IACA,WAAA;AAAA,IACA,IAAA,CAAK,WAAA;AAAA,IACL,cAAA;AAAA,IACA;AAAA,GACD,CAAA;AAGD,EAAA,MAAM,eAAA,GACJ,gBACA,CAAC,oBAAA,IACD,CAAC,SAAA,IACD,CAAC,QAAA,IACD,YAAA,GAAe,WAAA,CAAY,MAAA;AAC7B,EAAA,MAAM,kBAAA,GAAqB,OAAO,KAAK,CAAA;AACvC,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,eAAA,IAAmB,kBAAA,CAAmB,OAAA,EAAS;AACpD,IAAA,kBAAA,CAAmB,OAAA,GAAU,IAAA;AAC7B,IAAA,OAAA,CAAQ,IAAA;AAAA,MACN,kBAAkB,YAAY,CAAA,MAAA,EAAS,YAAY,CAAA,eAAA,EAAkB,YAAY,MAAM,CAAA,iLAAA;AAAA,KAGzF;AAAA,EACF,GAAG,CAAC,eAAA,EAAiB,cAAc,YAAA,EAAc,WAAA,CAAY,MAAM,CAAC,CAAA;AAEpE,EAAA,MAAM,OAAA,GAA8B,QAAQ,MAAM;AAChD,IAAA,IAAI,YAAA,EAAc;AAChB,MAAA,OAAO;AAAA,QACL,QAAQ,YAAA,CAAa,MAAA;AAAA,QACrB,QAAQ,YAAA,CAAa,MAAA;AAAA,QACrB,OAAA,EAAS,MAAM,YAAA,CAAa,IAAA,CAAK,OAAA;AAAQ,OAC3C;AAAA,IACF;AACA,IAAA,OAAO;AAAA,MACL,QAAQ,YAAY;AAClB,QAAA,MAAM,IAAI,KAAA;AAAA,UACR;AAAA,SACF;AAAA,MACF,CAAA;AAAA,MACA,QAAQ,YAAY;AAClB,QAAA,MAAM,IAAI,KAAA;AAAA,UACR;AAAA,SACF;AAAA,MACF,CAAA;AAAA,MACA,SAAS,MAAM;AAAA,MAEf;AAAA,KACF;AAAA,EACF,CAAA,EAAG;AAAA,IACD,YAAA;AAAA,IACA,YAAA,CAAa,MAAA;AAAA,IACb,YAAA,CAAa,MAAA;AAAA,IACb,YAAA,CAAa;AAAA,GACd,CAAA;AAGD,EAAA,MAAM,KAAA,GAAQ,WAAA;AAAA,IACZ,CAAC,SACC,UAAA,GAAa,UAAA,CAAW,IAAI,CAAA,GAAI,MAAA,CAAQ,IAAA,CAAiC,EAAA,IAAM,EAAE,CAAA;AAAA,IACnF,CAAC,UAAU;AAAA,GACb;AAcA,EAAA,MAAM,cAAc,IAAA,CAAK,YAAA,GAAe,KAAA,CAAM,IAAA,CAAK,YAAY,CAAA,GAAI,IAAA;AACnE,EAAA,MAAM,WAAA,GAAc,OAAA,GAAU,OAAA,CAAQ,QAAA,GAAW,WAAA;AACjD,EAAA,MAAM,WACJ,IAAA,CAAK,YAAA,IAAgB,WAAA,KAAgB,WAAA,GAAc,KAAK,YAAA,GAAe,IAAA;AACzE,EAAA,MAAM,aAAA,GAA0B,CAAC,WAAA,GAC7B,QAAA,GACC,WAAA,CAAY,IAAA,CAAK,CAAC,GAAA,KAAQ,KAAA,CAAM,GAAG,CAAA,KAAM,WAAW,CAAA,IAAK,QAAA;AAG9D,EAAA,MAAM,QAAA,GAAW,OAAA,IAAW,WAAA,IAAe,CAAC,gBAAgB,WAAA,GAAc,IAAA;AAC1E,EAAA,MAAM,MAAA,GAAS,MAAA,CAAuB,YAAA,IAAgB,UAAA,EAAY,QAAA,EAAU;AAAA,IAC1E,OAAA,EAAS,YAAA,IAAgB,CAAC,CAAC;AAAA,GAC5B,CAAA;AACD,EAAA,MAAM,eACJ,aAAA,KAAkB,QAAA,IAAY,MAAA,CAAO,IAAA,GAAQ,OAAO,IAAA,GAAa,IAAA,CAAA;AAInE,EAAA,MAAM,WAAA,GACJ,CAAC,CAAC,QAAA,IACF,CAAC,YAAA,IACD,CAAC,SAAA,KACA,YAAA,GAAe,MAAA,CAAO,OAAA,GAAU,CAAC,kBAAA,CAAA;AACpC,EAAA,MAAM,UAAA,GAAa,OAAA,GAAU,YAAA,KAAiB,IAAA,IAAQ,cAAc,IAAA,CAAK,UAAA;AAGzE,EAAA,MAAM,CAAC,WAAA,EAAa,cAAc,IAAI,QAAA,iBAAsB,IAAI,KAAK,CAAA;AAErE,EAAA,MAAM,kBAAA,GAAqB,WAAA,CAAY,CAAC,EAAA,KAAe;AACrD,IAAA,cAAA,CAAe,CAAC,IAAA,KAAS;AACvB,MAAA,MAAM,IAAA,GAAO,IAAI,GAAA,CAAI,IAAI,CAAA;AACzB,MAAA,IAAI,KAAK,GAAA,CAAI,EAAE,CAAA,EAAG,IAAA,CAAK,OAAO,EAAE,CAAA;AAAA,WAC3B,IAAA,CAAK,IAAI,EAAE,CAAA;AAChB,MAAA,OAAO,IAAA;AAAA,IACT,CAAC,CAAA;AAAA,EACH,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,eAAA,GAAkB,YAAY,MAAM;AACxC,IAAA,cAAA,CAAe,CAAC,IAAA,KAAS;AACvB,MAAA,IAAI,KAAK,IAAA,KAAS,IAAA,CAAK,KAAK,MAAA,EAAQ,2BAAW,GAAA,EAAI;AACnD,MAAA,OAAO,IAAI,GAAA,CAAI,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,KAAK,CAAC,CAAA;AAAA,IACrC,CAAC,CAAA;AAAA,EACH,CAAA,EAAG,CAAC,IAAA,CAAK,IAAA,EAAM,KAAK,CAAC,CAAA;AAErB,EAAA,MAAM,oBAAA,GAAuB,YAAY,MAAM;AAC7C,IAAA,cAAA,iBAAe,IAAI,KAAK,CAAA;AAAA,EAC1B,CAAA,EAAG,EAAE,CAAA;AAGL,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAI,SAAS,KAAK,CAAA;AAC9C,EAAA,MAAM,CAAC,UAAA,EAAY,aAAa,CAAA,GAAI,SAA4B,QAAQ,CAAA;AACxE,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAI,SAAmB,IAAI,CAAA;AAGvD,EAAA,MAAM,gBAAA,GAAmB,WAAA,IAAe,CAAC,QAAA,IAAY,YAAA;AACrD,EAAA,MAAM,cAAA,GAAiB,SAAA,IAAa,CAAC,MAAA,IAAU,YAAA;AAE/C,EAAA,MAAM,YAAA,GAAe,YAAY,MAAM;AACrC,IAAA,IAAI,gBAAA,EAAkB;AACpB,MAAA,aAAA,CAAc,QAAQ,CAAA;AACtB,MAAA,WAAA,CAAY,IAAI,CAAA;AAChB,MAAA,WAAA,CAAY,IAAI,CAAA;AAAA,IAClB,WAAW,QAAA,EAAU;AACnB,MAAA,QAAA,EAAS;AAAA,IACX;AAAA,EACF,CAAA,EAAG,CAAC,gBAAA,EAAkB,QAAQ,CAAC,CAAA;AAG/B,EAAA,MAAM,MAAA,GAAS,WAAA;AAAA,IACb,CAAC,QAAwB,IAAA,KAAsB;AAC7C,MAAA,IAAI,OAAO,CAAC,GAAA,CAAI,MAAA,EAAQ,IAAI,GAAG,OAAO,KAAA;AACtC,MAAA,IAAI,CAAC,MAAM,OAAO,IAAA;AAClB,MAAA,IAAI,WAAA,IAAe,CAAC,WAAA,CAAY,IAAI,GAAG,OAAO,KAAA;AAC9C,MAAA,IAAI,WAAW,MAAA,IAAU,OAAA,IAAW,CAAC,OAAA,CAAQ,IAAI,GAAG,OAAO,KAAA;AAC3D,MAAA,IAAI,WAAW,QAAA,IAAY,SAAA,IAAa,CAAC,SAAA,CAAU,IAAI,GAAG,OAAO,KAAA;AACjE,MAAA,OAAO,IAAA;AAAA,IACT,CAAA;AAAA,IACA,CAAC,GAAA,EAAK,WAAA,EAAa,OAAA,EAAS,SAAS;AAAA,GACvC;AAEA,EAAA,MAAM,UAAA,GAAa,WAAA;AAAA,IACjB,CAAC,IAAA,KAAY;AACX,MAAA,IAAI,CAAC,MAAA,CAAO,MAAA,EAAQ,IAAI,CAAA,EAAG;AAC3B,MAAA,IAAI,cAAA,EAAgB;AAClB,QAAA,aAAA,CAAc,MAAM,CAAA;AACpB,QAAA,WAAA,CAAY,IAAI,CAAA;AAChB,QAAA,WAAA,CAAY,IAAI,CAAA;AAAA,MAClB,WAAW,MAAA,EAAQ;AACjB,QAAA,MAAA,CAAO,IAAI,CAAA;AAAA,MACb;AAAA,IACF,CAAA;AAAA,IACA,CAAC,cAAA,EAAgB,MAAA,EAAQ,MAAM;AAAA,GACjC;AAEA,EAAA,MAAM,WAAA,GAAc,YAAY,MAAM;AACpC,IAAA,IAAA,CAAK,cAAc,KAAK,CAAA;AACxB,IAAA,IAAA,CAAK,gBAAgB,IAAI,CAAA;AACzB,IAAA,OAAA,EAAS,YAAY,IAAI,CAAA;AAAA,EAC3B,CAAA,EAAG,CAAC,IAAA,EAAM,OAAO,CAAC,CAAA;AAGlB,EAAA,MAAM,gBAAA,GAAmB,CAAC,CAAC,WAAA,IAAe,CAAC,QAAA,IAAY,YAAA;AACvD,EAAA,MAAM,eAAA,GACJ,aAAA,KAAkB,MAAA,GAAY,gBAAA,GAAmB,CAAC,CAAC,aAAA;AACrD,EAAA,MAAM,UAAA,GACJ,OAAO,aAAA,KAAkB,QAAA,GAAW,aAAA,GAAgB,MAAA;AAItD,EAAA,MAAM,CAAC,aAAA,EAAe,gBAAgB,CAAA,GAAI,SAAmB,IAAI,CAAA;AACjE,EAAA,MAAM,CAAC,UAAA,EAAY,aAAa,CAAA,GAAI,SAAS,KAAK,CAAA;AAClD,EAAA,MAAM,EAAE,MAAA,EAAQ,YAAA,EAAa,GAAI,YAAA;AAEjC,EAAA,MAAM,EAAE,IAAA,EAAM,YAAA,EAAa,GAAI,gBAAgB,YAAA,EAAc;AAAA,IAC3D,SAAS,gBAAA,IAAoB;AAAA,GAC9B,CAAA;AACD,EAAA,MAAM,UAAA,GAAsC,YAAA,EAAc,UAAA,GAAa,SAAA,GAAY,WAAA;AAEnF,EAAA,MAAM,aAAA,GAAgB,WAAA;AAAA,IACpB,OAAO,IAAA,KAAY;AACjB,MAAA,IAAI,gBAAA,EAAkB;AAGpB,QAAA,MAAM,YAAA;AAAA,UACH,UAAA,GACG,KAAA,CAAM,IAAI,CAAA,GACT,IAAA,CAAiC;AAAA,SACxC;AAAA,MACF,WAAW,QAAA,EAAU;AACnB,QAAA,MAAM,SAAS,IAAI,CAAA;AAAA,MACrB;AACA,MAAA,WAAA,EAAY;AACZ,MAAA,SAAA,GAAY,IAAI,CAAA;AAAA,IAClB,CAAA;AAAA,IACA;AAAA,MACE,gBAAA;AAAA,MACA,YAAA;AAAA,MACA,UAAA;AAAA,MACA,KAAA;AAAA,MACA,QAAA;AAAA,MACA,WAAA;AAAA,MACA;AAAA;AACF,GACF;AAEA,EAAA,MAAM,gBAAiD,EACrD,gBAAA,IAAoB,YAElB,MAAA,GACA,eAAA,GACE,CAAC,IAAA,KAAY;AACX,IAAA,gBAAA,CAAiB,IAAI,CAAA;AACrB,IAAA,aAAA,CAAc,IAAI,CAAA;AAAA,EACpB,CAAA,GACA,gBAAA,GACE,CAAC,IAAA,KAAY;AACX,IAAA,aAAA,CAAc,IAAI,CAAA,CAAE,KAAA,CAAM,CAAC,GAAA,KAAiB;AAG1C,MAAA,IAAI,CAAC,iBAAiB,OAAA,EAAS;AAC7B,QAAA,KAAA,CAAM,KAAA,CAAM,GAAA,YAAe,KAAA,GAAQ,GAAA,CAAI,UAAU,oBAAoB,CAAA;AAAA,MACvE;AAAA,IACF,CAAC,CAAA;AAAA,EACH,CAAA;AAAA;AAAA;AAAA,IAGA,CAAC,IAAA,KAAY;AAGX,MAAA,MAAM,MAAA,GAAS,CAAC,GAAA,KAAiB;AAC/B,QAAA,MAAM,KAAA,GAAQ,eAAe,KAAA,GAAQ,GAAA,GAAM,IAAI,KAAA,CAAM,MAAA,CAAO,GAAG,CAAC,CAAA;AAChE,QAAA,IAAI,iBAAiB,OAAA,EAAS;AAC5B,UAAA,IAAI;AACF,YAAA,eAAA,CAAgB,QAAQ,KAAK,CAAA;AAC7B,YAAA;AAAA,UACF,CAAA,CAAA,MAAQ;AAAA,UAER;AAAA,QACF;AACA,QAAA,KAAA,CAAM,KAAA,CAAM,KAAA,CAAM,OAAA,IAAW,oBAAoB,CAAA;AAAA,MACnD,CAAA;AAEA,MAAA,IAAI;AACF,QAAA,OAAA,CAAQ,QAAQ,QAAA,GAAW,IAAI,CAAC,CAAA,CAAE,MAAM,MAAM,CAAA;AAAA,MAChD,SAAS,GAAA,EAAK;AACZ,QAAA,MAAA,CAAO,GAAG,CAAA;AAAA,MACZ;AAAA,IACF;AAAA,GAAA;AAGR,EAAA,MAAM,mBAAmB,CAAC,CAAC,YAAA,IAAgB,MAAA,CAAO,QAAQ,YAAY,CAAA;AACtE,EAAA,MAAM,oBAAoB,CAAC,CAAC,YAAA,IAAgB,MAAA,CAAO,UAAU,YAAY,CAAA;AAGzE,EAAA,MAAM,YAAA,GAAe,QAAQ,MAAM;AACjC,IAAA,MAAM,OAAO,YAAA,GACT,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,CAAC,GAAA,MAAS;AAAA,MACzB,KAAK,GAAA,CAAI,GAAA;AAAA,MACT,MAAA,EAAQ,GAAA,CAAI,MAAA,IAAU,GAAA,CAAI,GAAA;AAAA,MAC1B,QAAA,EAAU,IAAI,QAAA,IAAY,IAAA;AAAA,MAC1B,WAAW,GAAA,CAAI,SAAA;AAAA,MACf,OAAO,GAAA,CAAI,KAAA;AAAA,MACX,UAAU,GAAA,CAAI,QAAA;AAAA,MACd,gBAAgB,GAAA,CAAI,cAAA;AAAA,MACpB,UAAU,GAAA,CAAI,QAAA;AAAA,MACd,UAAU,GAAA,CAAI,QAAA;AAAA,MACd,MAAA,EAAQ,GAAA,CAAI,MAAA,GACR,CAAC,IAAA,EAAS,KAAA,KAAmB,GAAA,CAAI,MAAA,CAAQ,IAAA,EAAM,KAAA,EAAO,OAAO,CAAA,GAC7D;AAAA,KACN,CAAE,IACF,IAAA,CAAK,YAAA;AACT,IAAA,IAAI,CAAC,oBAAoB,OAAO,IAAA;AAKhC,IAAA,OAAO,IAAA,CAAK,IAAI,CAAC,GAAA,MAAS,EAAE,GAAG,GAAA,EAAK,QAAA,EAAU,KAAA,EAAM,CAAE,CAAA;AAAA,EACxD,CAAA,EAAG;AAAA,IACD,YAAA;AAAA,IACA,kBAAA;AAAA,IACA,IAAA,CAAK,OAAA;AAAA,IACL,IAAA,CAAK,YAAA;AAAA,IACL;AAAA,GACD,CAAA;AAMD,EAAA,MAAM,CAAC,cAAA,EAAgB,iBAAiB,CAAA,GAAI,SAGlC,IAAI,CAAA;AACd,EAAA,MAAM,WAAW,IAAA,CAAK,IAAA;AACtB,EAAA,MAAM,cAAc,IAAA,CAAK,OAAA;AACzB,EAAA,MAAM,SAAA,GAAY,QAAyB,MAAM;AAC/C,IAAA,IAAI,CAAC,QAAA,EAAU,OAAO,EAAC;AACvB,IAAA,MAAM,UAAyB,EAAE,GAAA,EAAK,SAAS,KAAA,EAAO,GAAA,EAAK,SAAS,KAAA,EAAM;AAC1E,IAAA,MAAM,IAAA,GACJ,cAAA,IAAkB,cAAA,CAAe,OAAA,KAAY,CAAA,EAAG,OAAA,CAAQ,GAAG,CAAA,CAAA,EAAI,OAAA,CAAQ,GAAG,CAAA,CAAA,GACtE,cAAA,CAAe,OACf,EAAC;AAIP,IAAA,OAAO,CAAC,OAAA,EAAS,GAAG,IAAI,CAAA,CAAE,OAAO,CAAC,CAAA,KAAM,YAAA,CAAa,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,GAAA,KAAQ,CAAA,CAAE,GAAG,CAAC,CAAA;AAAA,EACnF,CAAA,EAAG,CAAC,QAAA,EAAU,cAAA,EAAgB,YAAY,CAAC,CAAA;AAC3C,EAAA,MAAM,eAAA,GAAkB,WAAA;AAAA,IACtB,CAAC,IAAA,KAA0B;AACzB,MAAA,MAAM,CAAC,OAAA,EAAS,GAAG,IAAI,CAAA,GAAI,IAAA;AAC3B,MAAA,iBAAA,CAAkB,OAAA,GAAU,EAAE,OAAA,EAAS,CAAA,EAAG,OAAA,CAAQ,GAAG,CAAA,CAAA,EAAI,OAAA,CAAQ,GAAG,CAAA,CAAA,EAAI,IAAA,EAAK,GAAI,IAAI,CAAA;AACrF,MAAA,WAAA,CAAY,OAAA,GAAU,EAAE,KAAA,EAAO,OAAA,CAAQ,KAAK,KAAA,EAAO,OAAA,CAAQ,GAAA,EAAI,GAAI,IAAI,CAAA;AAAA,IACzE,CAAA;AAAA,IACA,CAAC,WAAW;AAAA,GACd;AAMA,EAAA,MAAM,YAAY,oBAAA,GACb,YAAA,CAAa,MAAA,CAAO,UAAA,EAAY,QAAQ,CAAA,GACzC,QAAA;AACJ,EAAA,MAAM,YAAA,GAAe,oBAAA,GACjB,YAAA,CAAa,MAAA,CAAO,YAAY,OAAA,GAChC,WAAA;AACJ,EAAA,MAAM,UAAA,GAAa,uBAAuB,YAAA,GAAe,SAAA;AACzD,EAAA,MAAM,iBAAA,GAAoB,oBAAA,GACtB,YAAA,CAAa,OAAA,GACb,YAAA;AACJ,EAAA,MAAM,cAAc,SAAA,IAAa,CAAA;AAKjC,EAAA,MAAM,WAAW,GAAA,EAAK,KAAA;AACtB,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,QAAA,GAAW;AAAA,MACT,GAAG,IAAA,CAAK,MAAA;AAAA,MACR,MAAM,IAAA,CAAK,IAAA;AAAA,MACX,GAAI,oBAAA,GAAuB,EAAE,IAAA,EAAM,WAAA,KAAgB;AAAC,KACrD,CAAA;AAAA,EACH,CAAA,EAAG,CAAC,QAAA,EAAU,IAAA,CAAK,QAAQ,IAAA,CAAK,IAAA,EAAM,WAAA,EAAa,oBAAoB,CAAC,CAAA;AAQxE,EAAA,MAAM,kBAAA,GAAqB,WAAA;AAAA,IACzB,CAAC,KAAA,KAAkB;AACjB,MAAA,IAAA,CAAK,YAAA,CAAa,eAAe,KAAK,CAAA;AACtC,MAAA,IAAI,CAAC,kBAAA,EAAoB;AACzB,MAAA,cAAA,GAAiB,KAAK,CAAA;AAItB,MAAA,IAAI,WAAA,KAAgB,CAAA,IAAK,CAAC,oBAAA,iBAAqC,CAAC,CAAA;AAAA,IAClE,CAAA;AAAA,IACA;AAAA,MACE,IAAA,CAAK,YAAA;AAAA,MACL,kBAAA;AAAA,MACA,cAAA;AAAA,MACA,YAAA;AAAA,MACA,oBAAA;AAAA,MACA;AAAA;AACF,GACF;AAEA,EAAA,MAAM,gBAAA,GAAmB,WAAA;AAAA,IACvB,CAAC,KAAA,KAAkB;AACjB,MAAA,IAAA,CAAK,YAAA,CAAa,aAAa,KAAK,CAAA;AACpC,MAAA,IAAI,CAAC,kBAAA,EAAoB;AACzB,MAAA,MAAM,CAAC,KAAA,EAAO,KAAK,CAAA,GAAI,KAAA,CAAM,MAAM,GAAG,CAAA;AACtC,MAAA,YAAA;AAAA,QACE,KAAA,KAAU,UAAU,KAAA,IAAS,KAAA,KAAU,UACnC,EAAE,KAAA,EAAO,OAAM,GACf;AAAA,OACN;AAEA,MAAA,IAAI,CAAC,oBAAA,EAAsB,YAAA,GAAe,CAAC,CAAA;AAAA,IAC7C,CAAA;AAAA,IACA;AAAA,MACE,IAAA,CAAK,YAAA;AAAA,MACL,kBAAA;AAAA,MACA,YAAA;AAAA,MACA,YAAA;AAAA,MACA;AAAA;AACF,GACF;AAEA,EAAA,MAAM,kBAAA,GAAqB,YAAY,MAAM;AAC3C,IAAA,IAAA,CAAK,YAAA,EAAa;AAClB,IAAA,IAAI,CAAC,kBAAA,EAAoB;AAGzB,IAAA,cAAA,GAAiB,EAAE,CAAA;AACnB,IAAA,YAAA,GAAe,IAAI,CAAA;AACnB,IAAA,IAAI,CAAC,oBAAA,EAAsB,YAAA,GAAe,CAAC,CAAA;AAAA,EAC7C,CAAA,EAAG;AAAA,IACD,IAAA;AAAA,IACA,kBAAA;AAAA,IACA,cAAA;AAAA,IACA,YAAA;AAAA,IACA,YAAA;AAAA,IACA;AAAA,GACD,CAAA;AAWD,EAAA,MAAM,kBAAA,GAAqB,WAAA;AAAA,IACzB,CAAC,MAAA,KAAqB;AACpB,MAAA,IAAA,CAAK,YAAA,CAAa,WAAA,EAAa,QAAA,CAAS,MAAM,CAAA;AAC9C,MAAA,IAAI,CAAC,kBAAA,EAAoB;AACzB,MAAA,IAAI,WAAA,KAAgB,CAAA,IAAK,CAAC,oBAAA,iBAAqC,CAAC,CAAA;AAAA,IAClE,CAAA;AAAA,IACA;AAAA,MACE,IAAA,CAAK,YAAA;AAAA,MACL,kBAAA;AAAA,MACA,YAAA;AAAA,MACA,oBAAA;AAAA,MACA;AAAA;AACF,GACF;AAEA,EAAA,MAAM,iBAAA,GAAoB,QAAQ,MAAM;AACtC,IAAA,MAAM,IAAA,GAAO,KAAK,YAAA,CAAa,WAAA;AAC/B,IAAA,IAAI,CAAC,MAAM,OAAO,MAAA;AAClB,IAAA,OAAO,EAAE,GAAG,IAAA,EAAM,QAAA,EAAU,kBAAA,EAAmB;AAAA,EACjD,GAAG,CAAC,IAAA,CAAK,YAAA,CAAa,WAAA,EAAa,kBAAkB,CAAC,CAAA;AAEtD,EAAA,MAAM,oBAAA,GAAuB,WAAA;AAAA,IAC3B,CAAC,IAAA,KAAiB;AAChB,MAAA,aAAA,CAAc,YAAY,IAAI,CAAA;AAC9B,MAAA,eAAA,GAAkB,IAAI,CAAA;AAEtB,MAAA,IAAI,oBAAA,EAAsB,YAAA,CAAa,UAAA,CAAW,IAAI,CAAA;AAAA,WAAA,IAC7C,kBAAA,iBAAmC,CAAC,CAAA;AAAA,IAC/C,CAAA;AAAA,IACA;AAAA,MACE,aAAA;AAAA,MACA,eAAA;AAAA,MACA,oBAAA;AAAA,MACA,YAAA,CAAa,UAAA;AAAA,MACb,kBAAA;AAAA,MACA;AAAA;AACF,GACF;AAiBA,EAAA,MAAM,cAAA,GACJ,kBAAA,IAAsB,CAAC,CAAC,qBAAqB,YAAA,KAAiB,MAAA;AAChE,EAAA,MAAM,YAAA,GACJ,kBAAA,IAAsB,CAAC,CAAC,qBAAqB,UAAA,KAAe,MAAA;AAC9D,EAAA,MAAM,qBAAqB,cAAA,IAAkB,YAAA;AAC7C,EAAA,MAAM,iBAAA,GAAoB;AAAA,IACxB,GAAI,cAAA,GAAiB,CAAC,SAAS,IAAI,EAAC;AAAA,IACpC,GAAI,YAAA,GAAe,CAAC,OAAO,IAAI;AAAC,GAClC;AACA,EAAA,MAAM,uBAAA,GAA0B,OAAO,KAAK,CAAA;AAC5C,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,kBAAA,EAAoB;AACzB,IAAA,IAAI,wBAAwB,OAAA,EAAS;AACrC,IAAA,uBAAA,CAAwB,OAAA,GAAU,IAAA;AAClC,IAAA,OAAA,CAAQ,KAAA;AAAA,MACN,iBAAiB,iBAAA,CACd,GAAA,CAAI,CAAC,IAAA,KAAS,KAAK,IAAI,CAAA,EAAA,CAAI,CAAA,CAC3B,IAAA,CAAK,OAAO,CAAC,CAAA,CAAA,EACd,kBAAkB,MAAA,GAAS,CAAA,GAAI,QAAQ,IACzC,CAAA,4CAAA;AAAA,KACF;AAAA,EAIF,CAAA,EAAG,CAAC,kBAAkB,CAAC,CAAA;AAKvB,EAAA,MAAM,gBAAgB,YAAA,IAAgB,iBAAA;AACtC,EAAA,MAAM,aAAa,IAAA,CAAK,GAAA;AAAA,IACtB,CAAA;AAAA,IACA,KAAK,IAAA,CAAK,YAAA,GAAe,KAAK,GAAA,CAAI,CAAA,EAAG,aAAa,CAAC;AAAA,GACrD;AACA,EAAA,MAAM,SAAA,GACJ,KAAK,IAAA,CAAK,MAAA,KAAW,IAAI,CAAA,GAAA,CAAK,WAAA,GAAc,KAAK,aAAA,GAAgB,CAAA;AACnE,EAAA,MAAM,UAAU,SAAA,KAAc,CAAA,GAAI,IAAI,SAAA,GAAY,IAAA,CAAK,KAAK,MAAA,GAAS,CAAA;AAOrE,EAAA,MAAM,EAAE,OAAA,EAAS,eAAA,EAAgB,GAAI,YAAA;AACrC,EAAA,MAAM,cACJ,CAAC,SAAA,IAAa,CAAC,QAAA,IAAY,CAAC,aAAa,IAAA,CAAK,iBAAA;AAChD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,oBAAA,IAAwB,CAAC,WAAA,EAAa;AAC3C,IAAA,IAAI,WAAA,GAAc,UAAA,EAAY,eAAA,CAAgB,UAAU,CAAA;AAAA,EAC1D,GAAG,CAAC,oBAAA,EAAsB,aAAa,WAAA,EAAa,UAAA,EAAY,eAAe,CAAC,CAAA;AAGhF,EAAA,MAAM,OAAA,GAAU,CAAC,IAAA,KACf,QAAA,GACI,QAAA,CAAS,IAAI,CAAA,GACb,MAAA,CAAQ,IAAA,CAAiC,IAAA,CAAK,UAAU,CAAA,IAAK,EAAE,CAAA;AACrE,EAAA,MAAM,WAAA,GAAc,YAAA,GAAe,OAAA,CAAQ,YAAY,CAAA,GAAI,EAAA;AAC3D,EAAA,MAAM,cAAA,GAAiB,CAAC,YAAA,GACpB,MAAA,GACA,cACE,WAAA,CAAY,YAAY,CAAA,GACxB,IAAA,CAAK,aAAA,GACH,MAAA;AAAA,IACG,YAAA,CAAyC,IAAA,CAAK,aAAa,CAAA,IAAK;AAAA,GACnE,GACA,MAAA;AAGR,EAAA,MAAM,cAAA,GAAiB,CAAC,IAAA,KAAY;AAClC,IAAA,IAAI,WAAW,OAAA,EAAS;AAEtB,MAAA,MAAM,KAAM,IAAA,CAAiC,EAAA;AAC7C,MAAA,IAAI,gBAAgB,EAAA,EAAI;AACtB,QAAA,UAAA,CAAW,CAAA,CAAA,EAAI,YAAY,CAAA,CAAA,EAAI,EAAE,CAAA,CAAE,CAAA;AAAA,MACrC;AACA,MAAA;AAAA,IACF;AACA,IAAA,IAAA,CAAK,eAAe,IAAI,CAAA;AACxB,IAAA,OAAA,EAAS,WAAA,CAAY,KAAA,CAAM,IAAI,CAAC,CAAA;AAAA,EAClC,CAAA;AAOA,EAAA,MAAM,aAAA,GAAgB,CAAC,CAAC,WAAA,IAAe,YAAY,MAAA,GAAS,CAAA;AAK5D,EAAA,MAAM,WAAA,GAAc,cAAc,QAAA,IAAY,UAAA;AAC9C,EAAA,MAAM,cAAc,qBAAA,CAAsB;AAAA,IACxC,SAAA,EAAW,KAAK,IAAA,CAAK,MAAA;AAAA,IACrB,OAAA,EAAS,kBAAA,IAAsB,IAAA,CAAK,QAAA,KAAa,OAAA;AAAA,IACjD,WAAA;AAAA,IACA,MAAA,EAAQ,CAAC,KAAA,KAAU;AACjB,MAAA,MAAM,IAAA,GAAO,IAAA,CAAK,IAAA,CAAK,KAAK,CAAA;AAC5B,MAAA,IAAI,IAAA,iBAAqB,IAAI,CAAA;AAAA,IAC/B,CAAA;AAAA,IACA,cAAA,EAAgB,aAAA,GACZ,CAAC,KAAA,KAAU;AACT,MAAA,MAAM,IAAA,GAAO,IAAA,CAAK,IAAA,CAAK,KAAK,CAAA;AAC5B,MAAA,IAAI,IAAA,EAAM;AACR,QAAA,kBAAA,CAAmB,KAAA,CAAM,IAAI,CAAC,CAAA;AAAA,MAChC;AAAA,IACF,CAAA,GACA,MAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOJ,MAAA,EAAQ,aAAa,WAAA,GAAc;AAAA,GACpC,CAAA;AAGD,EAAA,OAAO;AAAA,IACL,OAAA;AAAA,IACA,MAAA;AAAA,IACA,eAAA;AAAA,IACA,WAAA;AAAA,IACA,WAAA;AAAA,IACA,eAAA;AAAA,IACA,UAAA;AAAA,IACA,aAAA;AAAA,IACA,UAAA;AAAA,IACA,UAAA;AAAA,IACA,UAAA;AAAA,IACA,cAAA;AAAA,IACA,WAAA;AAAA,IACA,WAAA;AAAA,IACA,YAAA;AAAA,IACA,iBAAA;AAAA,IACA,UAAA;AAAA,IACA,QAAA;AAAA,IACA,QAAA;AAAA,IACA,kBAAA;AAAA,IACA,oBAAA;AAAA,IACA,YAAA;AAAA,IACA,UAAA;AAAA,IACA,oBAAA;AAAA,IACA,cAAA;AAAA,IACA,kBAAA;AAAA,IACA,gBAAA;AAAA,IACA,eAAA;AAAA,IACA,eAAA;AAAA,IACA,kBAAA;AAAA,IACA,QAAA;AAAA,IACA,YAAA;AAAA,IACA,SAAA;AAAA,IACA,kBAAA;AAAA,IACA,KAAA;AAAA,IACA,WAAA;AAAA,IACA,WAAA;AAAA,IACA,MAAA;AAAA,IACA,iBAAA;AAAA,IACA,IAAA;AAAA,IACA,kBAAA;AAAA,IACA,iBAAA;AAAA,IACA,aAAA;AAAA,IACA,aAAA;AAAA,IACA,SAAA;AAAA,IACA,OAAA;AAAA,IACA,YAAA;AAAA,IACA,oBAAA;AAAA,IACA,iBAAA;AAAA,IACA,gBAAA;AAAA,IACA,WAAA;AAAA,IACA,YAAA;AAAA,IACA,kBAAA;AAAA,IACA,aAAA;AAAA,IACA,WAAA;AAAA,IACA,QAAA;AAAA,IACA,iBAAA;AAAA,IACA,YAAA;AAAA,IACA,SAAA;AAAA,IACA,OAAA;AAAA,IACA,UAAA;AAAA,IACA,aAAA;AAAA,IACA,gBAAA;AAAA,IACA,gBAAA;AAAA,IACA;AAAA,GACF;AACF;AAuHO,SAAS,iBAEd,KAAA,EAAoD;AACpD,EAAA,MAAM,CAAA,GAAI,sBAAyB,KAAK,CAAA;AACxC,EAAA,MAAM,EAAE,aAAA,EAAe,aAAA,EAAc,GAAI,CAAA;AACzC,EAAA,MAAM,OAAA,GAAU,WAAA;AAAA,IACd,MAAO,aAAA,GAAgB,aAAA,CAAc,aAAa,CAAA,GAAI,QAAQ,OAAA,EAAQ;AAAA,IACtE,CAAC,eAAe,aAAa;AAAA,GAC/B;AACA,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,EAAE,IAAA,CAAK,IAAA;AAAA,IACb,KAAA,EAAO,EAAE,IAAA,CAAK,KAAA;AAAA,IACd,SAAS,CAAA,CAAE,SAAA;AAAA,IACX,OAAO,CAAA,CAAE,QAAA;AAAA,IACT,WAAW,CAAA,CAAE,eAAA;AAAA,IACb,SAAS,CAAA,CAAE,YAAA;AAAA,IACX,SAAS,CAAA,CAAE,OAAA;AAAA,IACX,QAAQ,CAAA,CAAE,KAAA;AAAA,IACV,UAAU,CAAA,CAAE,OAAA;AAAA,IACZ,KAAK,CAAA,CAAE,MAAA;AAAA,IACP,MAAA,EAAQ,EAAE,IAAA,CAAK,MAAA;AAAA,IACf,WAAW,CAAA,CAAE,kBAAA;AAAA,IACb,MAAM,CAAA,CAAE,SAAA;AAAA,IACR,SAAS,CAAA,CAAE,eAAA;AAAA,IACX,cAAc,CAAA,CAAE,iBAAA;AAAA,IAChB,gBAAA,EAAkB,EAAE,IAAA,CAAK,gBAAA;AAAA,IACzB,cAAc,CAAA,CAAE,kBAAA;AAAA,IAChB,MAAM,CAAA,CAAE,WAAA;AAAA,IACR,WAAW,CAAA,CAAE,UAAA;AAAA,IACb,UAAU,CAAA,CAAE,iBAAA;AAAA,IACZ,aAAa,CAAA,CAAE,oBAAA;AAAA,IACf,SAAS,CAAA,CAAE,iBAAA;AAAA,IACX,WAAW,CAAA,CAAE,SAAA;AAAA,IACb,SAAS,CAAA,CAAE,OAAA;AAAA,IACX,aAAa,CAAA,CAAE,WAAA;AAAA,IACf,gBAAgB,CAAA,CAAE,kBAAA;AAAA,IAClB,WAAW,CAAA,CAAE,eAAA;AAAA,IACb,gBAAgB,CAAA,CAAE,oBAAA;AAAA,IAClB,UAAU,CAAA,CAAE,YAAA;AAAA,IACZ,YAAY,CAAA,CAAE,UAAA;AAAA,IACd,SAAS,CAAA,CAAE,cAAA;AAAA,IACX,aAAa,CAAA,CAAE,WAAA;AAAA,IACf,iBAAiB,CAAA,CAAE,WAAA;AAAA,IACnB,QAAQ,CAAA,CAAE,gBAAA,IAAoB,KAAA,CAAM,QAAA,GAAW,EAAE,YAAA,GAAe,MAAA;AAAA,IAChE,MAAM,CAAA,CAAE,UAAA;AAAA,IACR,IAAA,EAAM;AAAA,MACJ,MAAM,CAAA,CAAE,QAAA;AAAA,MACR,SAAS,CAAA,CAAE,WAAA;AAAA,MACX,QAAQ,CAAA,CAAE,UAAA;AAAA,MACV,MAAM,CAAA,CAAE;AAAA,KACV;AAAA,IACA,QAAQ,CAAA,CAAE,aAAA;AAAA,IACV,aAAA,EAAe;AAAA,MACb,MAAM,CAAA,CAAE,UAAA;AAAA,MACR,SAAS,CAAA,CAAE,aAAA;AAAA,MACX,IAAA,EAAM,aAAA;AAAA,MACN,OAAA;AAAA,MACA,MAAM,CAAA,CAAE,UAAA;AAAA,MACR,MAAM,CAAA,CAAE;AAAA;AACV,GACF;AACF","file":"chunk-C7PQ54JI.js","sourcesContent":["import type { MutationMode, UndoableWrite } from \"@marktiderman/genesis-core/hooks\";\nimport { toast } from \"../ui/sonner\";\n\nconst DONE: Record<UndoableWrite[\"kind\"], string> = {\n create: \"Created.\",\n update: \"Saved.\",\n delete: \"Deleted.\",\n};\n\n/**\n * The undo toast for an `undoable` write (core's `onUndoable`): a sonner\n * toast with an Undo button, shown for as long as the undo is offered.\n * Needs a mounted `<Toaster />`.\n */\nexport function showUndoToast(write: UndoableWrite): void {\n toast(DONE[write.kind], {\n duration: write.delayMs,\n action: {\n label: \"Undo\",\n onClick: () => {\n void write.undo().then((undone) => {\n // Sonner pauses on hover, so the button can outlive the window.\n if (!undone && write.strategy === \"delay\") {\n toast(\"Already saved. It can no longer be undone.\");\n }\n });\n },\n },\n });\n}\n\n/** The default error report for writes that fail after the form has closed. */\nexport function showWriteErrorToast(error: Error): void {\n toast.error(error.message || \"The change could not be saved.\");\n}\n\n/**\n * ResourcePage's write-mode options for its `useResource`: the page's\n * `mutationMode` unless `resourceOptions` sets one, the undo toast, and an\n * error toast for a write that fails after it was shown as done.\n */\nexport function writeModeOptions(\n resourceOptions: { mutationMode?: MutationMode; onUndoable?: (write: UndoableWrite) => void; onError?: (error: Error) => void } | undefined,\n mutationMode: MutationMode | undefined,\n): { mutationMode: MutationMode; onUndoable: (write: UndoableWrite) => void; onError?: (error: Error) => void } {\n const mode = resourceOptions?.mutationMode ?? mutationMode ?? \"pessimistic\";\n return {\n mutationMode: mode,\n onUndoable: resourceOptions?.onUndoable ?? showUndoToast,\n onError: resourceOptions?.onError ?? (mode === \"pessimistic\" ? undefined : showWriteErrorToast),\n };\n}\n","\"use client\";\n\n/**\n * `useResourceTable`: ResourcePage's behaviour without its markup. Lives\n * apart from ResourcePage.tsx so importing the hook (e.g. from `/hooks`)\n * does not pull in the page's components and icons.\n */\nimport { useMemo, useState, useCallback, useEffect, useRef } from \"react\";\nimport type { DataTableColumn, DataTableSort } from \"./DataTable\";\nimport type {\n ResourceAction,\n ResourceDeleteConfirmCopy,\n ResourcePageProps,\n} from \"./ResourcePage\";\nimport { useViewSettings } from \"../../hooks/use-view-settings\";\nimport { useKeyboardNavigation } from \"../../hooks/use-keyboard-navigation\";\nimport { useResourceUrlState } from \"../../hooks/use-resource-url-state\";\nimport {\n useResourcePage,\n type ResourceActions,\n} from \"../../hooks/use-resource-page\";\nimport {\n useCapabilities,\n useOne,\n useResource,\n} from \"@marktiderman/genesis-core/hooks\";\nimport type {\n BaseRecord,\n Identifier,\n} from \"@marktiderman/genesis-core/provider\";\nimport { writeModeOptions } from \"./undo-toast\";\nimport { toast } from \"../ui/sonner\";\nimport { defaultNavigate } from \"../../navigation\";\n\n/**\n * Everything ResourcePage's markup reads. Internal: its names may change in\n * any release. Apps use {@link useResourceTable}.\n *\n * @internal\n */\nexport function useResourceTableModel<\n T extends Record<string, unknown> = Record<string, unknown>,\n>(props: ResourcePageProps<T>) {\n const {\n resource: resourceName,\n data: dataProp,\n total: totalProp,\n pagination = \"client\",\n clientRowLimit = 1000,\n title,\n subtitle,\n icon,\n columns: columnsProp,\n getKey: getKeyProp,\n detail = \"panel\",\n detailWidth = \"md\",\n titleField: titleFieldProp,\n subtitleField: subtitleFieldProp,\n getTitle,\n getSubtitle,\n renderDetail: renderDetailProp,\n detailFields,\n statusFilter,\n searchFields,\n searchPlaceholder,\n initialFilters,\n onFiltersChange,\n filters: filtersProp,\n page: pageProp,\n perPage: perPageProp,\n onPageChange,\n onPerPageChange,\n onSortChange,\n onSearchChange,\n loading: loadingProp,\n error: errorProp,\n errorMessage,\n onRetry: onRetryProp,\n savedViews,\n onLoadView,\n onSaveView,\n onDeleteView,\n canSaveViews,\n columnVisibility,\n columnVisibilityKey,\n resizableColumns,\n resizeKey,\n stickyHeader,\n stickyFirstColumn,\n pageSizeOptions,\n onCreate,\n onEdit,\n onDelete,\n can,\n canEditItem,\n createLabel = \"New\",\n canEdit,\n canDelete,\n allowDelete,\n confirmDelete,\n onDeleted,\n secondaryActions,\n allowCreate,\n allowEdit,\n formFields,\n renderForm: renderFormProp,\n formMode,\n formSteps,\n formLayout: formLayoutProp,\n mutationMode: mutationModeProp,\n bulkActions,\n renderCard: renderCardProp,\n openOnCardClick = false,\n renderTable: renderTableProp,\n gridCols: gridColsProp,\n keyboardNavigation = true,\n capabilities,\n toolbar,\n emptyState,\n emptyIcon,\n emptyMessage,\n emptyDescription,\n header: headerMode = \"page\",\n resourceOptions,\n urlState: urlStateProp,\n defaultView = \"table\",\n onNavigate = defaultNavigate,\n viewSettingsKey: viewSettingsKeyProp,\n slots,\n slotProps,\n className,\n } = props;\n\n // ── Determine mode ──\n const isClientMode = !!resourceName;\n\n /**\n * Server-controlled mode is entered by supplying ANY of the controlled\n * props — presence is the switch, so a caller that only pages (no server\n * search) still gets its `data` left alone.\n */\n // `resource` mode paging through the provider: ResourcePage owns both the\n // fetch and the page state, and reuses the server-controlled path below\n // (no client-side transform, the pager under the list) with useResource's\n // setters standing in for the caller's callbacks.\n const resourceServerPaging = isClientMode && pagination === \"server\";\n\n // ── URL state (`urlState`): the open record, search, sort and page ──\n // An adapter has `setSearchParams`; the options object wraps one.\n const url = useResourceUrlState(\n urlStateProp\n ? \"setSearchParams\" in urlStateProp\n ? { searchParams: urlStateProp }\n : urlStateProp\n : undefined,\n );\n // Read once: the URL seeds the list when it mounts, then follows it.\n const [urlSeed] = useState(() => {\n if (!url) return null;\n // A URL sort only counts when it names a sortable column: a hand-edited\n // or stale link must not send an arbitrary field to the provider.\n const sortable =\n !url.sort || !columnsProp\n ? true\n : columnsProp.some((col) =>\n typeof col === \"string\"\n ? col === url.sort!.field\n : col.key === url.sort!.field && col.sortable !== false,\n );\n return { q: url.q, sort: sortable ? url.sort : null, page: url.page };\n });\n // The URL names the open record only where there is a peek to open.\n const urlPeek = detail === \"panel\" || detail === \"modal\" ? url : undefined;\n const urlSortKey = urlSeed?.sort\n ? `${urlSeed.sort.field}:${urlSeed.sort.order}`\n : \"\";\n\n const isServerControlled =\n resourceServerPaging ||\n pageProp !== undefined ||\n perPageProp !== undefined ||\n onPageChange !== undefined ||\n onPerPageChange !== undefined ||\n onSortChange !== undefined ||\n onSearchChange !== undefined;\n\n const viewSettingsKey =\n viewSettingsKeyProp ??\n resourceName ??\n title.toLowerCase().replace(/\\s+/g, \"-\");\n const { settings, updateSetting } = useViewSettings(viewSettingsKey);\n\n // Server search needs the columns to match. Without them the provider\n // would get a query it ignores, so the search box hides instead of lying.\n const serverSearchFields = resourceOptions?.searchFields ?? searchFields;\n\n // ── Client-side mode: call useResource (hook is always called for rules-of-hooks) ──\n // Core's useResource constrains its row type to BaseRecord (rows carry an\n // `id`), which is stricter than ResourcePage's public `T extends\n // Record<string, unknown>`. Intersect at the call site so the public\n // ResourcePageProps<T> generic stays unchanged while satisfying the hook.\n const resourceHook = useResource<T & BaseRecord>(\n resourceName ?? \"__noop__\",\n isClientMode\n ? {\n ...resourceOptions,\n // Client paging fetches everything it can in one request; server\n // paging starts at the user's stored page size. An explicit\n // `defaultPerPage` wins over both.\n defaultPerPage:\n resourceOptions?.defaultPerPage ??\n (resourceServerPaging\n ? (perPageProp ?? settings.pageSize)\n : clientRowLimit),\n searchFields: resourceServerPaging\n ? serverSearchFields\n : resourceOptions?.searchFields,\n // Paging, searching and sorting change the query key; keep the\n // current page on screen while the next one loads.\n keepPreviousData:\n resourceOptions?.keepPreviousData ?? resourceServerPaging,\n // Start where the URL says, so restoring a link doesn't push a\n // search or sort that resets the page to 1.\n ...(resourceServerPaging && urlSeed\n ? {\n defaultSearch: urlSeed.q,\n ...(urlSeed.page ? { defaultPage: urlSeed.page } : {}),\n ...(urlSeed.sort ? { defaultSort: urlSeed.sort } : {}),\n }\n : {}),\n ...writeModeOptions(resourceOptions, mutationModeProp),\n }\n : { enabled: false },\n );\n\n /** Explicit prop beats the per-user stored preference. */\n const effectivePageSize = resourceServerPaging\n ? (resourceHook.params.pagination?.perPage ?? settings.pageSize)\n : (perPageProp ?? settings.pageSize);\n\n // ── Resolve display data ──\n const displayData: T[] = isClientMode\n ? (resourceHook.list.data?.data ?? [])\n : (dataProp ?? []);\n const displayTotal: number = isClientMode\n ? (resourceHook.list.data?.total ?? 0)\n : (totalProp ?? 0);\n // Client-side mode reads the hook it owns; server-data mode reads the\n // caller's `loading` / `error` props, defaulting to false so a page that\n // supplies neither renders exactly as it did before they existed.\n const isLoading = isClientMode\n ? resourceHook.list.isLoading\n : (loadingProp ?? false);\n const hasError = isClientMode\n ? resourceHook.list.isError\n : (errorProp ?? false);\n\n // ── Call useResourcePage ──\n const page = useResourcePage<T>({\n resource: resourceName,\n data: displayData,\n total: displayTotal,\n columns: columnsProp,\n statusFilter,\n searchFields,\n initialFilters:\n initialFilters ??\n (urlSeed && (urlSeed.q || urlSeed.sort)\n ? [\n ...(urlSeed.q\n ? [{ field: \"__search__\", operator: \"contains\" as const, value: urlSeed.q }]\n : []),\n ...(urlSeed.sort\n ? [{ field: \"__sort__\", operator: \"eq\" as const, value: urlSortKey }]\n : []),\n ]\n : undefined),\n onFiltersChange,\n defaultView,\n // Each page remembers its own table/cards choice, under the same key as\n // its density and page size — not one key shared by every data page.\n viewKey: viewSettingsKey,\n detail,\n titleField: titleFieldProp,\n subtitleField: subtitleFieldProp,\n controlled: isServerControlled,\n });\n\n // ── `pagination=\"server\"`: push the filter row's state into useResource ──\n // Effects rather than the change handlers, so `initialFilters` and \"Clear\n // all\" reach the provider by the same path as a keystroke. Each push is\n // skipped while its value still equals what the hook already has, so the\n // first render does not reset `defaultSort` or refetch for nothing.\n const {\n setSearch: setResourceSearch,\n setSort: setResourceSort,\n setFilters: setResourceFilters,\n } = resourceHook;\n // Seeded from the URL, which useResource already starts on (see above).\n const pushedSearchRef = useRef(resourceServerPaging ? (urlSeed?.q ?? \"\") : \"\");\n const searchEffectRanRef = useRef(false);\n useEffect(() => {\n if (!resourceServerPaging) return;\n const firstRun = !searchEffectRanRef.current;\n searchEffectRanRef.current = true;\n if (page.search === pushedSearchRef.current) return;\n const push = () => {\n pushedSearchRef.current = page.search;\n setResourceSearch(page.search);\n };\n // One request per pause in typing, not per keystroke — but an\n // `initialFilters` search (first run) or a cleared box (\"Clear all\")\n // goes out at once, landing with the sort / status pushes instead of\n // 300ms behind them.\n if (firstRun || page.search === \"\") {\n push();\n return;\n }\n const timer = setTimeout(push, 300);\n return () => clearTimeout(timer);\n }, [resourceServerPaging, page.search, setResourceSearch]);\n\n const defaultSort = resourceOptions?.defaultSort;\n const pushedSortRef = useRef<string>(resourceServerPaging ? urlSortKey : \"\");\n useEffect(() => {\n if (!resourceServerPaging) return;\n const key = page.sort ? `${page.sort.field}:${page.sort.order}` : \"\";\n if (key === pushedSortRef.current) return;\n pushedSortRef.current = key;\n // Clearing the sort returns to the resource's default order, not to\n // whatever order the provider happens to use.\n setResourceSort(page.sort ?? defaultSort);\n }, [resourceServerPaging, page.sort, defaultSort, setResourceSort]);\n\n const statusField = statusFilter\n ? typeof statusFilter === \"string\"\n ? statusFilter\n : statusFilter.field\n : undefined;\n const defaultFilters = resourceOptions?.defaultFilters;\n const pushedStatusRef = useRef<string>(\"\");\n useEffect(() => {\n if (!resourceServerPaging || !statusField) return;\n // `defaultFilters` is part of the key: useResource re-syncs its filters\n // to a changed `defaultFilters` (dropping the status filter), so a\n // change there must re-push even when the chips did not move.\n const key = JSON.stringify([page.statusValue, defaultFilters ?? null]);\n if (key === pushedStatusRef.current) return;\n pushedStatusRef.current = key;\n setResourceFilters([\n ...(defaultFilters ?? []),\n ...(page.statusValue.length > 0\n ? [{ field: statusField, operator: \"in\" as const, value: page.statusValue }]\n : []),\n ]);\n }, [\n resourceServerPaging,\n statusField,\n page.statusValue,\n defaultFilters,\n setResourceFilters,\n ]);\n\n // ── `pagination=\"client\"`: say so when the resource outgrew the fetch ──\n const clientTruncated =\n isClientMode &&\n !resourceServerPaging &&\n !isLoading &&\n !hasError &&\n displayTotal > displayData.length;\n const warnedTruncatedRef = useRef(false);\n useEffect(() => {\n if (!clientTruncated || warnedTruncatedRef.current) return;\n warnedTruncatedRef.current = true;\n console.warn(\n `ResourcePage: \"${resourceName}\" has ${displayTotal} rows but only ${displayData.length} were fetched. ` +\n `Pass \\`pagination=\"server\"\\` to page through all of them, or raise \\`clientRowLimit\\` ` +\n `(no higher than the provider's \\`maxPerPage\\`, which refuses a larger page).`,\n );\n }, [clientTruncated, resourceName, displayTotal, displayData.length]);\n // ── Build ResourceActions for column render functions ──\n const actions: ResourceActions<T> = useMemo(() => {\n if (isClientMode) {\n return {\n update: resourceHook.update as ResourceActions<T>[\"update\"],\n remove: resourceHook.remove,\n refetch: () => resourceHook.list.refetch(),\n };\n }\n return {\n update: async () => {\n throw new Error(\n \"ResourceActions.update not available in server-data mode\",\n );\n },\n remove: async () => {\n throw new Error(\n \"ResourceActions.remove not available in server-data mode\",\n );\n },\n refetch: () => {\n /* no-op in server-data mode */\n },\n };\n }, [\n isClientMode,\n resourceHook.update,\n resourceHook.remove,\n resourceHook.list,\n ]);\n\n // ── Row identity ──\n const keyOf = useCallback(\n (item: T): string =>\n getKeyProp ? getKeyProp(item) : String((item as Record<string, unknown>).id ?? \"\"),\n [getKeyProp],\n );\n\n // ── The peek's row, kept live ──\n // `page.selectedItem` is a snapshot taken at click time. Re-resolving it by\n // key against the current rows means a save (which refetches) shows its\n // new values in the open peek instead of the pre-edit copy. A row missing\n // from the current rows keeps the snapshot: paging, sorting, search and\n // filters all drop rows that still exist. A confirmed delete closes the\n // peek itself (`performDelete`).\n // An empty key (rows with no `id` and no `getKey`) identifies nothing, so\n // it keeps the snapshot rather than matching the first keyless row.\n // With `urlState` the URL names the open record (`?id=`): a link opens it,\n // and Back closes it. The click-time snapshot still covers a record that\n // isn't in the current rows.\n const snapshotKey = page.selectedItem ? keyOf(page.selectedItem) : null;\n const selectedKey = urlPeek ? urlPeek.detailId : snapshotKey;\n const snapshot =\n page.selectedItem && snapshotKey === selectedKey ? page.selectedItem : null;\n const rowOrSnapshot: T | null = !selectedKey\n ? snapshot\n : (displayData.find((row) => keyOf(row) === selectedKey) ?? snapshot);\n // A linked record that isn't in the loaded rows (another page, outside the\n // search) is fetched on its own; one that can't be read shows as missing.\n const linkedId = urlPeek && selectedKey && !rowOrSnapshot ? selectedKey : null;\n const linked = useOne<T & BaseRecord>(resourceName ?? \"__noop__\", linkedId, {\n enabled: isClientMode && !!linkedId,\n });\n const selectedItem: T | null =\n rowOrSnapshot ?? (linkedId && linked.data ? (linked.data as T) : null);\n // Missing only when that is known: the fetch failed (resource mode), or\n // `data` is the whole set (data mode without server paging). A record\n // absent from one server-controlled page may be on another.\n const linkMissing =\n !!linkedId &&\n !selectedItem &&\n !isLoading &&\n (isClientMode ? linked.isError : !isServerControlled);\n const detailOpen = urlPeek ? selectedItem !== null || linkMissing : page.detailOpen;\n\n // ── Bulk selection ──\n const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set());\n\n const handleToggleSelect = useCallback((id: string) => {\n setSelectedIds((prev) => {\n const next = new Set(prev);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n return next;\n });\n }, []);\n\n const handleToggleAll = useCallback(() => {\n setSelectedIds((prev) => {\n if (prev.size === page.data.length) return new Set();\n return new Set(page.data.map(keyOf));\n });\n }, [page.data, keyOf]);\n\n const handleClearSelection = useCallback(() => {\n setSelectedIds(new Set());\n }, []);\n\n // ── Built-in form state ──\n const [formOpen, setFormOpen] = useState(false);\n const [formAction, setFormAction] = useState<\"create\" | \"edit\">(\"create\");\n const [formItem, setFormItem] = useState<T | null>(null);\n\n // Determine if built-in form should handle create/edit\n const useBuiltInCreate = allowCreate && !onCreate && isClientMode;\n const useBuiltInEdit = allowEdit && !onEdit && isClientMode;\n\n const handleCreate = useCallback(() => {\n if (useBuiltInCreate) {\n setFormAction(\"create\");\n setFormItem(null);\n setFormOpen(true);\n } else if (onCreate) {\n onCreate();\n }\n }, [useBuiltInCreate, onCreate]);\n\n // One permission check: `can`, then the deprecated per-row predicates.\n const allows = useCallback(\n (action: ResourceAction, item?: T): boolean => {\n if (can && !can(action, item)) return false;\n if (!item) return true;\n if (canEditItem && !canEditItem(item)) return false;\n if (action === \"edit\" && canEdit && !canEdit(item)) return false;\n if (action === \"delete\" && canDelete && !canDelete(item)) return false;\n return true;\n },\n [can, canEditItem, canEdit, canDelete],\n );\n\n const handleEdit = useCallback(\n (item: T) => {\n if (!allows(\"edit\", item)) return;\n if (useBuiltInEdit) {\n setFormAction(\"edit\");\n setFormItem(item);\n setFormOpen(true);\n } else if (onEdit) {\n onEdit(item);\n }\n },\n [useBuiltInEdit, onEdit, allows],\n );\n\n const closeDetail = useCallback(() => {\n page.setDetailOpen(false);\n page.setSelectedItem(null);\n urlPeek?.setDetailId(null);\n }, [page, urlPeek]);\n\n // ── Delete: built-in, confirmed, or the caller's as-is ──\n const useBuiltInDelete = !!allowDelete && !onDelete && isClientMode;\n const deleteConfirmed =\n confirmDelete === undefined ? useBuiltInDelete : !!confirmDelete;\n const deleteCopy =\n typeof confirmDelete === \"object\" ? confirmDelete : undefined;\n // The row being confirmed, kept after the dialog closes so its copy does\n // not flip to the defaults during the exit animation; `deleteOpen` is what\n // actually opens and closes it.\n const [pendingDelete, setPendingDelete] = useState<T | null>(null);\n const [deleteOpen, setDeleteOpen] = useState(false);\n const { remove: removeRecord } = resourceHook;\n // A recycle-bin resource says so in the confirm step instead of \"can't be undone\".\n const { data: providerCaps } = useCapabilities(resourceName, {\n enabled: useBuiltInDelete && deleteConfirmed,\n });\n const deleteKind: \"recycle\" | \"permanent\" = providerCaps?.softDelete ? \"recycle\" : \"permanent\";\n\n const performDelete = useCallback(\n async (item: T) => {\n if (useBuiltInDelete) {\n // A caller-supplied `getKey` (e.g. `encodeRecordKey` for a composite\n // key) is the row's identity to the provider too; otherwise `id`.\n await removeRecord(\n (getKeyProp\n ? keyOf(item)\n : (item as Record<string, unknown>).id) as Identifier,\n );\n } else if (onDelete) {\n await onDelete(item);\n }\n closeDetail();\n onDeleted?.(item);\n },\n [\n useBuiltInDelete,\n removeRecord,\n getKeyProp,\n keyOf,\n onDelete,\n closeDetail,\n onDeleted,\n ],\n );\n\n const deleteHandler: ((item: T) => void) | undefined = !(\n useBuiltInDelete || onDelete\n )\n ? undefined\n : deleteConfirmed\n ? (item: T) => {\n setPendingDelete(item);\n setDeleteOpen(true);\n }\n : useBuiltInDelete\n ? (item: T) => {\n performDelete(item).catch((err: unknown) => {\n // useResource has already handed the failure to\n // `resourceOptions.onError`; without one, the user is told.\n if (!resourceOptions?.onError) {\n toast.error(err instanceof Error ? err.message : \"The delete failed.\");\n }\n });\n }\n : // Unconfirmed `onDelete` keeps its original contract exactly:\n // called straight from the peek, nothing closed for it.\n (item: T) => {\n // A throw or a rejected promise is reported, never left unhandled,\n // even when `onError` itself throws (the toast is the fallback).\n const report = (err: unknown) => {\n const error = err instanceof Error ? err : new Error(String(err));\n if (resourceOptions?.onError) {\n try {\n resourceOptions.onError(error);\n return;\n } catch {\n // fall through to the toast\n }\n }\n toast.error(error.message || \"The delete failed.\");\n };\n // Called right away, as before; a throw or a rejection is reported.\n try {\n Promise.resolve(onDelete?.(item)).catch(report);\n } catch (err) {\n report(err);\n }\n };\n\n // Per-row rights, evaluated against the row the peek is showing.\n const selectedEditable = !!selectedItem && allows(\"edit\", selectedItem);\n const selectedDeletable = !!selectedItem && allows(\"delete\", selectedItem);\n\n // ── Patch tableColumns to use real actions (client-side mode) ──\n const tableColumns = useMemo(() => {\n const base = isClientMode\n ? page.columns.map((col) => ({\n key: col.key,\n header: col.header ?? col.key,\n sortable: col.sortable ?? true,\n hideBelow: col.hideBelow,\n width: col.width,\n minWidth: col.minWidth,\n defaultVisible: col.defaultVisible,\n editable: col.editable,\n accessor: col.accessor,\n render: col.render\n ? (item: T, value: unknown) => col.render!(item, value, actions)\n : undefined,\n }))\n : page.tableColumns;\n if (!isServerControlled) return base;\n // The server owns the ordering. DataTable's header sort is client-side\n // and would only reorder the rows of the current page — a visibly wrong\n // answer presented as a sort — so the affordance is withdrawn rather\n // than left to lie. The DataFilters sort control drives `onSortChange`.\n return base.map((col) => ({ ...col, sortable: false }));\n }, [\n isClientMode,\n isServerControlled,\n page.columns,\n page.tableColumns,\n actions,\n ]);\n\n // ── Client mode: DataTable's header sort is `page.sort` ──\n // The primary header sort is the page's sort (and so the URL's); Shift-\n // click tie-breakers are kept here while that primary still matches, and\n // dropped when the sort changes elsewhere (the sort select, the URL).\n const [tableTieBreaks, setTableTieBreaks] = useState<{\n primary: string;\n rest: DataTableSort[];\n } | null>(null);\n const pageSort = page.sort;\n const setPageSort = page.setSort;\n const tableSort = useMemo<DataTableSort[]>(() => {\n if (!pageSort) return [];\n const primary: DataTableSort = { key: pageSort.field, dir: pageSort.order };\n const rest =\n tableTieBreaks && tableTieBreaks.primary === `${primary.key}:${primary.dir}`\n ? tableTieBreaks.rest\n : [];\n // Only the table's own columns: a sort-select option or a URL sort on a\n // field the table doesn't show still orders the rows (page.sort), but is\n // not a header sort.\n return [primary, ...rest].filter((s) => tableColumns.some((c) => c.key === s.key));\n }, [pageSort, tableTieBreaks, tableColumns]);\n const handleTableSort = useCallback(\n (next: DataTableSort[]) => {\n const [primary, ...rest] = next;\n setTableTieBreaks(primary ? { primary: `${primary.key}:${primary.dir}`, rest } : null);\n setPageSort(primary ? { field: primary.key, order: primary.dir } : null);\n },\n [setPageSort],\n );\n\n // ── Server-driven pager state, needed above for handleSearchChange's\n // already-on-page-1 check. ──\n // The pager's inputs: the caller's controlled props, or — for\n // `pagination=\"server\"` — useResource's own page state.\n const pagerPage = resourceServerPaging\n ? (resourceHook.params.pagination?.page ?? 1)\n : pageProp;\n const pagerPerPage = resourceServerPaging\n ? resourceHook.params.pagination?.perPage\n : perPageProp;\n const pagerTotal = resourceServerPaging ? displayTotal : totalProp;\n const pagerOnPageChange = resourceServerPaging\n ? resourceHook.setPage\n : onPageChange;\n const currentPage = pagerPage ?? 1;\n\n // ── `urlState`: write search, sort and (server paging) page back ──\n // Replace-only, so Back steps through opened records rather than every\n // keystroke; an unchanged URL is not rewritten.\n const writeUrl = url?.write;\n useEffect(() => {\n writeUrl?.({\n q: page.search,\n sort: page.sort,\n ...(resourceServerPaging ? { page: currentPage } : {}),\n });\n }, [writeUrl, page.search, page.sort, currentPage, resourceServerPaging]);\n\n // ── Filter changes: keep the controlled UI state, and tell the server ──\n // In client-side mode these are exactly the hook's own setters; in\n // server-controlled mode they additionally notify the caller and reset to\n // page 1, since the previous page number is meaningless against a new\n // query. The reset is skipped when already on page 1 — nothing changed,\n // so there is nothing for the caller to do.\n const handleSearchChange = useCallback(\n (value: string) => {\n page.filterConfig.onSearchChange(value);\n if (!isServerControlled) return;\n onSearchChange?.(value);\n // `pagination=\"server\"`: useResource's setSearch resets the page\n // itself once the debounce settles; resetting here too would fetch\n // page 1 of the OLD query first.\n if (currentPage !== 1 && !resourceServerPaging) onPageChange?.(1);\n },\n [\n page.filterConfig,\n isServerControlled,\n onSearchChange,\n onPageChange,\n resourceServerPaging,\n currentPage,\n ],\n );\n\n const handleSortSelect = useCallback(\n (value: string) => {\n page.filterConfig.onSortChange(value);\n if (!isServerControlled) return;\n const [field, order] = value.split(\":\");\n onSortChange?.(\n field && (order === \"asc\" || order === \"desc\")\n ? { field, order }\n : null,\n );\n // See handleSearchChange: useResource's setSort resets the page.\n if (!resourceServerPaging) onPageChange?.(1);\n },\n [\n page.filterConfig,\n isServerControlled,\n onSortChange,\n onPageChange,\n resourceServerPaging,\n ],\n );\n\n const handleClearFilters = useCallback(() => {\n page.clearFilters();\n if (!isServerControlled) return;\n // Clearing has to reach the server too — otherwise \"Clear all\" empties\n // the controls and leaves the same rows on screen.\n onSearchChange?.(\"\");\n onSortChange?.(null);\n if (!resourceServerPaging) onPageChange?.(1);\n }, [\n page,\n isServerControlled,\n onSearchChange,\n onSortChange,\n onPageChange,\n resourceServerPaging,\n ]);\n\n // ── Status-chip changes: same page-1 reset as search/sort ──\n // In server-controlled mode `useResourcePage` skips client-side status\n // filtering, so a status change only reaches the caller through\n // `onFiltersChange`. Nothing else calls `onPageChange(1)` for it, so\n // selecting a more restrictive status while on page 3 could otherwise\n // fetch page 3 of the new result set and render an empty page while the\n // matching rows sit on page 1. Guarded the same way as\n // `handleSearchChange`, and not reachable from `handleClearFilters`\n // (which already does its own single reset).\n const handleStatusChange = useCallback(\n (values: string[]) => {\n page.filterConfig.statusChips?.onChange(values);\n if (!isServerControlled) return;\n if (currentPage !== 1 && !resourceServerPaging) onPageChange?.(1);\n },\n [\n page.filterConfig,\n isServerControlled,\n onPageChange,\n resourceServerPaging,\n currentPage,\n ],\n );\n\n const statusChipsConfig = useMemo(() => {\n const base = page.filterConfig.statusChips;\n if (!base) return undefined;\n return { ...base, onChange: handleStatusChange };\n }, [page.filterConfig.statusChips, handleStatusChange]);\n\n const handlePageSizeChange = useCallback(\n (size: number) => {\n updateSetting(\"pageSize\", size);\n onPerPageChange?.(size);\n // useResource's setPerPage resets to page 1 itself.\n if (resourceServerPaging) resourceHook.setPerPage(size);\n else if (isServerControlled) onPageChange?.(1);\n },\n [\n updateSetting,\n onPerPageChange,\n resourceServerPaging,\n resourceHook.setPerPage,\n isServerControlled,\n onPageChange,\n ],\n );\n\n // ── Pagination-config error ──\n // `perPage` AND `total` are both required whenever `onPageChange` is\n // supplied. Neither can be derived from the other, and neither can be\n // derived from the rows:\n // - `perPage`: see the prop doc on `perPage`. A short final page has\n // fewer rows than the page size, so the row count of a page cannot\n // stand in for the page size.\n // - `total`: `displayTotal` falls back to `0` (Line 453). With `total`\n // omitted the range span reads \"No records\" and `Next` stays\n // disabled, while `page.data` renders rows directly below it. A\n // surface that says \"no records\" above visible records is a lie, not\n // a degraded view.\n // Rather than silently guess either one, the pager below refuses to\n // render and shows the error instead. Logged once per mount (not on\n // every render) so it's visible in a console without spamming it.\n const missingPerPage =\n isServerControlled && !!pagerOnPageChange && pagerPerPage === undefined;\n const missingTotal =\n isServerControlled && !!pagerOnPageChange && pagerTotal === undefined;\n const pagerMisconfigured = missingPerPage || missingTotal;\n const missingPagerProps = [\n ...(missingPerPage ? [\"perPage\"] : []),\n ...(missingTotal ? [\"total\"] : []),\n ];\n const loggedMissingPerPageRef = useRef(false);\n useEffect(() => {\n if (!pagerMisconfigured) return;\n if (loggedMissingPerPageRef.current) return;\n loggedMissingPerPageRef.current = true;\n console.error(\n `ResourcePage: ${missingPagerProps\n .map((name) => `\\`${name}\\``)\n .join(\" and \")} ${\n missingPagerProps.length > 1 ? \"are\" : \"is\"\n } required when \\`onPageChange\\` is supplied.`,\n );\n // `missingPagerProps` is derived from `pagerMisconfigured`'s own inputs\n // and the ref makes this run at most once, so it is not a dependency.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [pagerMisconfigured]);\n\n // ── Server-driven pager math ──\n // By the time the pager renders, `pagerMisconfigured` has already gated\n // it off, so `perPageProp` and `totalProp` are both present here.\n const pagerPageSize = pagerPerPage ?? effectivePageSize;\n const totalPages = Math.max(\n 1,\n Math.ceil(displayTotal / Math.max(1, pagerPageSize)),\n );\n const rangeFrom =\n page.data.length === 0 ? 0 : (currentPage - 1) * pagerPageSize + 1;\n const rangeTo = rangeFrom === 0 ? 0 : rangeFrom + page.data.length - 1;\n\n // ── `pagination=\"server\"`: never strand the user past the last page ──\n // Deleting the last row of the last page (or any shrink in `total`) would\n // otherwise leave `page` beyond the end: the list comes back empty, the\n // shell swaps in its empty state — pager included — and there is no way\n // back. Step back to the real last page instead.\n const { setPage: setResourcePage } = resourceHook;\n const settledPage =\n !isLoading && !hasError && !resourceHook.list.isPlaceholderData;\n useEffect(() => {\n if (!resourceServerPaging || !settledPage) return;\n if (currentPage > totalPages) setResourcePage(totalPages);\n }, [resourceServerPaging, settledPage, currentPage, totalPages, setResourcePage]);\n\n // ── Detail title/subtitle values ──\n const titleOf = (item: T): string =>\n getTitle\n ? getTitle(item)\n : String((item as Record<string, unknown>)[page.titleField] ?? \"\");\n const detailTitle = selectedItem ? titleOf(selectedItem) : \"\";\n const detailSubtitle = !selectedItem\n ? undefined\n : getSubtitle\n ? getSubtitle(selectedItem)\n : page.subtitleField\n ? String(\n (selectedItem as Record<string, unknown>)[page.subtitleField] ?? \"\",\n )\n : undefined;\n\n // ── Row click handler (route mode navigates) ──\n const handleRowClick = (item: T) => {\n if (detail === \"route\") {\n // Navigate to /{resource}/{id}\n const id = (item as Record<string, unknown>).id;\n if (resourceName && id) {\n onNavigate(`/${resourceName}/${id}`);\n }\n return;\n }\n page.handleRowClick(item);\n urlPeek?.setDetailId(keyOf(item));\n };\n\n // ── Keyboard navigation (j/k, Enter, Backspace, x) ──\n // Only engaged for grid/list views: table view runs its own independent\n // client-side sort + pagination (DataTable), so a flat index into\n // `page.data` can't reliably be mapped back onto its currently-visible,\n // possibly differently-ordered rows.\n const hasBulkSelect = !!bulkActions && bulkActions.length > 0;\n // A detail panel/modal or the built-in form is covering the list. Cursor\n // keys suspend (they'd otherwise drive the list behind the overlay, and\n // Enter would re-open the row instead of activating the focused control);\n // ⌫ stays live so it can dismiss the overlay.\n const overlayOpen = detailOpen || formOpen || deleteOpen;\n const keyboardNav = useKeyboardNavigation({\n itemCount: page.data.length,\n enabled: keyboardNavigation && page.viewMode !== \"table\",\n overlayOpen,\n onOpen: (index) => {\n const item = page.data[index];\n if (item) handleRowClick(item);\n },\n onToggleSelect: hasBulkSelect\n ? (index) => {\n const item = page.data[index];\n if (item) {\n handleToggleSelect(keyOf(item));\n }\n }\n : undefined,\n // Supplied only while there is an open detail to close — the hook\n // suppresses Backspace's default whenever this is present, so leaving it\n // wired up permanently would swallow the browser/app's Backspace on\n // every grid/list page (including detail=\"none\" and detail=\"route\",\n // which never open one). `detailOpen` is only ever true for the panel\n // and modal modes, so it is the precise precondition here.\n onBack: detailOpen ? closeDetail : undefined,\n });\n\n // ── Create button ──\n return {\n actions,\n allows,\n clientTruncated,\n closeDetail,\n currentPage,\n deleteConfirmed,\n deleteCopy,\n deleteHandler,\n deleteKind,\n deleteOpen,\n detailOpen,\n detailSubtitle,\n detailTitle,\n displayData,\n displayTotal,\n effectivePageSize,\n formAction,\n formItem,\n formOpen,\n handleClearFilters,\n handleClearSelection,\n handleCreate,\n handleEdit,\n handlePageSizeChange,\n handleRowClick,\n handleSearchChange,\n handleSortSelect,\n handleTableSort,\n handleToggleAll,\n handleToggleSelect,\n hasError,\n isClientMode,\n isLoading,\n isServerControlled,\n keyOf,\n keyboardNav,\n linkMissing,\n linked,\n missingPagerProps,\n page,\n pagerMisconfigured,\n pagerOnPageChange,\n pendingDelete,\n performDelete,\n rangeFrom,\n rangeTo,\n resourceHook,\n resourceServerPaging,\n selectedDeletable,\n selectedEditable,\n selectedIds,\n selectedItem,\n serverSearchFields,\n setDeleteOpen,\n setFormOpen,\n settings,\n statusChipsConfig,\n tableColumns,\n tableSort,\n titleOf,\n totalPages,\n updateSetting,\n useBuiltInCreate,\n useBuiltInDelete,\n useBuiltInEdit,\n };\n}\n\n/**\n * What {@link useResourceTable} returns: the list's rows and the handlers a\n * custom layout wires to its controls.\n *\n * @stability Beta\n */\nexport interface ResourceTableState<\n T extends Record<string, unknown> = Record<string, unknown>,\n> {\n // ── Rows ──\n /**\n * The rows to show: filtered and sorted. With `pagination=\"client\"` this\n * is every matching row (page it yourself); with server paging it is the\n * current page.\n */\n rows: T[];\n /** How many rows match, across all pages. */\n total: number;\n loading: boolean;\n /** The read failed. */\n error: boolean;\n /** True when more than `clientRowLimit` rows exist and only that many were loaded. */\n truncated: boolean;\n /** The columns, resolved to DataTable's format. */\n columns: DataTableColumn<T>[];\n /** Write actions for cell renderers (update, remove, …). */\n actions: ResourceActions<T>;\n /** A row's identity: `getKey`, else its `id`. */\n getKey: (item: T) => string;\n /** A row's title: `getTitle`, else its title field. */\n getTitle: (item: T) => string;\n /** The page's permission check (`can`, then the deprecated per-row predicates). */\n can: (action: ResourceAction, item?: T) => boolean;\n\n // ── Search, sort and filters ──\n search: string;\n setSearch: (value: string) => void;\n /** Sort keys, primary first. */\n sort: DataTableSort[];\n setSort: (sort: DataTableSort[]) => void;\n /** The status filter's choices, its selected values and its setter, when the list has one. */\n statusFilter:\n | { options: string[]; selected: string[]; onChange: (values: string[]) => void }\n | undefined;\n hasActiveFilters: boolean;\n clearFilters: () => void;\n\n // ── Paging (server or caller-controlled paging) ──\n /** The current page, from 1. */\n page: number;\n pageCount: number;\n pageSize: number;\n setPageSize: (size: number) => void;\n /** Go to a page; undefined when the page is not controlled (client paging). */\n setPage: ((page: number) => void) | undefined;\n /** The 1-based range of the rows shown, for \"21–40 of 95\"; 0 when empty. */\n rangeFrom: number;\n rangeTo: number;\n\n // ── Selection ──\n selectedIds: Set<string>;\n toggleSelected: (id: string) => void;\n toggleAll: () => void;\n clearSelection: () => void;\n\n // ── The open record ──\n /** The open row, kept current as the data changes. */\n openItem: T | null;\n detailOpen: boolean;\n /** What clicking a row does: opens the peek, modal or route. */\n openRow: (item: T) => void;\n closeDetail: () => void;\n /** A record linked by URL that does not exist (or was deleted). */\n openItemMissing: boolean;\n\n // ── Create and edit ──\n /** Undefined when the page cannot create. */\n create: (() => void) | undefined;\n edit: (item: T) => void;\n /** The built-in form's state, for rendering your own form. */\n form: {\n open: boolean;\n setOpen: (open: boolean) => void;\n action: \"create\" | \"edit\";\n /** The row being edited; null when creating. */\n item: T | null;\n };\n\n // ── Delete ──\n /** Delete a row: asks first when the delete is confirmed. Undefined when the page cannot delete. */\n remove: ((item: T) => void) | undefined;\n /** The confirm step's state, when `remove` asks first. */\n deleteConfirm: {\n open: boolean;\n setOpen: (open: boolean) => void;\n /** The row being confirmed (kept through the close animation). */\n item: T | null;\n /** Run the delete; rejects with the failure. */\n confirm: () => Promise<void>;\n /** \"recycle\" when the provider soft-deletes, so the copy can say it can be restored. */\n kind: \"recycle\" | \"permanent\";\n copy: ResourceDeleteConfirmCopy<T> | undefined;\n };\n}\n\n/**\n * The list behind {@link ResourcePage}, without any markup: where the rows\n * come from (a `resource` through the data provider, or `data` you pass),\n * search, sort, status filter and paging, selection, the open record (and\n * its URL state), the built-in create/edit form and confirmed delete, and\n * the row handlers. Takes the same options as `ResourcePage`.\n *\n * Use it to build a different layout over the same behaviour; `ResourcePage`\n * itself is this behaviour plus Genesis's markup.\n *\n * @stability Beta\n */\nexport function useResourceTable<\n T extends Record<string, unknown> = Record<string, unknown>,\n>(props: ResourcePageProps<T>): ResourceTableState<T> {\n const m = useResourceTableModel<T>(props);\n const { pendingDelete, performDelete } = m;\n const confirm = useCallback(\n () => (pendingDelete ? performDelete(pendingDelete) : Promise.resolve()),\n [pendingDelete, performDelete],\n );\n return {\n rows: m.page.data,\n total: m.page.total,\n loading: m.isLoading,\n error: m.hasError,\n truncated: m.clientTruncated,\n columns: m.tableColumns,\n actions: m.actions,\n getKey: m.keyOf,\n getTitle: m.titleOf,\n can: m.allows,\n search: m.page.search,\n setSearch: m.handleSearchChange,\n sort: m.tableSort,\n setSort: m.handleTableSort,\n statusFilter: m.statusChipsConfig,\n hasActiveFilters: m.page.hasActiveFilters,\n clearFilters: m.handleClearFilters,\n page: m.currentPage,\n pageCount: m.totalPages,\n pageSize: m.effectivePageSize,\n setPageSize: m.handlePageSizeChange,\n setPage: m.pagerOnPageChange,\n rangeFrom: m.rangeFrom,\n rangeTo: m.rangeTo,\n selectedIds: m.selectedIds,\n toggleSelected: m.handleToggleSelect,\n toggleAll: m.handleToggleAll,\n clearSelection: m.handleClearSelection,\n openItem: m.selectedItem,\n detailOpen: m.detailOpen,\n openRow: m.handleRowClick,\n closeDetail: m.closeDetail,\n openItemMissing: m.linkMissing,\n create: m.useBuiltInCreate || props.onCreate ? m.handleCreate : undefined,\n edit: m.handleEdit,\n form: {\n open: m.formOpen,\n setOpen: m.setFormOpen,\n action: m.formAction,\n item: m.formItem,\n },\n remove: m.deleteHandler,\n deleteConfirm: {\n open: m.deleteOpen,\n setOpen: m.setDeleteOpen,\n item: pendingDelete,\n confirm,\n kind: m.deleteKind,\n copy: m.deleteCopy,\n },\n };\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/option-storage.ts","../src/components/layout/PageHeader.tsx","../src/components/layout/AppShell.tsx"],"names":["readStoredOptions","OPTION_DEFAULTS","useState","useEffect","jsx","jsxs","Fragment","useId","useMemo","useCallback","SlidersHorizontal"],"mappings":"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","file":"chunk-UYI3GLFJ.js","sourcesContent":["/**\n * Generic localStorage-backed persistence for \"customize chrome\" option\n * objects (AppShell, PageHeader, …). SSR-safe (no-ops without `window`) and\n * swallows quota / private-mode errors so a storage failure never breaks\n * rendering.\n *\n * Callers own their own shape validation — this module only handles the\n * JSON <-> localStorage plumbing shared across chrome components.\n */\nexport function readStoredOptions<T extends object>(key: string): Partial<T> {\n if (typeof window === \"undefined\") return {};\n try {\n const raw = localStorage.getItem(key);\n if (!raw) return {};\n const parsed = JSON.parse(raw) as unknown;\n if (!parsed || typeof parsed !== \"object\") return {};\n return parsed as Partial<T>;\n } catch {\n return {};\n }\n}\n\nexport function writeStoredOptions<T extends object>(\n key: string,\n value: Partial<T>,\n): void {\n if (typeof window === \"undefined\") return;\n try {\n localStorage.setItem(key, JSON.stringify(value));\n } catch {\n // quota / private mode\n }\n}\n","\"use client\";\n\nimport { useCallback, useEffect, useId, useMemo, useState, type ReactNode } from \"react\";\nimport type { LucideIcon } from \"lucide-react\";\nimport { ListFilter, MoreHorizontal, SlidersHorizontal } from \"lucide-react\";\nimport { Badge } from \"../ui/badge\";\nimport { Button } from \"../ui/button\";\nimport { Collapsible, CollapsibleContent } from \"../ui/collapsible\";\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from \"../ui/popover\";\nimport { Switch } from \"../ui/switch\";\nimport { Label } from \"../ui/label\";\nimport { ViewToggle, type ViewMode } from \"../patterns/view-toggle\";\nimport { ViewSettings } from \"../patterns/view-settings\";\nimport type { Density } from \"../../hooks/use-view-settings\";\nimport { cn } from \"../../utils\";\nimport {\n readStoredOptions as readStoredOptionsRaw,\n writeStoredOptions,\n} from \"../../option-storage\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from \"../ui/dropdown-menu\";\n\n/**\n * Declarative chrome for PageHeader — developer defaults + optional\n * in-header user toggles (Notion/Linear “customize view” pattern).\n *\n * @stability Beta\n */\nexport interface PageHeaderOptions {\n /**\n * The icon, title and subtitle block. Turn it off where the surrounding\n * page already names the content (a list inside a tab), keeping only the\n * actions row: count, view toggle, filters, create. Default true. A\n * developer setting, not offered in the user's Header options.\n */\n showTitle?: boolean;\n showIcon?: boolean;\n showSubtitle?: boolean;\n showCount?: boolean;\n showViewToggle?: boolean;\n showViewSettings?: boolean;\n showCreate?: boolean;\n /**\n * Stat cards row under the title block. Off by default — a header that\n * receives `stats` still hides them until the developer or the user turns\n * this on, so an existing page gains no new chrome by upgrading.\n */\n showStats?: boolean;\n /** Ghost ListFilter control in the actions cluster */\n showDetailsToggle?: boolean;\n /** Quiet hint beside actions while details are collapsed */\n showDetailsHint?: boolean;\n /** Move subtitle into the details panel (default true when details exist) */\n subtitleInDetails?: boolean;\n defaultDetailsOpen?: boolean;\n detailsLabel?: string;\n /**\n * Show the in-header Header options popover so users can customize chrome.\n * Default true when the header has more than one chrome affordance.\n */\n configurable?: boolean;\n}\n\n/** @stability Beta */\nexport type PageHeaderOptionKey = keyof PageHeaderOptions;\n\n/** Naive English pluralization for the count badge — singular at exactly 1. */\nfunction pluralizeEntity(entity: string, count: number): string {\n if (count === 1) return entity;\n return entity.endsWith(\"s\") ? entity : `${entity}s`;\n}\n\nconst OPTION_DEFAULTS: Required<\n Omit<PageHeaderOptions, \"detailsLabel\" | \"defaultDetailsOpen\" | \"subtitleInDetails\" | \"configurable\">\n> &\n Pick<PageHeaderOptions, \"detailsLabel\" | \"defaultDetailsOpen\" | \"subtitleInDetails\" | \"configurable\"> = {\n showTitle: true,\n showIcon: true,\n showSubtitle: true,\n showCount: true,\n showViewToggle: true,\n showViewSettings: true,\n showCreate: true,\n showStats: false,\n showDetailsToggle: true,\n showDetailsHint: true,\n subtitleInDetails: undefined,\n defaultDetailsOpen: false,\n detailsLabel: \"Details\",\n configurable: undefined,\n};\n\n// `showTitle` is left out on purpose: it is a developer setting, so a stored\n// user override must never hide the title.\nconst BOOLEAN_OPTION_KEYS: PageHeaderOptionKey[] = [\n \"showIcon\",\n \"showSubtitle\",\n \"showCount\",\n \"showViewToggle\",\n \"showViewSettings\",\n \"showCreate\",\n \"showStats\",\n \"showDetailsToggle\",\n \"showDetailsHint\",\n \"subtitleInDetails\",\n \"defaultDetailsOpen\",\n \"configurable\",\n];\nconst STRING_OPTION_KEYS: PageHeaderOptionKey[] = [\"detailsLabel\"];\n\n/**\n * Reads persisted options and keeps only known keys whose stored value has\n * the expected primitive type — a malformed or hand-edited localStorage\n * value can't smuggle in an unexpected key or wrong-typed override.\n */\nfunction readStoredOptions(key: string): Partial<PageHeaderOptions> {\n const raw = readStoredOptionsRaw<PageHeaderOptions>(key);\n const sanitized: Partial<PageHeaderOptions> = {};\n for (const optKey of BOOLEAN_OPTION_KEYS) {\n const value = raw[optKey];\n if (typeof value === \"boolean\") {\n (sanitized as Record<string, boolean>)[optKey] = value;\n }\n }\n for (const optKey of STRING_OPTION_KEYS) {\n const value = raw[optKey];\n if (typeof value === \"string\") {\n (sanitized as Record<string, string>)[optKey] = value;\n }\n }\n return sanitized;\n}\n\n/** One entry in {@link PageHeaderProps.secondaryActions}. */\nexport interface PageHeaderAction {\n label: string;\n onClick: () => void;\n icon?: LucideIcon;\n /** `data-testid` on the menu item, so e2e can drive it. */\n testId?: string;\n disabled?: boolean;\n /** Omits the action entirely — for one gated on data. */\n hidden?: boolean;\n}\n\nexport interface PageHeaderProps {\n title: string;\n subtitle?: string;\n icon?: LucideIcon;\n /**\n * Header chrome config (developer defaults). Merged under user picks from\n * the in-header options menu when `options.configurable` / storage is on.\n */\n options?: PageHeaderOptions;\n /** Persist user header-option overrides (localStorage) */\n optionsStorageKey?: string;\n /** Extra trailing actions (after create); prefer first-class slots below */\n actions?: ReactNode;\n /**\n * Stat cards row, full width, directly under the title block and above\n * `details`. Layout-only: pass `<StatCard>`s (or anything else) and the\n * header positions them. Rendered only when `options.showStats` resolves\n * true — see {@link PageHeaderOptions.showStats}.\n */\n stats?: ReactNode;\n /** Collapsible details region below the title row */\n details?: ReactNode;\n detailsOpen?: boolean;\n onDetailsOpenChange?: (open: boolean) => void;\n detailsActive?: boolean;\n detailsHint?: ReactNode;\n /** Count badge */\n count?: number;\n totalCount?: number;\n /** Singular entity for “N rows” copy when unfiltered */\n entityName?: string;\n countActive?: boolean;\n viewMode?: ViewMode;\n onViewModeChange?: (mode: ViewMode) => void;\n pageSize?: number;\n onPageSizeChange?: (size: number) => void;\n density?: Density;\n onDensityChange?: (density: Density) => void;\n createAction?: ReactNode;\n /**\n * Additional actions, rendered in ONE overflow menu — never as more\n * side-by-side buttons.\n *\n * The budget is the point. A header with three top-level buttons squeezes\n * its own title to an ellipsis at real viewport widths, so a surface that\n * genuinely has four actions needs somewhere to put the other three. Before\n * this existed the only place was a fork of the header, which is exactly\n * what one consumer did.\n *\n * Pass `ReactNode` via `actions` instead when you need arbitrary chrome;\n * this prop is for the ordinary case, and it keeps the budget for you.\n */\n secondaryActions?: PageHeaderAction[];\n}\n\ntype ToggleDef = {\n key: keyof PageHeaderOptions;\n label: string;\n available: boolean;\n};\n\nexport function PageHeader({\n title,\n subtitle,\n icon: Icon,\n options: optionsProp,\n optionsStorageKey,\n actions,\n stats,\n details,\n detailsOpen,\n onDetailsOpenChange,\n detailsActive = false,\n detailsHint,\n count,\n totalCount,\n entityName,\n countActive = false,\n viewMode,\n onViewModeChange,\n pageSize,\n onPageSizeChange,\n density,\n onDensityChange,\n createAction,\n secondaryActions,\n}: PageHeaderProps) {\n const detailsRegionId = useId();\n const hasDetails = details != null;\n const hasStats = stats != null;\n const hasCount = count !== undefined && totalCount !== undefined;\n const hasViewToggle = Boolean(viewMode && onViewModeChange);\n const hasViewSettings = Boolean(onPageSizeChange && onDensityChange);\n const hasCreate = createAction != null;\n // `hidden` is filtered here rather than at the call site: an action gated on\n // data (\"Review drafts\", only when drafts exist) is the common case, and a\n // conditional array at every call site is what makes those call sites drift.\n const visibleSecondary = (secondaryActions ?? []).filter((a) => !a.hidden);\n\n const [userOverrides, setUserOverrides] = useState<Partial<PageHeaderOptions>>(\n {},\n );\n // Tracks which storage key the current overrides were hydrated from, so a\n // key change (routing between pages with distinct keys while this header\n // stays mounted) can't flush the previous key's overrides into the new key\n // before the read effect re-hydrates.\n const [hydratedKey, setHydratedKey] = useState<string | undefined>(\n optionsStorageKey ? undefined : \"\",\n );\n\n useEffect(() => {\n if (!optionsStorageKey) {\n setUserOverrides({});\n setHydratedKey(\"\");\n return;\n }\n setUserOverrides(readStoredOptions(optionsStorageKey));\n setHydratedKey(optionsStorageKey);\n }, [optionsStorageKey]);\n\n useEffect(() => {\n // Persist only once overrides belong to the current key (see hydratedKey).\n if (!optionsStorageKey || hydratedKey !== optionsStorageKey) return;\n writeStoredOptions(optionsStorageKey, userOverrides);\n }, [optionsStorageKey, userOverrides, hydratedKey]);\n\n const resolved = useMemo(() => {\n const merged: PageHeaderOptions = {\n ...OPTION_DEFAULTS,\n ...optionsProp,\n ...userOverrides,\n };\n if (merged.subtitleInDetails === undefined) {\n merged.subtitleInDetails = hasDetails;\n }\n if (merged.configurable === undefined) {\n merged.configurable =\n hasDetails || hasStats || hasCount || hasViewSettings || hasViewToggle;\n }\n return merged;\n }, [\n optionsProp,\n userOverrides,\n hasDetails,\n hasStats,\n hasCount,\n hasViewSettings,\n hasViewToggle,\n ]);\n\n const patchOption = useCallback((key: keyof PageHeaderOptions, value: boolean) => {\n setUserOverrides((prev) => ({ ...prev, [key]: value }));\n }, []);\n\n const moveSubtitle = Boolean(resolved.subtitleInDetails) && hasDetails;\n const showTitleSubtitle =\n Boolean(subtitle) &&\n Boolean(resolved.showSubtitle) &&\n !moveSubtitle;\n\n const [uncontrolledOpen, setUncontrolledOpen] = useState(\n () => optionsProp?.defaultDetailsOpen ?? OPTION_DEFAULTS.defaultDetailsOpen!,\n );\n const isControlled = detailsOpen !== undefined;\n const open = isControlled ? detailsOpen! : uncontrolledOpen;\n\n const setOpen = (next: boolean) => {\n if (!isControlled) setUncontrolledOpen(next);\n onDetailsOpenChange?.(next);\n };\n\n const detailsLabel = resolved.detailsLabel ?? \"Details\";\n const entity = entityName || \"item\";\n\n const toggles: ToggleDef[] = (\n [\n { key: \"showIcon\", label: \"Icon\", available: Boolean(Icon) },\n {\n key: \"showSubtitle\",\n label: \"Subtitle\",\n available: Boolean(subtitle) && !moveSubtitle,\n },\n { key: \"showCount\", label: \"Count\", available: hasCount },\n { key: \"showViewToggle\", label: \"View toggle\", available: hasViewToggle },\n {\n key: \"showViewSettings\",\n label: \"Display settings\",\n available: hasViewSettings,\n },\n { key: \"showCreate\", label: \"Create action\", available: hasCreate },\n { key: \"showStats\", label: \"Stat cards\", available: hasStats },\n {\n key: \"showDetailsToggle\",\n label: \"Filters / details\",\n available: hasDetails,\n },\n {\n key: \"showDetailsHint\",\n label: \"Collapsed hint\",\n available: hasDetails && detailsHint != null,\n },\n ] as const satisfies readonly ToggleDef[]\n ).filter((t) => t.available);\n\n const showDetailsToggle =\n hasDetails && Boolean(resolved.showDetailsToggle);\n const showStats = hasStats && Boolean(resolved.showStats);\n const showHint =\n hasDetails &&\n !open &&\n Boolean(resolved.showDetailsHint) &&\n detailsHint != null;\n\n const actionsCluster = (\n <div className=\"flex items-center gap-1.5 shrink-0\">\n {showHint ? (\n <span className=\"hidden max-w-[14rem] truncate text-xs text-muted-foreground sm:inline\">\n {detailsHint}\n </span>\n ) : null}\n\n {hasCount && resolved.showCount !== false ? (\n <Badge variant=\"secondary\" className=\"text-xs\">\n {countActive\n ? `${count} of ${totalCount}`\n : `${totalCount} ${pluralizeEntity(entity, totalCount!)}`}\n </Badge>\n ) : null}\n\n {hasViewToggle && resolved.showViewToggle !== false ? (\n <ViewToggle viewMode={viewMode!} onViewModeChange={onViewModeChange!} />\n ) : null}\n\n {showDetailsToggle ? (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className={cn(\n \"relative h-8 w-8\",\n (open || detailsActive) && \"bg-accent text-accent-foreground\",\n )}\n onClick={() => setOpen(!open)}\n data-testid=\"page-header-details-toggle\"\n title={open ? `Hide ${detailsLabel}` : `Show ${detailsLabel}`}\n aria-label={open ? `Hide ${detailsLabel}` : `Show ${detailsLabel}`}\n aria-expanded={open}\n aria-controls={detailsRegionId}\n testID=\"page-header-details-toggle\"\n >\n <ListFilter className=\"h-4 w-4\" />\n {detailsActive ? (\n <span\n className=\"absolute right-1.5 top-1.5 size-1.5 rounded-full bg-primary\"\n aria-hidden\n />\n ) : null}\n </Button>\n ) : null}\n\n {hasViewSettings && resolved.showViewSettings !== false ? (\n <ViewSettings\n pageSize={pageSize ?? 25}\n onPageSizeChange={onPageSizeChange!}\n density={density ?? \"comfortable\"}\n onDensityChange={onDensityChange!}\n />\n ) : null}\n\n {hasCreate && resolved.showCreate !== false ? createAction : null}\n\n {visibleSecondary.length > 0 ? (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n aria-label=\"More actions\"\n data-testid=\"page-header-more-actions\"\n >\n <MoreHorizontal className=\"h-4 w-4\" aria-hidden=\"true\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n {visibleSecondary.map((action) => {\n const ActionIcon = action.icon;\n return (\n <DropdownMenuItem\n key={action.label}\n onSelect={action.onClick}\n disabled={action.disabled}\n data-testid={action.testId}\n >\n {ActionIcon ? (\n <ActionIcon className=\"mr-2 h-4 w-4\" aria-hidden=\"true\" />\n ) : null}\n {action.label}\n </DropdownMenuItem>\n );\n })}\n </DropdownMenuContent>\n </DropdownMenu>\n ) : null}\n\n {actions}\n\n {resolved.configurable && toggles.length > 0 ? (\n <Popover>\n <PopoverTrigger asChild>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-8 w-8\"\n title=\"Header options\"\n aria-label=\"Header options\"\n data-testid=\"page-header-options\"\n testID=\"page-header-options\"\n >\n <SlidersHorizontal className=\"h-4 w-4\" />\n </Button>\n </PopoverTrigger>\n <PopoverContent align=\"end\" className=\"w-64 space-y-3\">\n <div>\n <h4 className=\"text-sm font-semibold\">Header options</h4>\n <p className=\"text-xs text-muted-foreground\">\n Customize this page header. Saved on this device when a storage\n key is set.\n </p>\n </div>\n <ul className=\"space-y-3\">\n {toggles.map((t) => {\n const checked = Boolean(resolved[t.key] ?? true);\n return (\n <li\n key={t.key}\n className=\"flex items-center justify-between gap-3\"\n >\n <Label\n htmlFor={`page-header-opt-${t.key}`}\n className=\"text-sm font-normal\"\n >\n {t.label}\n </Label>\n <Switch\n id={`page-header-opt-${t.key}`}\n checked={checked}\n onCheckedChange={(v) => patchOption(t.key, v)}\n />\n </li>\n );\n })}\n </ul>\n {optionsStorageKey && Object.keys(userOverrides).length > 0 ? (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"h-8 w-full text-xs\"\n onClick={() => setUserOverrides({})}\n data-testid=\"page-header-options-reset\"\n aria-label=\"Reset header options\"\n testID=\"page-header-options-reset\"\n >\n Reset to defaults\n </Button>\n ) : null}\n </PopoverContent>\n </Popover>\n ) : null}\n </div>\n );\n\n const titleRow = resolved.showTitle === false ? (\n <div\n data-testid=\"page-header-toolbar\"\n className=\"flex min-w-0 flex-wrap items-center justify-end gap-2\"\n >\n {actionsCluster}\n </div>\n ) : (\n <div className=\"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"flex items-center gap-3 min-w-0\">\n {Icon && resolved.showIcon !== false ? (\n <div className=\"flex h-10 w-10 shrink-0 items-center justify-center overflow-hidden rounded-xl bg-primary/10\">\n <Icon className=\"h-5 w-5 text-primary\" />\n </div>\n ) : null}\n <div className=\"min-w-0\">\n <h1\n data-testid=\"page-title\"\n className=\"truncate font-display text-xl font-bold tracking-tight sm:text-2xl\"\n >\n {title}\n </h1>\n {showTitleSubtitle ? (\n <p className=\"truncate text-sm text-muted-foreground\">{subtitle}</p>\n ) : null}\n </div>\n </div>\n {actionsCluster}\n </div>\n );\n\n const statsRow = showStats ? (\n <div\n data-testid=\"page-header-stats\"\n className=\"mt-3 grid gap-3 sm:grid-cols-2 lg:grid-cols-4\"\n >\n {stats}\n </div>\n ) : null;\n\n if (!hasDetails) {\n return (\n <>\n {titleRow}\n {statsRow}\n </>\n );\n }\n\n return (\n <Collapsible open={open} onOpenChange={setOpen}>\n {titleRow}\n {statsRow}\n <CollapsibleContent id={detailsRegionId} className=\"mt-3\">\n <div className=\"flex flex-col gap-3 rounded-lg border border-border bg-card/40 p-3 sm:p-4\">\n {moveSubtitle && subtitle && resolved.showSubtitle !== false ? (\n <p className=\"text-sm text-muted-foreground\">{subtitle}</p>\n ) : null}\n {details}\n </div>\n </CollapsibleContent>\n </Collapsible>\n );\n}\n","\"use client\";\n\nimport {\n type ReactNode,\n useCallback,\n useEffect,\n useId,\n useMemo,\n useState,\n} from \"react\";\nimport {\n Menu,\n X,\n Sun,\n Moon,\n SlidersHorizontal,\n PanelLeftClose,\n PanelLeft,\n ChevronDown,\n ArrowLeft,\n} from \"lucide-react\";\nimport type { LucideIcon } from \"lucide-react\";\nimport { Button } from \"../ui/button\";\nimport { Badge } from \"../ui/badge\";\nimport { Label } from \"../ui/label\";\nimport { Switch } from \"../ui/switch\";\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from \"../ui/popover\";\nimport { Collapsible, CollapsibleContent } from \"../ui/collapsible\";\nimport { cn } from \"../../utils\";\nimport { readStoredOptions, writeStoredOptions } from \"../../option-storage\";\nimport {\n DefaultLink,\n isPathActive,\n resolveNavigation,\n type LinkComponent,\n type NavigationNode,\n} from \"../../navigation\";\n\nexport interface NavItem {\n to: string;\n icon: LucideIcon;\n label: string;\n /** Nested items — rendered as a collapsible group when the rail is expanded */\n children?: NavItem[];\n badge?: string | number;\n disabled?: boolean;\n /**\n * Exact-match active state (e.g. overview `/`). Exact on the path only, so\n * an `activePath` carrying `?search#hash` still matches.\n */\n end?: boolean;\n}\n\n/**\n * The \"up\" link AppShell renders above page content: a real link to the\n * logical parent, never `history.back()`.\n *\n * @stability Beta\n */\nexport interface ParentNavigation {\n href: string;\n label: string;\n}\n\n/**\n * Declarative chrome for AppShell — developer defaults + optional\n * in-sidebar user toggles (Notion/Linear “customize chrome” pattern).\n *\n * @stability Beta\n */\nexport interface AppShellOptions {\n showLogo?: boolean;\n showAppName?: boolean;\n showThemeToggle?: boolean;\n /** Desktop rail collapse control */\n showCollapse?: boolean;\n showUserSlot?: boolean;\n showFooter?: boolean;\n showSecondaryNav?: boolean;\n /** Mobile fixed bottom tab bar */\n showMobileBottomNav?: boolean;\n defaultCollapsed?: boolean;\n /**\n * Show the in-sidebar Sidebar options popover so users can customize chrome.\n * Default true when collapse / secondary / theme / slots are available.\n */\n configurable?: boolean;\n /**\n * Toggle keys the developer has decided on and users may not override —\n * e.g. hiding `showThemeToggle` for a brand that manages theme elsewhere.\n * Locked keys are dropped from the options popover and any stored user\n * override for them is ignored on resolve.\n */\n lockedOptions?: (keyof AppShellOptions)[];\n /** Comfortable (default) vs compact row padding */\n density?: \"comfortable\" | \"compact\";\n /** Expanded rail width in rem-ish tokens: narrow ≈ 13rem, wide ≈ 16rem */\n railWidth?: \"narrow\" | \"wide\";\n /**\n * Where page content scrolls.\n * - `container` (default): main panel scrolls — classic app-shell chrome.\n * - `window`: document/window scrolls with a sticky rail so React Router\n * `ScrollRestoration` keeps working (dashboard dogfood).\n */\n scrollRoot?: \"container\" | \"window\";\n}\n\nconst OPTION_DEFAULTS: Required<\n Omit<AppShellOptions, \"configurable\" | \"defaultCollapsed\" | \"lockedOptions\">\n> &\n Pick<AppShellOptions, \"configurable\" | \"defaultCollapsed\" | \"lockedOptions\"> = {\n showLogo: true,\n showAppName: true,\n showThemeToggle: true,\n showCollapse: true,\n showUserSlot: true,\n showFooter: true,\n showSecondaryNav: true,\n showMobileBottomNav: true,\n defaultCollapsed: false,\n configurable: undefined,\n density: \"comfortable\",\n railWidth: \"narrow\",\n scrollRoot: \"container\",\n};\n\nfunction readStoredCollapsed(key: string): boolean | undefined {\n if (typeof window === \"undefined\") return undefined;\n try {\n const raw = localStorage.getItem(`${key}:collapsed`);\n if (raw === \"1\") return true;\n if (raw === \"0\") return false;\n return undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction writeStoredCollapsed(key: string, collapsed: boolean) {\n if (typeof window === \"undefined\") return;\n try {\n localStorage.setItem(`${key}:collapsed`, collapsed ? \"1\" : \"0\");\n } catch {\n // quota / private mode\n }\n}\n\n/**\n * @stability Beta\n */\nexport interface AppShellProps {\n /** App name shown in sidebar header */\n appName: string;\n /** App logo letter or short text (ignored when `logo` is set) */\n appLogo?: string;\n /** Custom logo node — preferred over `appLogo` letter tile */\n logo?: ReactNode;\n /**\n * Primary navigation items. Optional when `navigation` is set: the tree\n * root's `items` are the global nav then.\n */\n navItems?: NavItem[];\n /**\n * The app's logical navigation hierarchy. AppShell resolves it against\n * `activePath` (see `resolveNavigation`) and derives:\n * - the sidebar's global items from the root's `items` (unless `navItems`),\n * - a contextual section from the current node's `items`, labelled with\n * the node's `label` (`$param` segments in `to` filled from the URL),\n * - the mobile tab bar: the contextual items when there are any, else the\n * global top-level items (unless `mobileNavItems`),\n * - a back link to the current node's logical parent (unless\n * `parentNavigation`).\n *\n * @stability Beta\n */\n navigation?: NavigationNode<NavItem>;\n /**\n * Back-to-parent link rendered in the content header, above `children`, on\n * mobile and desktop. Derived from `navigation` when omitted; `null` hides\n * it. Use this instead of placing a back row inside page content.\n *\n * @stability Beta\n */\n parentNavigation?: ParentNavigation | null;\n /** Secondary nav (e.g. “More”) — rendered below a divider when shown */\n secondaryNavItems?: NavItem[];\n /** Label above secondary nav (default “More”) */\n secondaryNavLabel?: string;\n /**\n * Items for the mobile bottom tab bar. Defaults to top-level `navItems`\n * (no children). Pass a short list for apps with large sidebars; pass `[]`\n * and set `options.showMobileBottomNav: false` to hide.\n */\n mobileNavItems?: NavItem[];\n /** Slot below the logo row (product switcher, workspace picker, …) */\n headerSlot?: ReactNode;\n /**\n * Compact slot shown in the **collapsed** desktop rail, where `headerSlot`\n * is hidden for space. Use it to keep a core affordance reachable without\n * expanding — e.g. an icon-only product switcher. Omit to hide the header\n * region entirely while collapsed.\n */\n collapsedHeaderSlot?: ReactNode;\n /** Footer region above the user slot (version, links) */\n footer?: ReactNode;\n /**\n * User / account block at the bottom of the sidebar. When the rail is\n * collapsed, AppShell hides any descendant carrying the\n * `data-shell-user-detail` attribute (e.g. name/email text) so only a\n * compact element (avatar, initial) remains — tag the detail wrapper you\n * want hidden in the collapsed rail with that attribute.\n */\n userSlot?: ReactNode;\n /** Page content */\n children: ReactNode;\n /**\n * @deprecated Prefer `options.showThemeToggle`. Kept for sample-app\n * back-compat; merges into resolved options when `options` omits it.\n */\n showThemeToggle?: boolean;\n /** Chrome config (developer defaults + optional in-sidebar menu) */\n options?: AppShellOptions;\n /** Persist user sidebar-option overrides + collapse state (localStorage) */\n optionsStorageKey?: string;\n /** Controlled collapse (desktop rail) */\n collapsed?: boolean;\n onCollapsedChange?: (collapsed: boolean) => void;\n /**\n * Injectable link component. Defaults to a plain `<a>` (no router). Pass a\n * router adapter — e.g. React Router `({ href, ...p }) => <Link to={href} {...p} />`\n * or Next.js `next/link` — to get client-side navigation.\n */\n linkComponent?: LinkComponent;\n /**\n * Current location used to highlight the active nav item. Pass the full\n * location, `pathname + search + hash` (React Router: `useLocation()`), so\n * items whose `to` names a query or hash (`/admin?tab=users`) can become\n * active. A pathname alone still works for path-only items, `end` included.\n * Omit to disable active highlighting.\n */\n activePath?: string;\n /**\n * Optional custom active-state matcher. Defaults to a prefix match (with `/`\n * treated as exact), mirroring React Router `NavLink`.\n */\n isActive?: (to: string, activePath?: string) => boolean;\n}\n\nconst PARAM = /^\\$(.+)$/;\n\n/**\n * Fill `$name` path segments from `params`; `undefined` if one is missing. A\n * `?query` / `#hash` on `to` is kept as is.\n */\nfunction fillParams(to: string, params: Record<string, string>): string | undefined {\n const cut = to.search(/[?#]/);\n const path = cut === -1 ? to : to.slice(0, cut);\n const suffix = cut === -1 ? \"\" : to.slice(cut);\n let missing = false;\n const filled = path\n .split(\"/\")\n .map((part) => {\n const name = PARAM.exec(part)?.[1];\n if (name == null) return part;\n const value = params[name];\n if (value == null) missing = true;\n return value == null ? part : encodeURIComponent(value);\n })\n .join(\"/\");\n return missing ? undefined : filled + suffix;\n}\n\n/** Interpolate items (and children); drop any whose path the URL can't fill. */\nfunction fillItems(items: NavItem[], params: Record<string, string>): NavItem[] {\n return items.flatMap((item) => {\n const to = fillParams(item.to, params);\n if (to == null) return [];\n return [\n {\n ...item,\n to,\n children: item.children ? fillItems(item.children, params) : undefined,\n },\n ];\n });\n}\n\nfunction ThemeToggle({ testId }: { testId: string }) {\n const [dark, setDark] = useState(false);\n\n useEffect(() => {\n const stored = localStorage.getItem(\"theme\");\n const prefersDark = window.matchMedia(\n \"(prefers-color-scheme: dark)\",\n ).matches;\n const isDark = stored === \"dark\" || (!stored && prefersDark);\n setDark(isDark);\n document.documentElement.classList.toggle(\"dark\", isDark);\n }, []);\n\n function toggle() {\n const next = !dark;\n setDark(next);\n document.documentElement.classList.toggle(\"dark\", next);\n localStorage.setItem(\"theme\", next ? \"dark\" : \"light\");\n }\n\n return (\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={toggle}\n className=\"h-8 w-8\"\n title=\"Toggle theme\"\n aria-label=\"Toggle theme\"\n data-testid={testId}\n testID={testId}\n >\n {dark ? <Sun className=\"h-4 w-4\" /> : <Moon className=\"h-4 w-4\" />}\n </Button>\n );\n}\n\nfunction itemIsActive(\n item: NavItem,\n activePath: string | undefined,\n isActive: (to: string, activePath?: string) => boolean,\n): boolean {\n // `end` is exact on the path but ignores an incidental query/hash, so an\n // `end` item stays active on `/dashboard?page=2`.\n if (item.end) {\n return isPathActive(item.to, activePath, { end: true });\n }\n if (isActive(item.to, activePath)) return true;\n return Boolean(\n item.children?.some((child) => itemIsActive(child, activePath, isActive)),\n );\n}\n\nfunction NavLinkRow({\n item,\n collapsed,\n density,\n onNavClick,\n linkComponent: LinkComp,\n activePath,\n isActive,\n notCurrent = false,\n}: {\n item: NavItem;\n collapsed: boolean;\n density: \"comfortable\" | \"compact\";\n onNavClick?: () => void;\n linkComponent: LinkComponent;\n activePath?: string;\n isActive: (to: string, activePath?: string) => boolean;\n /** Highlight as usual but never claim `aria-current` (another section holds it). */\n notCurrent?: boolean;\n}) {\n const active = itemIsActive(item, activePath, isActive);\n const pad = density === \"compact\" ? \"px-2.5 py-1.5\" : \"px-3 py-2\";\n\n if (item.disabled) {\n return (\n <span\n title={item.label}\n className={cn(\n \"flex items-center gap-3 rounded-lg text-sm font-medium opacity-40\",\n pad,\n collapsed && \"justify-center px-2\",\n )}\n aria-disabled\n >\n <item.icon className=\"h-4 w-4 shrink-0\" />\n {!collapsed ? <span className=\"truncate\">{item.label}</span> : null}\n </span>\n );\n }\n\n return (\n <LinkComp\n href={item.to}\n onClick={onNavClick}\n title={collapsed ? item.label : undefined}\n aria-label={collapsed ? item.label : undefined}\n aria-current={active && !notCurrent ? \"page\" : undefined}\n className={cn(\n \"flex items-center gap-3 rounded-lg text-sm font-medium transition-colors\",\n pad,\n collapsed && \"justify-center px-2\",\n active\n ? \"bg-sidebar-accent text-sidebar-primary\"\n : \"text-sidebar-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground\",\n )}\n >\n <item.icon className=\"h-4 w-4 shrink-0\" />\n {!collapsed ? (\n <>\n <span className=\"min-w-0 flex-1 truncate\">{item.label}</span>\n {item.badge != null ? (\n <Badge variant=\"secondary\" className=\"h-5 shrink-0 px-1.5 text-[10px]\">\n {item.badge}\n </Badge>\n ) : null}\n </>\n ) : null}\n </LinkComp>\n );\n}\n\nfunction NavGroup({\n item,\n collapsed,\n density,\n onNavClick,\n linkComponent,\n activePath,\n isActive,\n notCurrent = false,\n}: {\n item: NavItem;\n collapsed: boolean;\n density: \"comfortable\" | \"compact\";\n onNavClick?: () => void;\n linkComponent: LinkComponent;\n activePath?: string;\n isActive: (to: string, activePath?: string) => boolean;\n /** Highlight as usual but never claim `aria-current` (another section holds it). */\n notCurrent?: boolean;\n}) {\n const children = item.children ?? [];\n const childActive = children.some((c) =>\n itemIsActive(c, activePath, isActive),\n );\n const [open, setOpen] = useState(childActive);\n\n useEffect(() => {\n if (childActive) setOpen(true);\n }, [childActive]);\n\n if (children.length === 0) {\n return (\n <NavLinkRow\n item={item}\n collapsed={collapsed}\n density={density}\n onNavClick={onNavClick}\n linkComponent={linkComponent}\n activePath={activePath}\n isActive={isActive}\n notCurrent={notCurrent}\n />\n );\n }\n\n // Collapsed rail: only the parent link (or first child if parent is a group stub)\n if (collapsed) {\n const target: NavItem = item.to\n ? { ...item, children: undefined }\n : { ...children[0]!, children: undefined };\n return (\n <NavLinkRow\n item={target}\n collapsed\n density={density}\n onNavClick={onNavClick}\n linkComponent={linkComponent}\n activePath={activePath}\n isActive={isActive}\n notCurrent={notCurrent}\n />\n );\n }\n\n // Parent may be its own route (`item.to`) — keep a real link and a separate\n // expand control so groups under an existing page stay navigable + highlightable.\n // Visual highlight may use prefix match; aria-current is exact-only so a child\n // route does not leave two \"page\" currents in the tree (CMT-322-008). Exact\n // means the same path; a query/hash on `activePath` alone doesn't break it.\n const selfExact = Boolean(\n item.to && isPathActive(item.to, activePath, { end: true }),\n );\n const selfActive = item.to\n ? item.end\n ? selfExact\n : isActive(item.to, activePath)\n : false;\n const groupHighlight = selfActive || childActive;\n const pad = density === \"compact\" ? \"px-2.5 py-1.5\" : \"px-3 py-2\";\n const LinkComp = linkComponent;\n const parentClass = cn(\n \"flex min-w-0 flex-1 items-center gap-3 rounded-lg text-sm font-medium transition-colors\",\n pad,\n groupHighlight\n ? \"bg-sidebar-accent/60 text-sidebar-primary\"\n : \"text-sidebar-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground\",\n );\n\n return (\n <Collapsible open={open} onOpenChange={setOpen}>\n <div className=\"space-y-0.5\">\n <div className=\"flex items-center gap-0.5\" data-testid={`nav-group-${item.label}`}>\n {item.to && !item.disabled ? (\n <LinkComp\n href={item.to}\n onClick={onNavClick}\n aria-current={selfExact && !notCurrent ? \"page\" : undefined}\n className={parentClass}\n >\n <item.icon className=\"h-4 w-4 shrink-0\" />\n <span className=\"min-w-0 flex-1 truncate text-left\">{item.label}</span>\n </LinkComp>\n ) : (\n <button\n type=\"button\"\n className={parentClass}\n onClick={() => setOpen((o) => !o)}\n aria-expanded={open}\n aria-disabled={item.disabled || undefined}\n disabled={item.disabled}\n >\n <item.icon className=\"h-4 w-4 shrink-0\" />\n <span className=\"min-w-0 flex-1 truncate text-left\">{item.label}</span>\n </button>\n )}\n <button\n type=\"button\"\n className={cn(\n \"shrink-0 rounded-lg p-1.5 text-sidebar-foreground transition-colors hover:bg-sidebar-accent\",\n groupHighlight && \"text-sidebar-primary\",\n item.disabled && \"pointer-events-none opacity-40\",\n )}\n onClick={() => setOpen((o) => !o)}\n aria-expanded={open}\n aria-label={open ? `Collapse ${item.label}` : `Expand ${item.label}`}\n aria-disabled={item.disabled || undefined}\n disabled={item.disabled}\n data-testid={`nav-group-toggle-${item.label}`}\n >\n <ChevronDown\n className={cn(\n \"h-3.5 w-3.5 opacity-60 transition-transform\",\n open && \"rotate-180\",\n )}\n />\n </button>\n </div>\n <CollapsibleContent>\n <div className=\"ml-3 space-y-0.5 border-l border-sidebar-border pl-2\">\n {children.map((child) => (\n <NavLinkRow\n key={child.to + child.label}\n item={child}\n collapsed={false}\n density={density}\n onNavClick={onNavClick}\n linkComponent={linkComponent}\n activePath={activePath}\n isActive={isActive}\n notCurrent={notCurrent}\n />\n ))}\n </div>\n </CollapsibleContent>\n </div>\n </Collapsible>\n );\n}\n\nfunction SidebarNav({\n navItems,\n contextualNavItems,\n contextualNavLabel,\n secondaryNavItems,\n secondaryNavLabel,\n showSecondary,\n collapsed,\n density,\n onNavClick,\n linkComponent,\n activePath,\n isActive,\n}: {\n navItems: NavItem[];\n contextualNavItems?: NavItem[];\n contextualNavLabel?: string;\n secondaryNavItems?: NavItem[];\n secondaryNavLabel: string;\n showSecondary: boolean;\n collapsed: boolean;\n density: \"comfortable\" | \"compact\";\n onNavClick?: () => void;\n linkComponent: LinkComponent;\n activePath?: string;\n isActive: (to: string, activePath?: string) => boolean;\n}) {\n const contextualLabelId = useId();\n // While a contextual item is the current page, global items keep their\n // highlight (the section you are in) but leave `aria-current` to it, so\n // \"Showcase\" and \"Overview\" are never both the current page.\n const contextualActive = Boolean(\n contextualNavItems?.some((item) => itemIsActive(item, activePath, isActive)),\n );\n return (\n <nav\n className={cn(\n \"flex-1 space-y-1 overflow-y-auto\",\n collapsed ? \"p-2\" : \"p-3\",\n )}\n aria-label=\"Main\"\n >\n {navItems.map((item) => (\n <NavGroup\n key={item.to + item.label}\n item={item}\n collapsed={collapsed}\n density={density}\n onNavClick={onNavClick}\n linkComponent={linkComponent}\n activePath={activePath}\n isActive={isActive}\n notCurrent={contextualActive}\n />\n ))}\n\n {contextualNavItems && contextualNavItems.length > 0 ? (\n <div\n className={cn(\n \"mt-4 space-y-1 border-t border-sidebar-border pt-4\",\n collapsed && \"mt-2 pt-2\",\n )}\n data-testid=\"app-shell-contextual-nav\"\n role=\"group\"\n aria-labelledby={!collapsed && contextualNavLabel ? contextualLabelId : undefined}\n aria-label={collapsed ? contextualNavLabel : undefined}\n >\n {!collapsed && contextualNavLabel ? (\n <p\n id={contextualLabelId}\n className=\"mb-2 truncate px-3 text-xs font-medium uppercase tracking-wider text-sidebar-foreground/40\"\n >\n {contextualNavLabel}\n </p>\n ) : null}\n {contextualNavItems.map((item) => (\n <NavGroup\n key={item.to + item.label}\n item={item}\n collapsed={collapsed}\n density={density}\n onNavClick={onNavClick}\n linkComponent={linkComponent}\n activePath={activePath}\n isActive={isActive}\n />\n ))}\n </div>\n ) : null}\n\n {showSecondary && secondaryNavItems && secondaryNavItems.length > 0 ? (\n <div\n className={cn(\n \"mt-4 space-y-1 border-t border-sidebar-border pt-4\",\n collapsed && \"mt-2 pt-2\",\n )}\n >\n {!collapsed ? (\n <p className=\"mb-2 px-3 text-xs font-medium uppercase tracking-wider text-sidebar-foreground/40\">\n {secondaryNavLabel}\n </p>\n ) : null}\n {secondaryNavItems.map((item) => (\n <NavGroup\n key={item.to + item.label}\n item={item}\n collapsed={collapsed}\n density={density}\n onNavClick={onNavClick}\n linkComponent={linkComponent}\n activePath={activePath}\n isActive={isActive}\n />\n ))}\n </div>\n ) : null}\n </nav>\n );\n}\n\nfunction SidebarBrand({\n appName,\n appLogo,\n logo,\n showLogo,\n showAppName,\n collapsed,\n}: {\n appName: string;\n appLogo?: string;\n logo?: ReactNode;\n showLogo: boolean;\n showAppName: boolean;\n collapsed: boolean;\n}) {\n if (!showLogo && !showAppName) return null;\n\n return (\n <div\n className={cn(\n \"flex min-w-0 items-center gap-2\",\n collapsed && \"justify-center\",\n )}\n >\n {showLogo ? (\n logo ? (\n <div className=\"flex h-7 w-7 shrink-0 items-center justify-center overflow-hidden\">\n {logo}\n </div>\n ) : appLogo ? (\n <div className=\"flex h-7 w-7 shrink-0 items-center justify-center rounded-lg bg-primary\">\n <span className=\"text-sm font-bold text-primary-foreground\">\n {appLogo}\n </span>\n </div>\n ) : null\n ) : null}\n {showAppName && !collapsed ? (\n <span className=\"truncate font-semibold text-sidebar-foreground\">\n {appName}\n </span>\n ) : null}\n </div>\n );\n}\n\ntype ToggleDef = {\n key: keyof AppShellOptions;\n label: string;\n available: boolean;\n};\n\nexport function AppShell({\n appName,\n appLogo,\n logo,\n navItems: navItemsProp,\n navigation,\n parentNavigation: parentNavigationProp,\n secondaryNavItems,\n secondaryNavLabel = \"More\",\n mobileNavItems,\n headerSlot,\n collapsedHeaderSlot,\n footer,\n userSlot,\n children,\n showThemeToggle: showThemeToggleProp,\n options: optionsProp,\n optionsStorageKey,\n collapsed: collapsedProp,\n onCollapsedChange,\n linkComponent = DefaultLink,\n activePath,\n isActive = isPathActive,\n}: AppShellProps) {\n const [mobileOpen, setMobileOpen] = useState(false);\n\n // Hierarchical nav: resolve the tree against the current location once.\n const derived = useMemo(() => {\n if (!navigation) return undefined;\n const nav = resolveNavigation(navigation, activePath ?? \"/\");\n const atRoot = nav.trail.length === 1;\n const globalItems = fillItems(navigation.items, nav.params);\n const contextualItems = atRoot ? [] : fillItems(nav.items, nav.params);\n // No link up to the root from a top-level page (it is where the global\n // nav already goes), and none whose path the URL couldn't fill.\n const parent =\n nav.parent &&\n nav.trail.length > 2 &&\n !nav.parent.path.split(\"/\").some((p) => PARAM.test(p))\n ? { href: nav.parent.path, label: nav.parent.label }\n : undefined;\n return { current: nav.current, globalItems, contextualItems, parent };\n }, [navigation, activePath]);\n\n const navItems = navItemsProp ?? derived?.globalItems ?? [];\n const contextualNavItems = derived?.contextualItems ?? [];\n const parentNavigation =\n parentNavigationProp === undefined ? derived?.parent : parentNavigationProp ?? undefined;\n\n const [userOverrides, setUserOverrides] = useState<Partial<AppShellOptions>>(\n {},\n );\n // Tracks which storage key the current overrides were hydrated from, so a\n // key change can't flush the previous key's overrides into the new key\n // before the read effect re-hydrates.\n const [hydratedKey, setHydratedKey] = useState<string | undefined>(\n optionsStorageKey ? undefined : \"\",\n );\n\n // Close the drawer on any path change (product switcher, deep links, …).\n useEffect(() => {\n setMobileOpen(false);\n }, [activePath]);\n\n const hasSecondary = Boolean(secondaryNavItems && secondaryNavItems.length);\n const hasUser = userSlot != null;\n const hasFooter = footer != null;\n const hasLogo = Boolean(logo || appLogo);\n\n useEffect(() => {\n if (!optionsStorageKey) {\n setUserOverrides({});\n setHydratedKey(\"\");\n return;\n }\n setUserOverrides(readStoredOptions<AppShellOptions>(optionsStorageKey));\n setHydratedKey(optionsStorageKey);\n }, [optionsStorageKey]);\n\n useEffect(() => {\n // Persist only once overrides belong to the current key (see hydratedKey).\n if (!optionsStorageKey || hydratedKey !== optionsStorageKey) return;\n writeStoredOptions<AppShellOptions>(optionsStorageKey, userOverrides);\n }, [optionsStorageKey, userOverrides, hydratedKey]);\n\n const lockedOptions = optionsProp?.lockedOptions;\n\n const resolved = useMemo(() => {\n const merged: AppShellOptions = {\n ...OPTION_DEFAULTS,\n ...(showThemeToggleProp !== undefined\n ? { showThemeToggle: showThemeToggleProp }\n : {}),\n ...optionsProp,\n ...userOverrides,\n };\n if (merged.configurable === undefined) {\n merged.configurable =\n hasSecondary ||\n hasUser ||\n hasFooter ||\n Boolean(merged.showCollapse) ||\n Boolean(merged.showThemeToggle);\n }\n // Locked keys always resolve to the developer default, never a stored\n // or in-session user override.\n if (lockedOptions?.length) {\n const defaults = OPTION_DEFAULTS as Record<string, unknown>;\n const devOptions = optionsProp as Record<string, unknown> | undefined;\n const target = merged as Record<string, unknown>;\n for (const key of lockedOptions) {\n target[key] = devOptions?.[key] ?? defaults[key];\n }\n }\n return merged;\n }, [\n optionsProp,\n userOverrides,\n showThemeToggleProp,\n hasSecondary,\n hasUser,\n hasFooter,\n lockedOptions,\n ]);\n\n const patchOption = useCallback(\n (key: keyof AppShellOptions, value: boolean) => {\n if (lockedOptions?.includes(key)) return;\n setUserOverrides((prev) => ({ ...prev, [key]: value }));\n },\n [lockedOptions],\n );\n\n const [uncontrolledCollapsed, setUncontrolledCollapsed] = useState(\n () =>\n optionsProp?.defaultCollapsed ?? OPTION_DEFAULTS.defaultCollapsed!,\n );\n\n useEffect(() => {\n if (!optionsStorageKey || collapsedProp !== undefined) return;\n const stored = readStoredCollapsed(optionsStorageKey);\n if (stored !== undefined) setUncontrolledCollapsed(stored);\n }, [optionsStorageKey, collapsedProp]);\n\n const isCollapseControlled = collapsedProp !== undefined;\n const collapsed = isCollapseControlled\n ? collapsedProp!\n : uncontrolledCollapsed;\n\n const setCollapsed = (next: boolean) => {\n if (!isCollapseControlled) {\n setUncontrolledCollapsed(next);\n if (optionsStorageKey) writeStoredCollapsed(optionsStorageKey, next);\n }\n onCollapsedChange?.(next);\n };\n\n const ParentLink = linkComponent;\n const density = resolved.density ?? \"comfortable\";\n const scrollWindow = resolved.scrollRoot === \"window\";\n const railExpanded =\n resolved.railWidth === \"wide\" ? \"md:w-64\" : \"md:w-52\";\n const railClass = collapsed ? \"md:w-14\" : railExpanded;\n\n const leaves = (items: NavItem[]) =>\n items.filter((i) => !i.children || i.children.length === 0);\n const contextualLeaves = leaves(contextualNavItems);\n const bottomItems = (\n mobileNavItems ??\n (contextualLeaves.length > 0 ? contextualLeaves : leaves(navItems))\n ).filter((i) => !i.disabled);\n // Global tabs shown as a fallback keep their highlight, but leave\n // `aria-current` to the contextual item that is the current page (see SidebarNav).\n const bottomNotCurrent =\n !mobileNavItems &&\n contextualLeaves.length === 0 &&\n contextualNavItems.some((i) => itemIsActive(i, activePath, isActive));\n\n const toggles: ToggleDef[] = (\n [\n { key: \"showLogo\", label: \"Logo\", available: hasLogo },\n { key: \"showAppName\", label: \"App name\", available: true },\n {\n key: \"showThemeToggle\",\n label: \"Theme toggle\",\n available: true,\n },\n { key: \"showCollapse\", label: \"Collapse control\", available: true },\n {\n key: \"showSecondaryNav\",\n label: \"Secondary nav\",\n available: hasSecondary,\n },\n { key: \"showFooter\", label: \"Footer\", available: hasFooter },\n { key: \"showUserSlot\", label: \"User block\", available: hasUser },\n {\n key: \"showMobileBottomNav\",\n label: \"Mobile bottom nav\",\n available: bottomItems.length > 0,\n },\n ] as const satisfies readonly ToggleDef[]\n ).filter((t) => t.available && !lockedOptions?.includes(t.key));\n\n const showTheme = resolved.showThemeToggle !== false;\n const showCollapseCtrl = resolved.showCollapse !== false;\n const showSecondary = hasSecondary && resolved.showSecondaryNav !== false;\n const showFooterSlot = hasFooter && resolved.showFooter !== false;\n const showUser = hasUser && resolved.showUserSlot !== false;\n const showMobileBottom =\n bottomItems.length > 0 && resolved.showMobileBottomNav !== false;\n\n const optionsControl =\n resolved.configurable && toggles.length > 0 ? (\n <Popover>\n <PopoverTrigger asChild>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-8 w-8\"\n title=\"Sidebar options\"\n aria-label=\"Sidebar options\"\n data-testid=\"app-shell-options\"\n testID=\"app-shell-options\"\n >\n <SlidersHorizontal className=\"h-4 w-4\" />\n </Button>\n </PopoverTrigger>\n <PopoverContent align=\"start\" side=\"top\" className=\"w-64 space-y-3\">\n <div>\n <h4 className=\"text-sm font-semibold\">Sidebar options</h4>\n <p className=\"text-xs text-muted-foreground\">\n Customize this sidebar. Saved on this device when a storage key is\n set.\n </p>\n </div>\n <ul className=\"space-y-3\">\n {toggles.map((t) => {\n const checked = Boolean(resolved[t.key] ?? true);\n return (\n <li\n key={t.key}\n className=\"flex items-center justify-between gap-3\"\n >\n <Label\n htmlFor={`app-shell-opt-${t.key}`}\n className=\"text-sm font-normal\"\n >\n {t.label}\n </Label>\n <Switch\n id={`app-shell-opt-${t.key}`}\n checked={checked}\n onCheckedChange={(v) => patchOption(t.key, v)}\n />\n </li>\n );\n })}\n </ul>\n {optionsStorageKey && Object.keys(userOverrides).length > 0 ? (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"h-8 w-full text-xs\"\n onClick={() => setUserOverrides({})}\n data-testid=\"app-shell-options-reset\"\n aria-label=\"Reset sidebar options\"\n testID=\"app-shell-options-reset\"\n >\n Reset to defaults\n </Button>\n ) : null}\n </PopoverContent>\n </Popover>\n ) : null;\n\n const sidebarChrome = (opts: { mobile?: boolean }) => (\n <>\n <div\n className={cn(\n \"flex h-14 shrink-0 items-center gap-2 border-b border-sidebar-border\",\n collapsed && !opts.mobile ? \"justify-center px-2\" : \"px-3\",\n )}\n >\n <div className=\"min-w-0 flex-1\">\n <SidebarBrand\n appName={appName}\n appLogo={appLogo}\n logo={logo}\n showLogo={resolved.showLogo !== false}\n showAppName={resolved.showAppName !== false}\n collapsed={collapsed && !opts.mobile}\n />\n </div>\n {opts.mobile ? (\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => setMobileOpen(false)}\n aria-label=\"Close navigation\"\n data-testid=\"app-shell-mobile-close\"\n testID=\"app-shell-mobile-close\"\n >\n <X className=\"h-5 w-5\" />\n </Button>\n ) : (\n <div className=\"flex shrink-0 items-center gap-0.5\">\n {showCollapseCtrl ? (\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-8 w-8\"\n onClick={() => setCollapsed(!collapsed)}\n title={collapsed ? \"Expand sidebar\" : \"Collapse sidebar\"}\n aria-label={collapsed ? \"Expand sidebar\" : \"Collapse sidebar\"}\n aria-pressed={collapsed}\n data-testid=\"app-shell-collapse\"\n testID=\"app-shell-collapse\"\n >\n {collapsed ? (\n <PanelLeft className=\"h-4 w-4\" />\n ) : (\n <PanelLeftClose className=\"h-4 w-4\" />\n )}\n </Button>\n ) : null}\n {!collapsed ? optionsControl : null}\n </div>\n )}\n </div>\n\n {collapsed && !opts.mobile ? (\n collapsedHeaderSlot ? (\n <div className=\"shrink-0 border-b border-sidebar-border p-2\">\n {collapsedHeaderSlot}\n </div>\n ) : null\n ) : headerSlot ? (\n <div className=\"shrink-0 border-b border-sidebar-border\">\n {headerSlot}\n </div>\n ) : null}\n\n <SidebarNav\n navItems={navItems}\n contextualNavItems={contextualNavItems}\n contextualNavLabel={derived?.current.label}\n secondaryNavItems={secondaryNavItems}\n secondaryNavLabel={secondaryNavLabel}\n showSecondary={showSecondary}\n collapsed={collapsed && !opts.mobile}\n density={density}\n onNavClick={opts.mobile ? () => setMobileOpen(false) : undefined}\n linkComponent={linkComponent}\n activePath={activePath}\n isActive={isActive}\n />\n\n {(showFooterSlot || showUser || showTheme || (collapsed && optionsControl)) &&\n !opts.mobile ? (\n <div className=\"mt-auto shrink-0 space-y-2 border-t border-sidebar-border p-2\">\n {showFooterSlot && !collapsed ? footer : null}\n {showUser ? (\n <div\n className={cn(\n collapsed &&\n \"flex justify-center [&_[data-shell-user-detail]]:hidden\",\n )}\n >\n {userSlot}\n </div>\n ) : null}\n <div\n className={cn(\n \"flex items-center gap-1\",\n collapsed ? \"flex-col\" : \"justify-end\",\n )}\n >\n {collapsed ? optionsControl : null}\n {showTheme ? (\n <ThemeToggle testId=\"app-shell-theme-toggle-desktop\" />\n ) : null}\n </div>\n </div>\n ) : null}\n\n {opts.mobile && (showFooterSlot || showUser || showTheme) ? (\n <div className=\"mt-auto shrink-0 space-y-2 border-t border-sidebar-border p-3\">\n {showFooterSlot ? footer : null}\n {showUser ? userSlot : null}\n {showTheme ? (\n <div className=\"flex justify-end\">\n <ThemeToggle testId=\"app-shell-theme-toggle-mobile-drawer\" />\n </div>\n ) : null}\n </div>\n ) : null}\n </>\n );\n\n return (\n <div\n className={cn(\n \"flex\",\n scrollWindow ? \"min-h-screen\" : \"h-screen overflow-hidden\",\n )}\n >\n {/* Desktop sidebar */}\n <aside\n className={cn(\n \"hidden flex-col border-r border-sidebar-border bg-sidebar transition-[width] duration-200 md:flex\",\n scrollWindow && \"sticky top-0 h-screen\",\n railClass,\n )}\n data-collapsed={collapsed || undefined}\n data-testid=\"app-shell-sidebar\"\n >\n {sidebarChrome({})}\n </aside>\n\n {/* Mobile overlay */}\n {mobileOpen ? (\n <div\n className=\"fixed inset-0 z-40 bg-black/50 md:hidden\"\n onClick={() => setMobileOpen(false)}\n aria-hidden\n />\n ) : null}\n\n {/* Mobile sidebar — inert when closed so off-screen links leave tab order */}\n <aside\n className={cn(\n \"fixed inset-y-0 left-0 z-50 flex w-60 flex-col border-r border-sidebar-border bg-sidebar transition-transform md:hidden\",\n mobileOpen ? \"translate-x-0\" : \"-translate-x-full pointer-events-none\",\n )}\n id=\"app-shell-mobile-nav\"\n aria-hidden={!mobileOpen}\n inert={!mobileOpen || undefined}\n >\n {sidebarChrome({ mobile: true })}\n </aside>\n\n {/* Main content */}\n <div\n className={cn(\n \"flex min-w-0 flex-1 flex-col\",\n !scrollWindow && \"overflow-hidden\",\n )}\n >\n <header\n className={cn(\n \"flex h-14 items-center gap-3 border-b px-4 md:hidden\",\n scrollWindow && \"sticky top-0 z-20 bg-background\",\n )}\n >\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => setMobileOpen(true)}\n aria-label=\"Open navigation\"\n aria-expanded={mobileOpen}\n aria-controls=\"app-shell-mobile-nav\"\n data-testid=\"app-shell-mobile-open\"\n testID=\"app-shell-mobile-open\"\n >\n <Menu className=\"h-5 w-5\" />\n </Button>\n <span className=\"flex-1 truncate font-semibold\">{appName}</span>\n {showTheme ? (\n <ThemeToggle testId=\"app-shell-theme-toggle-mobile-header\" />\n ) : null}\n </header>\n\n <main\n className={cn(\n \"flex-1\",\n !scrollWindow && \"overflow-y-auto\",\n showMobileBottom ? \"pb-16 md:pb-0\" : \"pb-0\",\n )}\n >\n {parentNavigation ? (\n <div\n className=\"flex min-w-0 items-center px-4 pt-4 sm:px-6 sm:pt-6 lg:px-8 lg:pt-8\"\n data-testid=\"app-shell-parent-nav\"\n >\n {/* -ml-3 lines the arrow up with the content's left edge. */}\n <Button\n asChild\n variant=\"ghost\"\n size=\"sm\"\n className=\"-ml-3 min-w-0 max-w-full\"\n testID=\"app-shell-parent-link\"\n >\n <ParentLink\n href={parentNavigation.href}\n aria-label={`Back to ${parentNavigation.label}`}\n >\n <ArrowLeft aria-hidden />\n <span className=\"truncate\">{parentNavigation.label}</span>\n </ParentLink>\n </Button>\n </div>\n ) : null}\n <div\n className={cn(\n \"min-w-0 p-4 sm:p-6 lg:p-8\",\n parentNavigation && \"pt-2 sm:pt-3 lg:pt-4\",\n )}\n >\n {children}\n </div>\n </main>\n\n {showMobileBottom ? (\n <nav\n className=\"fixed bottom-0 left-0 right-0 z-30 flex border-t bg-background md:hidden\"\n aria-label=\"Primary\"\n >\n {bottomItems.map((item) => {\n const LinkComp = linkComponent;\n const active = itemIsActive(item, activePath, isActive);\n return (\n <LinkComp\n key={item.to + item.label}\n href={item.to}\n title={item.label}\n aria-label={item.label}\n aria-current={active && !bottomNotCurrent ? \"page\" : undefined}\n className={cn(\n \"flex flex-1 flex-col items-center gap-1 py-2 text-xs font-medium transition-colors\",\n active ? \"text-primary\" : \"text-muted-foreground\",\n )}\n >\n <item.icon className=\"h-5 w-5\" />\n <span className=\"max-w-full truncate px-0.5\">\n {item.label}\n </span>\n </LinkComp>\n );\n })}\n </nav>\n ) : null}\n </div>\n </div>\n );\n}\n"]}