@mistriwork/mistri 1.0.0-rc.12 → 1.0.0-rc.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -3
- package/dist/client/assets/LayoutBuilder-MPzkVU2e.js.map +1 -1
- package/dist/client/assets/index-D2dHI6hR.js.map +1 -1
- package/dist/client/assets/shell-TreN_uLs.js.map +1 -1
- package/dist/docs/access-model.md +1 -1
- package/dist/docs/build-and-deploy.md +0 -1
- package/dist/docs/cli.md +1 -1
- package/dist/docs/glossary.md +3 -3
- package/dist/docs/query.md +9 -21
- package/dist/docs/status.md +3 -3
- package/dist/embed/react/chunks/LayoutBuilder-Cbxa_wve.js.map +1 -1
- package/dist/embed/react/chunks/app-0UZ1Re1k.js.map +1 -1
- package/dist/embed/react/chunks/page-Bx4o1kpQ.js.map +1 -1
- package/dist/embed/react/chunks/palette-Bb7Lf6eo.js.map +1 -1
- package/dist/embed/react/chunks/shell-DZRACiB9.js.map +1 -1
- package/dist/embed/react/chunks/write-BQO4CFc9.js.map +1 -1
- package/dist/embed/react/index.js +1 -1
- package/dist/server/build/dockerfile.js +1 -1
- package/dist/server/cli/usage.js +2 -2
- package/dist/ui/index.js +2 -2
- package/dist/ui/page.js +2 -2
- package/dist/ui/{shared-N4Ej8yRD.js → shared-1PD7TOTJ.js} +5 -5
- package/dist/ui/{shared-N4Ej8yRD.js.map → shared-1PD7TOTJ.js.map} +1 -1
- package/dist/ui/{shared-D5m86-4o.js → shared-1gMnOu9J.js} +6 -6
- package/dist/ui/{shared-D5m86-4o.js.map → shared-1gMnOu9J.js.map} +1 -1
- package/dist/ui/{shared-Ctaj8mR2.js → shared-5RQMi4BR.js} +3 -3
- package/dist/ui/{shared-Ctaj8mR2.js.map → shared-5RQMi4BR.js.map} +1 -1
- package/dist/ui/{shared-DpLeIATZ.js → shared-B-BUF9fx.js} +2 -2
- package/dist/ui/{shared-DpLeIATZ.js.map → shared-B-BUF9fx.js.map} +1 -1
- package/dist/ui/{shared-DWYnjItP.js → shared-B-MhiPIN.js} +9 -9
- package/dist/ui/{shared-DWYnjItP.js.map → shared-B-MhiPIN.js.map} +1 -1
- package/dist/ui/{shared-0fNuhSbG.js → shared-B07qIMlE.js} +5 -5
- package/dist/ui/{shared-0fNuhSbG.js.map → shared-B07qIMlE.js.map} +1 -1
- package/dist/ui/{shared-lYtMadRU.js → shared-B1SAS_J-.js} +3 -3
- package/dist/ui/{shared-lYtMadRU.js.map → shared-B1SAS_J-.js.map} +1 -1
- package/dist/ui/{shared-CpI0Y8M5.js → shared-B4jgU8h9.js} +6 -6
- package/dist/ui/{shared-CpI0Y8M5.js.map → shared-B4jgU8h9.js.map} +1 -1
- package/dist/ui/{shared-Cxu1c35l.js → shared-B5aBCUi7.js} +30 -30
- package/dist/ui/{shared-Cxu1c35l.js.map → shared-B5aBCUi7.js.map} +1 -1
- package/dist/ui/{shared-CAe-US1q.js → shared-B9H7_Pji.js} +5 -5
- package/dist/ui/{shared-CAe-US1q.js.map → shared-B9H7_Pji.js.map} +1 -1
- package/dist/ui/{shared-Q2bgBaYo.js → shared-BAXr20S-.js} +4 -4
- package/dist/ui/{shared-Q2bgBaYo.js.map → shared-BAXr20S-.js.map} +1 -1
- package/dist/ui/{shared-CyEefFFb.js → shared-BDDUzH-f.js} +19 -19
- package/dist/ui/{shared-CyEefFFb.js.map → shared-BDDUzH-f.js.map} +1 -1
- package/dist/ui/{shared-BdhPI6dq.js → shared-BGmkeDeW.js} +3 -3
- package/dist/ui/{shared-BdhPI6dq.js.map → shared-BGmkeDeW.js.map} +1 -1
- package/dist/ui/{shared-DONIpq2q.js → shared-BHCQ60yN.js} +2 -2
- package/dist/ui/{shared-DONIpq2q.js.map → shared-BHCQ60yN.js.map} +1 -1
- package/dist/ui/{shared-CNmaAv64.js → shared-BHsjawAG.js} +8 -8
- package/dist/ui/{shared-CNmaAv64.js.map → shared-BHsjawAG.js.map} +1 -1
- package/dist/ui/{shared-DgjU9kOy.js → shared-BIQuK_nq.js} +4 -4
- package/dist/ui/{shared-DgjU9kOy.js.map → shared-BIQuK_nq.js.map} +1 -1
- package/dist/ui/{shared-icSQAj21.js → shared-BOe4W2FI.js} +3 -3
- package/dist/ui/{shared-icSQAj21.js.map → shared-BOe4W2FI.js.map} +1 -1
- package/dist/ui/{shared-BlxoOJSk.js → shared-BPpC08ip.js} +3 -3
- package/dist/ui/{shared-BlxoOJSk.js.map → shared-BPpC08ip.js.map} +1 -1
- package/dist/ui/{shared-BtiFL37J.js → shared-BdA3LPCB.js} +2 -2
- package/dist/ui/{shared-BtiFL37J.js.map → shared-BdA3LPCB.js.map} +1 -1
- package/dist/ui/{shared-CvR94vn4.js → shared-Be3nbWsd.js} +11 -11
- package/dist/ui/{shared-CvR94vn4.js.map → shared-Be3nbWsd.js.map} +1 -1
- package/dist/ui/{shared-Bl_nF_IH.js → shared-Bf30ZLoS.js} +8 -4
- package/dist/ui/shared-Bf30ZLoS.js.map +1 -0
- package/dist/ui/{shared-DijrJ_V-.js → shared-BguP_BaR.js} +7 -7
- package/dist/ui/{shared-DijrJ_V-.js.map → shared-BguP_BaR.js.map} +1 -1
- package/dist/ui/{shared-DPAVoWY0.js → shared-BoLbc2WD.js} +17 -2
- package/dist/ui/{shared-DPAVoWY0.js.map → shared-BoLbc2WD.js.map} +1 -1
- package/dist/ui/{shared-BkdBTYwx.js → shared-BttyOW4W.js} +3 -3
- package/dist/ui/{shared-BkdBTYwx.js.map → shared-BttyOW4W.js.map} +1 -1
- package/dist/ui/{shared-CQWLz8uT.js → shared-BumxsBlA.js} +10 -10
- package/dist/ui/{shared-CQWLz8uT.js.map → shared-BumxsBlA.js.map} +1 -1
- package/dist/ui/{shared-Dzu7tFiC.js → shared-Bw73ktBk.js} +3 -3
- package/dist/ui/{shared-Dzu7tFiC.js.map → shared-Bw73ktBk.js.map} +1 -1
- package/dist/ui/{shared-BhAYErSx.js → shared-C1B0GH0e.js} +4 -4
- package/dist/ui/{shared-BhAYErSx.js.map → shared-C1B0GH0e.js.map} +1 -1
- package/dist/ui/{shared-BQJQcGgj.js → shared-C2FsyYr7.js} +4 -4
- package/dist/ui/{shared-BQJQcGgj.js.map → shared-C2FsyYr7.js.map} +1 -1
- package/dist/ui/{shared-B9lw2Ryh.js → shared-C2RU1qjv.js} +4 -4
- package/dist/ui/{shared-B9lw2Ryh.js.map → shared-C2RU1qjv.js.map} +1 -1
- package/dist/ui/{shared-DQYNI9wO.js → shared-C42f07hJ.js} +5 -5
- package/dist/ui/{shared-DQYNI9wO.js.map → shared-C42f07hJ.js.map} +1 -1
- package/dist/ui/{shared-CqCZ8wMY.js → shared-C4LkPCU4.js} +3 -3
- package/dist/ui/{shared-CqCZ8wMY.js.map → shared-C4LkPCU4.js.map} +1 -1
- package/dist/ui/{shared-BhtpgOpa.js → shared-C4wSfz6k.js} +9 -9
- package/dist/ui/{shared-BhtpgOpa.js.map → shared-C4wSfz6k.js.map} +1 -1
- package/dist/ui/{shared-BHc2Izkj.js → shared-C9DZtSFH.js} +2 -2
- package/dist/ui/{shared-BHc2Izkj.js.map → shared-C9DZtSFH.js.map} +1 -1
- package/dist/ui/{shared-DW1YuiNS.js → shared-CA52ClGo.js} +2 -2
- package/dist/ui/{shared-DW1YuiNS.js.map → shared-CA52ClGo.js.map} +1 -1
- package/dist/ui/{shared-BbSbilkh.js → shared-CBciTwm6.js} +9 -9
- package/dist/ui/{shared-BbSbilkh.js.map → shared-CBciTwm6.js.map} +1 -1
- package/dist/ui/{shared-C-J32eBn.js → shared-CL3RLKDA.js} +16 -16
- package/dist/ui/{shared-C-J32eBn.js.map → shared-CL3RLKDA.js.map} +1 -1
- package/dist/ui/{shared-Ck8S4OxW.js → shared-CLq3-_hW.js} +3 -3
- package/dist/ui/{shared-Ck8S4OxW.js.map → shared-CLq3-_hW.js.map} +1 -1
- package/dist/ui/{shared-Q5WefT7G.js → shared-CMjK-Ucd.js} +3 -3
- package/dist/ui/{shared-Q5WefT7G.js.map → shared-CMjK-Ucd.js.map} +1 -1
- package/dist/ui/{shared-D3MAuEA3.js → shared-CPjpSFGh.js} +2 -2
- package/dist/ui/{shared-D3MAuEA3.js.map → shared-CPjpSFGh.js.map} +1 -1
- package/dist/ui/{shared-VshXGwXP.js → shared-CSPhENq3.js} +2 -2
- package/dist/ui/{shared-VshXGwXP.js.map → shared-CSPhENq3.js.map} +1 -1
- package/dist/ui/{shared-DJrJaE73.js → shared-CZJE4Bmp.js} +3 -3
- package/dist/ui/{shared-DJrJaE73.js.map → shared-CZJE4Bmp.js.map} +1 -1
- package/dist/ui/{shared-D7ONOwI7.js → shared-C_BhUL2I.js} +7 -7
- package/dist/ui/{shared-D7ONOwI7.js.map → shared-C_BhUL2I.js.map} +1 -1
- package/dist/ui/{shared-j-2peBIB.js → shared-CbeujwdU.js} +4 -4
- package/dist/ui/{shared-j-2peBIB.js.map → shared-CbeujwdU.js.map} +1 -1
- package/dist/ui/{shared-D5GrOEa2.js → shared-Cbf-o4Dt.js} +4 -4
- package/dist/ui/{shared-D5GrOEa2.js.map → shared-Cbf-o4Dt.js.map} +1 -1
- package/dist/ui/{shared-HwiPIajr.js → shared-CdNmeNHh.js} +3 -3
- package/dist/ui/{shared-HwiPIajr.js.map → shared-CdNmeNHh.js.map} +1 -1
- package/dist/ui/{shared-ZCFt-CPb.js → shared-CdQOMD8J.js} +3 -3
- package/dist/ui/{shared-ZCFt-CPb.js.map → shared-CdQOMD8J.js.map} +1 -1
- package/dist/ui/{shared-ClhXSGGK.js → shared-CdiPYlTh.js} +2 -2
- package/dist/ui/{shared-ClhXSGGK.js.map → shared-CdiPYlTh.js.map} +1 -1
- package/dist/ui/{shared-DA8_pVRZ.js → shared-CepLAhwm.js} +2 -2
- package/dist/ui/{shared-DA8_pVRZ.js.map → shared-CepLAhwm.js.map} +1 -1
- package/dist/ui/{shared-BrYKjrnM.js → shared-Ch82h_Fu.js} +6 -6
- package/dist/ui/{shared-BrYKjrnM.js.map → shared-Ch82h_Fu.js.map} +1 -1
- package/dist/ui/{shared-C4UrE8Fb.js → shared-Chp88all.js} +3 -3
- package/dist/ui/{shared-C4UrE8Fb.js.map → shared-Chp88all.js.map} +1 -1
- package/dist/ui/{shared-CWa80DTO.js → shared-Ci16s2rN.js} +9 -9
- package/dist/ui/{shared-CWa80DTO.js.map → shared-Ci16s2rN.js.map} +1 -1
- package/dist/ui/{shared-tksTLD6Q.js → shared-CiqNkoE1.js} +5 -5
- package/dist/ui/{shared-tksTLD6Q.js.map → shared-CiqNkoE1.js.map} +1 -1
- package/dist/ui/{shared-yt7DjSrq.js → shared-CpMhOq8F.js} +2 -2
- package/dist/ui/{shared-yt7DjSrq.js.map → shared-CpMhOq8F.js.map} +1 -1
- package/dist/ui/{shared-Dm0z5WUl.js → shared-CrWv5JKH.js} +6 -6
- package/dist/ui/{shared-Dm0z5WUl.js.map → shared-CrWv5JKH.js.map} +1 -1
- package/dist/ui/{shared-CQL3FGHc.js → shared-Csfi3Pti.js} +2 -2
- package/dist/ui/{shared-CQL3FGHc.js.map → shared-Csfi3Pti.js.map} +1 -1
- package/dist/ui/{shared-BKNRbm-V.js → shared-CuZt26rm.js} +2 -2
- package/dist/ui/{shared-BKNRbm-V.js.map → shared-CuZt26rm.js.map} +1 -1
- package/dist/ui/{shared-Guq3upiR.js → shared-Cws_z-TS.js} +2 -2
- package/dist/ui/{shared-Guq3upiR.js.map → shared-Cws_z-TS.js.map} +1 -1
- package/dist/ui/{shared-Bw_qZeIj.js → shared-D1KWuCg6.js} +2 -2
- package/dist/ui/{shared-Bw_qZeIj.js.map → shared-D1KWuCg6.js.map} +1 -1
- package/dist/ui/{shared-CuCZKwXW.js → shared-D66ju_Cb.js} +23 -23
- package/dist/ui/{shared-CuCZKwXW.js.map → shared-D66ju_Cb.js.map} +1 -1
- package/dist/ui/{shared-DYfX7NSM.js → shared-DGaQZXnw.js} +2 -2
- package/dist/ui/{shared-DYfX7NSM.js.map → shared-DGaQZXnw.js.map} +1 -1
- package/dist/ui/{shared-B3Hp8tOv.js → shared-DHy41sET.js} +6 -6
- package/dist/ui/{shared-B3Hp8tOv.js.map → shared-DHy41sET.js.map} +1 -1
- package/dist/ui/{shared-CXyd7IKi.js → shared-DKEOMQ6l.js} +2 -2
- package/dist/ui/{shared-CXyd7IKi.js.map → shared-DKEOMQ6l.js.map} +1 -1
- package/dist/ui/{shared-Ccmc8YO0.js → shared-DSUICuaJ.js} +33 -33
- package/dist/ui/{shared-Ccmc8YO0.js.map → shared-DSUICuaJ.js.map} +1 -1
- package/dist/ui/{shared-CL2iw_js.js → shared-DUPMRoO0.js} +13 -13
- package/dist/ui/{shared-CL2iw_js.js.map → shared-DUPMRoO0.js.map} +1 -1
- package/dist/ui/{shared-Dtp4eRul.js → shared-DVfdm6ah.js} +2 -2
- package/dist/ui/{shared-Dtp4eRul.js.map → shared-DVfdm6ah.js.map} +1 -1
- package/dist/ui/{shared-BJ5Ex32G.js → shared-DXM7d7lJ.js} +3 -3
- package/dist/ui/{shared-BJ5Ex32G.js.map → shared-DXM7d7lJ.js.map} +1 -1
- package/dist/ui/{shared-BFr6ld0e.js → shared-DXbMlcev.js} +2 -2
- package/dist/ui/{shared-BFr6ld0e.js.map → shared-DXbMlcev.js.map} +1 -1
- package/dist/ui/{shared-BUp3jv-N.js → shared-D_SkPtJ9.js} +6 -6
- package/dist/ui/{shared-BUp3jv-N.js.map → shared-D_SkPtJ9.js.map} +1 -1
- package/dist/ui/{shared-CdNomVzH.js → shared-Dd21k2ic.js} +4 -4
- package/dist/ui/{shared-CdNomVzH.js.map → shared-Dd21k2ic.js.map} +1 -1
- package/dist/ui/{shared-gRMbxmpu.js → shared-Dh0nHtLZ.js} +8 -8
- package/dist/ui/{shared-gRMbxmpu.js.map → shared-Dh0nHtLZ.js.map} +1 -1
- package/dist/ui/{shared-BKGJgjog.js → shared-DkOdSpSK.js} +3 -3
- package/dist/ui/{shared-BKGJgjog.js.map → shared-DkOdSpSK.js.map} +1 -1
- package/dist/ui/{shared-BMsh72Uq.js → shared-Dkph5ckT.js} +2 -2
- package/dist/ui/{shared-BMsh72Uq.js.map → shared-Dkph5ckT.js.map} +1 -1
- package/dist/ui/{shared-Be1HpDOB.js → shared-Dl1_Nx--.js} +3 -3
- package/dist/ui/{shared-Be1HpDOB.js.map → shared-Dl1_Nx--.js.map} +1 -1
- package/dist/ui/{shared-BQIZWOoJ.js → shared-Dm0IGbAf.js} +2 -2
- package/dist/ui/{shared-BQIZWOoJ.js.map → shared-Dm0IGbAf.js.map} +1 -1
- package/dist/ui/{shared-DSUtcU5S.js → shared-DnIkTpPr.js} +5 -5
- package/dist/ui/{shared-DSUtcU5S.js.map → shared-DnIkTpPr.js.map} +1 -1
- package/dist/ui/{shared-DsxGbYlV.js → shared-Docl_0tq.js} +3 -3
- package/dist/ui/{shared-DsxGbYlV.js.map → shared-Docl_0tq.js.map} +1 -1
- package/dist/ui/{shared-DZskrV26.js → shared-DprrHC72.js} +2 -2
- package/dist/ui/{shared-DZskrV26.js.map → shared-DprrHC72.js.map} +1 -1
- package/dist/ui/{shared-Bmw43Hwf.js → shared-DyKsJTZs.js} +2 -2
- package/dist/ui/{shared-Bmw43Hwf.js.map → shared-DyKsJTZs.js.map} +1 -1
- package/dist/ui/{shared-BLG88Pya.js → shared-FO7vfI3F.js} +4 -4
- package/dist/ui/{shared-BLG88Pya.js.map → shared-FO7vfI3F.js.map} +1 -1
- package/dist/ui/{shared-DLSd80D1.js → shared-HalAVHjv.js} +3 -3
- package/dist/ui/{shared-DLSd80D1.js.map → shared-HalAVHjv.js.map} +1 -1
- package/dist/ui/{shared-D1mMBLdj.js → shared-JvcI-LWp.js} +15 -15
- package/dist/ui/{shared-D1mMBLdj.js.map → shared-JvcI-LWp.js.map} +1 -1
- package/dist/ui/{shared-C6Hv_4O0.js → shared-K7Ym27yg.js} +2 -2
- package/dist/ui/{shared-C6Hv_4O0.js.map → shared-K7Ym27yg.js.map} +1 -1
- package/dist/ui/{shared-B39ln7oi.js → shared-SzlnwfJO.js} +3 -3
- package/dist/ui/{shared-B39ln7oi.js.map → shared-SzlnwfJO.js.map} +1 -1
- package/dist/ui/{shared-DgPn_Jll.js → shared-TrGbd1FY.js} +3 -3
- package/dist/ui/{shared-DgPn_Jll.js.map → shared-TrGbd1FY.js.map} +1 -1
- package/dist/ui/{shared-DrFb-XtA.js → shared-WhbuObEW.js} +2 -2
- package/dist/ui/{shared-DrFb-XtA.js.map → shared-WhbuObEW.js.map} +1 -1
- package/dist/ui/{shared-DiFQljcq.js → shared-XcSKDp6N.js} +11 -11
- package/dist/ui/{shared-DiFQljcq.js.map → shared-XcSKDp6N.js.map} +1 -1
- package/dist/ui/{shared-CMAg58rY.js → shared-Z4uBJU6I.js} +7 -6
- package/dist/ui/shared-Z4uBJU6I.js.map +1 -0
- package/dist/ui/{shared-BnUptuUp.js → shared-bAgeiRa5.js} +2 -2
- package/dist/ui/{shared-BnUptuUp.js.map → shared-bAgeiRa5.js.map} +1 -1
- package/dist/ui/{shared-BxMvSjey.js → shared-cgXG7OgZ.js} +5 -5
- package/dist/ui/{shared-BxMvSjey.js.map → shared-cgXG7OgZ.js.map} +1 -1
- package/dist/ui/{shared-u4CG2kQJ.js → shared-eZ0SB_zm.js} +2 -2
- package/dist/ui/{shared-u4CG2kQJ.js.map → shared-eZ0SB_zm.js.map} +1 -1
- package/dist/ui/{shared-L90bWW8e.js → shared-frKFb79C.js} +2 -2
- package/dist/ui/{shared-L90bWW8e.js.map → shared-frKFb79C.js.map} +1 -1
- package/dist/ui/{shared-Dd34nhkw.js → shared-hAayNSRA.js} +3 -3
- package/dist/ui/{shared-Dd34nhkw.js.map → shared-hAayNSRA.js.map} +1 -1
- package/dist/ui/{shared-DzC64cpp.js → shared-j_J16p2B.js} +2 -2
- package/dist/ui/{shared-DzC64cpp.js.map → shared-j_J16p2B.js.map} +1 -1
- package/dist/ui/{shared-DX7HRIV-.js → shared-tqpl5N3g.js} +6 -6
- package/dist/ui/{shared-DX7HRIV-.js.map → shared-tqpl5N3g.js.map} +1 -1
- package/dist/ui/{shared-BS5dBMpA.js → shared-y-6_ZDts.js} +2 -2
- package/dist/ui/{shared-BS5dBMpA.js.map → shared-y-6_ZDts.js.map} +1 -1
- package/dist/ui/{shared-Cv5v_MP1.js → shared-zG6e1Rhz.js} +13 -13
- package/dist/ui/{shared-Cv5v_MP1.js.map → shared-zG6e1Rhz.js.map} +1 -1
- package/dist/ui/testing.js +1 -1
- package/package.json +4 -4
- package/dist/docs/cli-browser.md +0 -232
- package/dist/docs/database-browser.md +0 -115
- package/dist/docs/keyboard.md +0 -63
- package/dist/docs/mcp.md +0 -86
- package/dist/ui/shared-Bl_nF_IH.js.map +0 -1
- package/dist/ui/shared-CMAg58rY.js.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { E as sessionIdentity, m as canonicalText, w as captureSessionIdentity } from "./shared-poc11xxo.js";
|
|
2
|
-
import { L as state, nt as setOwnWriteMarker, ut as connectionGeneration } from "./shared-
|
|
2
|
+
import { L as state, nt as setOwnWriteMarker, ut as connectionGeneration } from "./shared-BoLbc2WD.js";
|
|
3
3
|
import { r as queryClient } from "./shared-C3MTHv9P.js";
|
|
4
|
-
import { r as composedEpoch } from "./shared-
|
|
4
|
+
import { r as composedEpoch } from "./shared-CpMhOq8F.js";
|
|
5
5
|
import { t as gatherReads } from "./shared-C1vJ9Ujy.js";
|
|
6
6
|
// packages/kit/src/client/recordWriteRefresh.ts
|
|
7
7
|
function sameKey(value, key) {
|
|
@@ -236,4 +236,4 @@ function pageSectionRead(query, table, key, same = sameKey) {
|
|
|
236
236
|
}
|
|
237
237
|
export { refreshAfterCommand as n, refreshRecordInPlace as r, captureRecordWriteRefresh as t };
|
|
238
238
|
|
|
239
|
-
//# sourceMappingURL=shared-
|
|
239
|
+
//# sourceMappingURL=shared-CdQOMD8J.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared-ZCFt-CPb.js","names":[],"sources":["../../../kit/src/client/recordWriteRefresh.ts"],"sourcesContent":["import { type Query, type QueryClient, type QueryKey } from '@tanstack/react-query';\nimport { state } from './core.js';\nimport { connectionGeneration } from './connectionTransition.js';\nimport { captureSessionIdentity, sessionIdentity } from './sessionIdentity.js';\nimport { queryClient } from './components/mount.js';\nimport { composedEpoch } from './composedReads.js';\nimport { canonicalText } from '@mistriwork/engine/shared/recordReadKeys.js';\nimport { setOwnWriteMarker } from './ownWrites.js';\nimport { gatherReads } from './readGathering.js';\n\ntype KeyTest = (value: unknown, key: Readonly<Record<string, unknown>>) => boolean;\n\nfunction sameKey(value: unknown, key: Readonly<Record<string, unknown>>): boolean {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return false;\n const candidate = value as Record<string, unknown>;\n return (\n Object.keys(candidate).length === Object.keys(key).length &&\n Object.keys(key).every((name) => Object.hasOwn(candidate, name) && Object.is(candidate[name], key[name]))\n );\n}\n\n/** Existing query families are not uniformly connection-qualified. Only inspect\n * them while their captured schema/connection/session is still the current owner.\n * No `key` is any key of the table (live sync's `many`), and `same` is how a query's\n * key is judged to be it: exactly, for a confirmed write; as text, for a change the\n * server announces, whose ids past 2^53 are strings (liveInvalidate.ts). */\nexport function queryTouches(\n query: QueryKey,\n connection: string,\n table: string,\n key: Readonly<Record<string, unknown>> | undefined,\n primary: readonly string[],\n same: KeyTest = sameKey,\n): boolean {\n const is = (value: unknown) => key === undefined || same(value, key);\n switch (query[0]) {\n case 'record':\n case 'references':\n return query[1] === table && is(query[2]);\n case 'page-fields':\n return query[2] === table && is(query[3]);\n case 'run':\n // TableRoom includes connection; Dashboard's three-part key does not.\n // Text queries may include joins, so invalidate their owner's list family.\n return (\n (query.length > 3 && query[1] === connection) ||\n (query.length === 3 && typeof query[1] === 'string' && typeof query[2] === 'number')\n );\n case 'count':\n return query[1] === connection;\n case 'page-list':\n return !!query[1] && typeof query[1] === 'object' && (query[1] as { base?: unknown }).base === table;\n case 'peek':\n return (\n query[1] === connection &&\n query[2] === table &&\n (key === undefined || (typeof query[3] === 'string' && Object.hasOwn(key, query[3]) && same({ v: query[4] }, { v: key[query[3]] })))\n );\n case 'peekpanel': {\n const values = query[3];\n return (\n query[1] === connection &&\n query[2] === table &&\n primary.length > 0 &&\n Array.isArray(values) &&\n values.length === primary.length &&\n (key === undefined || primary.every((name, index) => Object.hasOwn(key, name) && same({ v: values[index] }, { v: key[name] })))\n );\n }\n case 'picker':\n case 'picker-labels':\n return query[1] === connection && query[2] === table;\n default:\n return false;\n }\n}\n\n/** Capture before dispatch; invoke only after a confirmed acknowledgement.\n * Stale reads are cancelled before invalidation. Mounted editors retain their\n * confirmed overlay/caret; lists can refresh and records read fresh on remount.\n * Cache failures cannot turn an acknowledged write into a rejected operation. */\nexport function captureRecordWriteRefresh(table: string, inputKey: Readonly<Record<string, unknown>>): () => void {\n const identity = captureSessionIdentity(),\n schema = state.schema;\n const connection = state.activeConnection ?? '',\n generation = connectionGeneration();\n const key = Object.freeze({ ...inputKey });\n const primary = (schema?.tables?.find((candidate: { id: string }) => candidate.id === table)?.columns ?? [])\n .filter((column: { primaryKey?: boolean }) => column.primaryKey)\n .map((column: { name: string }) => column.name) as string[];\n const owns = () =>\n identity === sessionIdentity() &&\n schema === state.schema &&\n connection === (state.activeConnection ?? '') &&\n generation === connectionGeneration();\n let acknowledged = false;\n return () => {\n if (acknowledged || !owns()) return;\n acknowledged = true;\n try {\n const cache = queryClient.getQueryCache();\n const matches = cache.getAll().filter((query) => queryTouches(query.queryKey, connection, table, key, primary));\n // Query object identity also fences a cleared/replaced cache during await.\n const current = (query: Query) => owns() && matches.includes(query) && cache.get(query.queryHash) === query;\n void queryClient\n .cancelQueries({ predicate: current })\n .then(async () => {\n if (!owns()) return;\n await queryClient.invalidateQueries({ predicate: current, refetchType: 'none' });\n if (!owns()) return;\n await queryClient.refetchQueries({\n type: 'active',\n predicate: (query) => current(query) && !['record', 'page-fields', 'references'].includes(String(query.queryKey[0])),\n });\n })\n .catch(() => {\n /* Read reconciliation has no authority over the write outcome. */\n });\n } catch {\n /* A disposed cache does not invalidate a confirmed mutation. */\n }\n };\n}\n\n/**\n * A write landed on the record on screen — a command, a Save that asked for a\n * repaint, a reply posted from its timeline — so its page re-reads where it\n * stands: every read on it asks again and keeps what it shows until the new\n * answer lands. A routed page used to repaint by replacing its walk entry,\n * which started the room over; its reads, kept only while the room is up,\n * went with it, and the record page stood blank until every one of them had\n * been asked again and the page composed (about 8 s for a tenant's ticket).\n * Dialogs and split panes always refreshed this way.\n *\n * Asked once per write: a command's receipt refreshes the record, and the\n * form's Done (or a one-click verb's end) asks the same of the host a moment\n * later. With no write sent or answered between them (composedReads.ts\n * composedEpoch), the second has nothing new to read, and asking it cancelled\n * the first's reads mid-flight and composed the page a second time (G173).\n * A second ask for the same record in the same moment of the writes from\n * another surface — its own scope, its connection spelled its own way — joins\n * what the first began instead: it never cancels it, and asks only what the\n * first did not (a field report: a save on a record page set off its compose,\n * lists and counts twice, the first set cancelled mid-flight).\n */\nexport function refreshRecordInPlace(\n client: QueryClient,\n record: {\n readonly connection: string;\n readonly table: string;\n readonly key: Readonly<Record<string, unknown>>;\n /** The surface's own reads only, when it has an owner's scope. */\n readonly queryScope?: number;\n },\n fields: boolean,\n /** A change another person made, which no write of this page's sits between: asked again though nothing was sent since\n the last ask. With `since` (liveMark), no read already out is cancelled: one that began before the change is let\n land and asked once more, one that began since is joined (askAgain). */\n again = false,\n since?: number,\n): Promise<void> {\n const asked = canonicalText([record.connection, record.table, record.key, record.queryScope ?? null, fields]);\n const epoch = composedEpoch(),\n id = canonicalText([record.table, record.key]);\n const last = refreshed.get(client);\n if (!again && last?.epoch === epoch && last.record === id) {\n if (last.asked.has(asked)) return Promise.resolve();\n last.asked.add(asked);\n /* Measured from the first ask: what it began since is joined, what has landed since is left. */\n again = true;\n since = last.mark;\n } else refreshed.set(client, { record: id, epoch, asked: new Set([asked]), mark: since ?? liveMark(client) });\n /* The page, its lists, its counts and its verbs are asked in this moment: a transport that can, sends them as one. */\n gatherReads();\n /* A write of this page's asks its table's lists and counts again here. A change pushed by someone else does not:\n live sync has already asked each read that change touches, by the tables it names (liveInvalidate.ts), and this\n asked every list and count on the connection once more on top, cancelling those it had just begun. */\n if (since === undefined) captureRecordWriteRefresh(record.table, record.key)();\n /* A write of this page's cancels what was out, since it began before the write; a change pushed by another\n person's write never does, or a steady stream of them starves every read (G211). */\n const ask = (predicate: (query: Query) => boolean, refetch: 'active' | 'none' = 'active'): Promise<void> =>\n since === undefined ? client.invalidateQueries({ predicate, refetchType: refetch }) : askAgain(client, predicate, since, refetch);\n const planned = ask(\n (query) =>\n ['page-root', 'page-plan'].includes(String(query.queryKey[0])) &&\n query.queryKey[1] === record.connection &&\n (record.queryScope === undefined || query.queryKey.at(-1) === record.queryScope),\n );\n const asking: Array<Promise<unknown>> = [planned];\n /* Every page that shows the record's fields, by the record, not by one page's id: a command's receipt does\n not know which page it was run from. */\n if (fields)\n asking.push(\n ask((query) => query.queryKey[0] === 'page-fields' && query.queryKey[2] === record.table && sameKey(query.queryKey[3], record.key)),\n );\n /* With the lists' invalidation above, in the same moment: the verbs' availability follows both as one\n (commandAvailability.ts), and waits for the compose that answers it. */\n asking.push(ask((query) => query.queryKey[0] === 'when' && query.queryKey[1] === record.table));\n /* Every section's read asks again, as the remount did: the write may have\n added a history entry, a timeline row, a flow step or a related row. They\n are marked now and asked once the page's compose is back, which brings\n their answers with it (composedReads.ts): asked beside it, each went out\n on its own (G173). One a new plan has already asked anew is no longer\n stale, so it is not asked twice. */\n const section = (query: Query) => pageSectionRead(query.queryKey, record.table, record.key);\n /* Marked as a pushed change marks: one that has landed since the change already shows it, and is left fresh. */\n void (since === undefined\n ? client.invalidateQueries({ predicate: section, refetchType: 'none' })\n : askAgain(client, section, since, 'none'));\n asking.push(\n planned\n .catch(() => {})\n .then(() => {\n gatherReads();\n const stale = (query: Query) => section(query) && query.state.isInvalidated;\n return since === undefined ? client.refetchQueries({ type: 'active', predicate: stale }) : askAgain(client, stale, since);\n }),\n );\n return Promise.allSettled(asking).then(() => {});\n}\n\n/* ---------- a change another person made: asked again, never cancelled ---------- */\n\n/* One order for the moments that matter here: a change arriving (liveMark) and a read beginning. A read that began\n after a change was marked was answered after its commit, so it already shows it. */\nlet sequence = 0;\nconst begun = new WeakMap<QueryClient, WeakMap<Query, number>>();\n\nfunction readsBegun(client: QueryClient): WeakMap<Query, number> {\n let known = begun.get(client);\n if (known) return known;\n const marks = (known = new WeakMap());\n begun.set(client, marks);\n client.getQueryCache().subscribe((event) => {\n if (event.type !== 'updated') return;\n /* A read that failed, or was cancelled and put back as it was (a revert is a setState), showed nothing new: it is\n no longer one that began since, so the change still asks it again. */\n const type = event.action.type;\n if (type === 'fetch') marks.set(event.query, ++sequence);\n else if (type === 'error' || type === 'setState') marks.delete(event.query);\n });\n return known;\n}\n\n/** The moment a pushed change arrived, in the order reads begin in; reads of `client` are followed from now on. */\nexport function liveMark(client: QueryClient): number {\n readsBegun(client);\n return ++sequence;\n}\n/* A write of this page's is marked as it is answered: its echo on the live stream is measured from there (ownWrites.ts). */\nsetOwnWriteMarker(() => liveMark(queryClient));\n\n/**\n * Ask the reads `predicate` matches again for a change marked at `since` (liveMark), never cancelling one already out:\n * a read that began before the change is let land and then asked once more, a read that began since is joined, and a\n * read that has landed since is left as it is. Inactive reads are only marked stale. Invalidating instead cancelled\n * and restarted every read in flight, so while changes kept coming faster than a read took, none ever landed (G211).\n */\nexport async function askAgain(\n client: QueryClient,\n predicate: (query: Query) => boolean,\n since: number,\n refetch: 'active' | 'none' = 'active',\n): Promise<void> {\n const marks = readsBegun(client);\n const after = (query: Query) => (marks.get(query) ?? 0) > since;\n const landedSince = (query: Query) => after(query) && query.state.fetchStatus !== 'fetching';\n const matched = client\n .getQueryCache()\n .findAll({ predicate })\n .filter((query) => !landedSince(query));\n if (!matched.length) return;\n await client.invalidateQueries({ predicate: (query) => matched.includes(query), refetchType: 'none' });\n if (refetch === 'none') return;\n const active = matched.filter((query) => query.isActive());\n const behind = active.filter((query) => query.state.fetchStatus === 'fetching' && !after(query));\n /* Joined, not cancelled: each settles as it would have, and is then asked once more. */\n if (behind.length) await client.refetchQueries({ predicate: (query) => behind.includes(query) }, { cancelRefetch: false });\n const asking = active.filter((query) => !landedSince(query));\n if (asking.length) await client.refetchQueries({ predicate: (query) => asking.includes(query) }, { cancelRefetch: false });\n}\n/* Per cache, the record last asked again and where the writes stood then. */\nconst refreshed = new WeakMap<QueryClient, { record: string; epoch: number; asked: Set<string>; mark: number }>();\n\n/**\n * A command applied to the record on screen. What it changed is that record —\n * its fields, its sections, the verbs its state allows — and the lists and\n * counts it stands in, so those are asked again now. Every other read is only\n * marked stale, to be asked when next shown: refetching the whole cache on a\n * receipt (the shell, other rooms kept in memory) was most of the two dozen\n * requests one command cost a tenant's ticket page (G173).\n */\nexport function refreshAfterCommand(\n client: QueryClient,\n record: {\n readonly connection: string;\n readonly table: string;\n readonly key: Readonly<Record<string, unknown>>;\n readonly queryScope?: number;\n },\n): void {\n void client.invalidateQueries({ predicate: (query) => query.getObserversCount() === 0, refetchType: 'none' });\n refreshRecordInPlace(client, record, true);\n}\n\n/* The record page's section reads. Those keyed by the record are matched by\n it; those keyed by the plan the server composed for this record (a related\n list, a timeline, a metric) carry no key of their own, so the whole family\n is marked stale and only what is on screen asks again. */\nexport const KEYED_SECTION_READS: Readonly<Record<string, { table: number; key: number }>> = {\n 'page-history': { table: 1, key: 2 },\n 'page-flows': { table: 1, key: 2 },\n 'page-link-fields': { table: 3, key: 4 },\n 'record-children': { table: 1, key: 2 },\n 'record-children-page': { table: 1, key: 2 },\n};\nexport const PLANNED_SECTION_READS = new Set(['page-list', 'page-timeline', 'page-metric', 'page-metric-measure', 'page-breakdown']);\n\nfunction pageSectionRead(\n query: QueryKey,\n table: string,\n key: Readonly<Record<string, unknown>> | undefined,\n same: KeyTest = sameKey,\n): boolean {\n const family = String(query[0]);\n if (PLANNED_SECTION_READS.has(family)) return true;\n if (family === 'page-custom') return query[1] === 'reads' || (query[3] === table && (key === undefined || same(query[4], key)));\n /* What a custom component asked for itself (sdk/hooks.ts useRecord, useRows, useBreakdown) is keyed by a\n resource's name, not the table, and may be a roll-up of the record's own rows, so the family is marked as\n the declared reads are and only what is on screen asks again. Left out, a section drew the status from\n before its page's action until a reload. */\n if (family === 'mistri-ui') return true;\n const at = KEYED_SECTION_READS[family];\n return !!at && query[at.table] === table && (key === undefined || same(query[at.key], key));\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"shared-CdQOMD8J.js","names":[],"sources":["../../../kit/src/client/recordWriteRefresh.ts"],"sourcesContent":["import { type Query, type QueryClient, type QueryKey } from '@tanstack/react-query';\nimport { state } from './core.js';\nimport { connectionGeneration } from './connectionTransition.js';\nimport { captureSessionIdentity, sessionIdentity } from './sessionIdentity.js';\nimport { queryClient } from './components/mount.js';\nimport { composedEpoch } from './composedReads.js';\nimport { canonicalText } from '@mistriwork/engine/shared/recordReadKeys.js';\nimport { setOwnWriteMarker } from './ownWrites.js';\nimport { gatherReads } from './readGathering.js';\n\ntype KeyTest = (value: unknown, key: Readonly<Record<string, unknown>>) => boolean;\n\nfunction sameKey(value: unknown, key: Readonly<Record<string, unknown>>): boolean {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return false;\n const candidate = value as Record<string, unknown>;\n return (\n Object.keys(candidate).length === Object.keys(key).length &&\n Object.keys(key).every((name) => Object.hasOwn(candidate, name) && Object.is(candidate[name], key[name]))\n );\n}\n\n/** Existing query families are not uniformly connection-qualified. Only inspect\n * them while their captured schema/connection/session is still the current owner.\n * No `key` is any key of the table (live sync's `many`), and `same` is how a query's\n * key is judged to be it: exactly, for a confirmed write; as text, for a change the\n * server announces, whose ids past 2^53 are strings (liveInvalidate.ts). */\nexport function queryTouches(\n query: QueryKey,\n connection: string,\n table: string,\n key: Readonly<Record<string, unknown>> | undefined,\n primary: readonly string[],\n same: KeyTest = sameKey,\n): boolean {\n const is = (value: unknown) => key === undefined || same(value, key);\n switch (query[0]) {\n case 'record':\n case 'references':\n return query[1] === table && is(query[2]);\n case 'page-fields':\n return query[2] === table && is(query[3]);\n case 'run':\n // TableRoom includes connection; Dashboard's three-part key does not.\n // Text queries may include joins, so invalidate their owner's list family.\n return (\n (query.length > 3 && query[1] === connection) ||\n (query.length === 3 && typeof query[1] === 'string' && typeof query[2] === 'number')\n );\n case 'count':\n return query[1] === connection;\n case 'page-list':\n return !!query[1] && typeof query[1] === 'object' && (query[1] as { base?: unknown }).base === table;\n case 'peek':\n return (\n query[1] === connection &&\n query[2] === table &&\n (key === undefined || (typeof query[3] === 'string' && Object.hasOwn(key, query[3]) && same({ v: query[4] }, { v: key[query[3]] })))\n );\n case 'peekpanel': {\n const values = query[3];\n return (\n query[1] === connection &&\n query[2] === table &&\n primary.length > 0 &&\n Array.isArray(values) &&\n values.length === primary.length &&\n (key === undefined || primary.every((name, index) => Object.hasOwn(key, name) && same({ v: values[index] }, { v: key[name] })))\n );\n }\n case 'picker':\n case 'picker-labels':\n return query[1] === connection && query[2] === table;\n default:\n return false;\n }\n}\n\n/** Capture before dispatch; invoke only after a confirmed acknowledgement.\n * Stale reads are cancelled before invalidation. Mounted editors retain their\n * confirmed overlay/caret; lists can refresh and records read fresh on remount.\n * Cache failures cannot turn an acknowledged write into a rejected operation. */\nexport function captureRecordWriteRefresh(table: string, inputKey: Readonly<Record<string, unknown>>): () => void {\n const identity = captureSessionIdentity(),\n schema = state.schema;\n const connection = state.activeConnection ?? '',\n generation = connectionGeneration();\n const key = Object.freeze({ ...inputKey });\n const primary = (schema?.tables?.find((candidate: { id: string }) => candidate.id === table)?.columns ?? [])\n .filter((column: { primaryKey?: boolean }) => column.primaryKey)\n .map((column: { name: string }) => column.name) as string[];\n const owns = () =>\n identity === sessionIdentity() &&\n schema === state.schema &&\n connection === (state.activeConnection ?? '') &&\n generation === connectionGeneration();\n let acknowledged = false;\n return () => {\n if (acknowledged || !owns()) return;\n acknowledged = true;\n try {\n const cache = queryClient.getQueryCache();\n const matches = cache.getAll().filter((query) => queryTouches(query.queryKey, connection, table, key, primary));\n // Query object identity also fences a cleared/replaced cache during await.\n const current = (query: Query) => owns() && matches.includes(query) && cache.get(query.queryHash) === query;\n void queryClient\n .cancelQueries({ predicate: current })\n .then(async () => {\n if (!owns()) return;\n await queryClient.invalidateQueries({ predicate: current, refetchType: 'none' });\n if (!owns()) return;\n await queryClient.refetchQueries({\n type: 'active',\n predicate: (query) => current(query) && !['record', 'page-fields', 'references'].includes(String(query.queryKey[0])),\n });\n })\n .catch(() => {\n /* Read reconciliation has no authority over the write outcome. */\n });\n } catch {\n /* A disposed cache does not invalidate a confirmed mutation. */\n }\n };\n}\n\n/**\n * A write landed on the record on screen — a command, a Save that asked for a\n * repaint, a reply posted from its timeline — so its page re-reads where it\n * stands: every read on it asks again and keeps what it shows until the new\n * answer lands. A routed page used to repaint by replacing its walk entry,\n * which started the room over; its reads, kept only while the room is up,\n * went with it, and the record page stood blank until every one of them had\n * been asked again and the page composed (about 8 s for a tenant's ticket).\n * Dialogs and split panes always refreshed this way.\n *\n * Asked once per write: a command's receipt refreshes the record, and the\n * form's Done (or a one-click verb's end) asks the same of the host a moment\n * later. With no write sent or answered between them (composedReads.ts\n * composedEpoch), the second has nothing new to read, and asking it cancelled\n * the first's reads mid-flight and composed the page a second time (G173).\n * A second ask for the same record in the same moment of the writes from\n * another surface — its own scope, its connection spelled its own way — joins\n * what the first began instead: it never cancels it, and asks only what the\n * first did not (a field report: a save on a record page set off its compose,\n * lists and counts twice, the first set cancelled mid-flight).\n */\nexport function refreshRecordInPlace(\n client: QueryClient,\n record: {\n readonly connection: string;\n readonly table: string;\n readonly key: Readonly<Record<string, unknown>>;\n /** The surface's own reads only, when it has an owner's scope. */\n readonly queryScope?: number;\n },\n fields: boolean,\n /** A change another person made, which no write of this page's sits between: asked again though nothing was sent since\n the last ask. With `since` (liveMark), no read already out is cancelled: one that began before the change is let\n land and asked once more, one that began since is joined (askAgain). */\n again = false,\n since?: number,\n): Promise<void> {\n const asked = canonicalText([record.connection, record.table, record.key, record.queryScope ?? null, fields]);\n const epoch = composedEpoch(),\n id = canonicalText([record.table, record.key]);\n const last = refreshed.get(client);\n if (!again && last?.epoch === epoch && last.record === id) {\n if (last.asked.has(asked)) return Promise.resolve();\n last.asked.add(asked);\n /* Measured from the first ask: what it began since is joined, what has landed since is left. */\n again = true;\n since = last.mark;\n } else refreshed.set(client, { record: id, epoch, asked: new Set([asked]), mark: since ?? liveMark(client) });\n /* The page, its lists, its counts and its verbs are asked in this moment: a transport that can, sends them as one. */\n gatherReads();\n /* A write of this page's asks its table's lists and counts again here. A change pushed by someone else does not:\n live sync has already asked each read that change touches, by the tables it names (liveInvalidate.ts), and this\n asked every list and count on the connection once more on top, cancelling those it had just begun. */\n if (since === undefined) captureRecordWriteRefresh(record.table, record.key)();\n /* A write of this page's cancels what was out, since it began before the write; a change pushed by another\n person's write never does, or a steady stream of them starves every read (G211). */\n const ask = (predicate: (query: Query) => boolean, refetch: 'active' | 'none' = 'active'): Promise<void> =>\n since === undefined ? client.invalidateQueries({ predicate, refetchType: refetch }) : askAgain(client, predicate, since, refetch);\n const planned = ask(\n (query) =>\n ['page-root', 'page-plan'].includes(String(query.queryKey[0])) &&\n query.queryKey[1] === record.connection &&\n (record.queryScope === undefined || query.queryKey.at(-1) === record.queryScope),\n );\n const asking: Array<Promise<unknown>> = [planned];\n /* Every page that shows the record's fields, by the record, not by one page's id: a command's receipt does\n not know which page it was run from. */\n if (fields)\n asking.push(\n ask((query) => query.queryKey[0] === 'page-fields' && query.queryKey[2] === record.table && sameKey(query.queryKey[3], record.key)),\n );\n /* With the lists' invalidation above, in the same moment: the verbs' availability follows both as one\n (commandAvailability.ts), and waits for the compose that answers it. */\n asking.push(ask((query) => query.queryKey[0] === 'when' && query.queryKey[1] === record.table));\n /* Every section's read asks again, as the remount did: the write may have\n added a history entry, a timeline row, a flow step or a related row. They\n are marked now and asked once the page's compose is back, which brings\n their answers with it (composedReads.ts): asked beside it, each went out\n on its own (G173). One a new plan has already asked anew is no longer\n stale, so it is not asked twice. */\n const section = (query: Query) => pageSectionRead(query.queryKey, record.table, record.key);\n /* Marked as a pushed change marks: one that has landed since the change already shows it, and is left fresh. */\n void (since === undefined\n ? client.invalidateQueries({ predicate: section, refetchType: 'none' })\n : askAgain(client, section, since, 'none'));\n asking.push(\n planned\n .catch(() => {})\n .then(() => {\n gatherReads();\n const stale = (query: Query) => section(query) && query.state.isInvalidated;\n return since === undefined ? client.refetchQueries({ type: 'active', predicate: stale }) : askAgain(client, stale, since);\n }),\n );\n return Promise.allSettled(asking).then(() => {});\n}\n\n/* ---------- a change another person made: asked again, never cancelled ---------- */\n\n/* One order for the moments that matter here: a change arriving (liveMark) and a read beginning. A read that began\n after a change was marked was answered after its commit, so it already shows it. */\nlet sequence = 0;\nconst begun = new WeakMap<QueryClient, WeakMap<Query, number>>();\n\nfunction readsBegun(client: QueryClient): WeakMap<Query, number> {\n let known = begun.get(client);\n if (known) return known;\n const marks = (known = new WeakMap());\n begun.set(client, marks);\n client.getQueryCache().subscribe((event) => {\n if (event.type !== 'updated') return;\n /* A read that failed, or was cancelled and put back as it was (a revert is a setState), showed nothing new: it is\n no longer one that began since, so the change still asks it again. */\n const type = event.action.type;\n if (type === 'fetch') marks.set(event.query, ++sequence);\n else if (type === 'error' || type === 'setState') marks.delete(event.query);\n });\n return known;\n}\n\n/** The moment a pushed change arrived, in the order reads begin in; reads of `client` are followed from now on. */\nexport function liveMark(client: QueryClient): number {\n readsBegun(client);\n return ++sequence;\n}\n/* A write of this page's is marked as it is answered: its echo on the live stream is measured from there (ownWrites.ts). */\nsetOwnWriteMarker(() => liveMark(queryClient));\n\n/**\n * Ask the reads `predicate` matches again for a change marked at `since` (liveMark), never cancelling one already out:\n * a read that began before the change is let land and then asked once more, a read that began since is joined, and a\n * read that has landed since is left as it is. Inactive reads are only marked stale. Invalidating instead cancelled\n * and restarted every read in flight, so while changes kept coming faster than a read took, none ever landed (G211).\n */\nexport async function askAgain(\n client: QueryClient,\n predicate: (query: Query) => boolean,\n since: number,\n refetch: 'active' | 'none' = 'active',\n): Promise<void> {\n const marks = readsBegun(client);\n const after = (query: Query) => (marks.get(query) ?? 0) > since;\n const landedSince = (query: Query) => after(query) && query.state.fetchStatus !== 'fetching';\n const matched = client\n .getQueryCache()\n .findAll({ predicate })\n .filter((query) => !landedSince(query));\n if (!matched.length) return;\n await client.invalidateQueries({ predicate: (query) => matched.includes(query), refetchType: 'none' });\n if (refetch === 'none') return;\n const active = matched.filter((query) => query.isActive());\n const behind = active.filter((query) => query.state.fetchStatus === 'fetching' && !after(query));\n /* Joined, not cancelled: each settles as it would have, and is then asked once more. */\n if (behind.length) await client.refetchQueries({ predicate: (query) => behind.includes(query) }, { cancelRefetch: false });\n const asking = active.filter((query) => !landedSince(query));\n if (asking.length) await client.refetchQueries({ predicate: (query) => asking.includes(query) }, { cancelRefetch: false });\n}\n/* Per cache, the record last asked again and where the writes stood then. */\nconst refreshed = new WeakMap<QueryClient, { record: string; epoch: number; asked: Set<string>; mark: number }>();\n\n/**\n * A command applied to the record on screen. What it changed is that record —\n * its fields, its sections, the verbs its state allows — and the lists and\n * counts it stands in, so those are asked again now. Every other read is only\n * marked stale, to be asked when next shown: refetching the whole cache on a\n * receipt (the shell, other rooms kept in memory) was most of the two dozen\n * requests one command cost a tenant's ticket page (G173).\n */\nexport function refreshAfterCommand(\n client: QueryClient,\n record: {\n readonly connection: string;\n readonly table: string;\n readonly key: Readonly<Record<string, unknown>>;\n readonly queryScope?: number;\n },\n): void {\n void client.invalidateQueries({ predicate: (query) => query.getObserversCount() === 0, refetchType: 'none' });\n refreshRecordInPlace(client, record, true);\n}\n\n/* The record page's section reads. Those keyed by the record are matched by\n it; those keyed by the plan the server composed for this record (a related\n list, a timeline, a metric) carry no key of their own, so the whole family\n is marked stale and only what is on screen asks again. */\nexport const KEYED_SECTION_READS: Readonly<Record<string, { table: number; key: number }>> = {\n 'page-history': { table: 1, key: 2 },\n 'page-flows': { table: 1, key: 2 },\n 'page-link-fields': { table: 3, key: 4 },\n 'record-children': { table: 1, key: 2 },\n 'record-children-page': { table: 1, key: 2 },\n};\nexport const PLANNED_SECTION_READS = new Set(['page-list', 'page-timeline', 'page-metric', 'page-metric-measure', 'page-breakdown']);\n\nfunction pageSectionRead(\n query: QueryKey,\n table: string,\n key: Readonly<Record<string, unknown>> | undefined,\n same: KeyTest = sameKey,\n): boolean {\n const family = String(query[0]);\n if (PLANNED_SECTION_READS.has(family)) return true;\n if (family === 'page-custom') return query[1] === 'reads' || (query[3] === table && (key === undefined || same(query[4], key)));\n /* What a custom component asked for itself (sdk/hooks.ts useRecord, useRows, useBreakdown) is keyed by a\n resource's name, not the table, and may be a roll-up of the record's own rows, so the family is marked as\n the declared reads are and only what is on screen asks again. Left out, a section drew the status from\n before its page's action until a reload. */\n if (family === 'mistri-ui') return true;\n const at = KEYED_SECTION_READS[family];\n return !!at && query[at.table] === table && (key === undefined || same(query[at.key], key));\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { n as __exportAll } from "./shared-C-UrYobY.js";
|
|
2
2
|
import { n as PALETTE_TOKENS, r as RADIUS_TOKENS, t as FONT_TOKENS } from "./shared-hfXqN0xE.js";
|
|
3
3
|
import { nt as Button } from "./shared-poc11xxo.js";
|
|
4
|
-
import { A as Tone, C as Loaded, D as Stack, E as Segmented, M as SplitListDetail, O as Stat, S as Icon, T as Row, _ as useVisitor, a as useComposer, b as Empty, c as useFormat, d as useNavigate, f as useRecord, g as useViewer, h as useToken, i as useCommand, j as Value, k as Table, l as useLook, m as useSectionSize, n as useAnalytics, o as useFile, p as useRows, r as useBreakdown, s as useFlags, u as useMessage, v as Card, w as Meter, x as Heading, y as Columns } from "./shared-
|
|
4
|
+
import { A as Tone, C as Loaded, D as Stack, E as Segmented, M as SplitListDetail, O as Stat, S as Icon, T as Row, _ as useVisitor, a as useComposer, b as Empty, c as useFormat, d as useNavigate, f as useRecord, g as useViewer, h as useToken, i as useCommand, j as Value, k as Table, l as useLook, m as useSectionSize, n as useAnalytics, o as useFile, p as useRows, r as useBreakdown, s as useFlags, u as useMessage, v as Card, w as Meter, x as Heading, y as Columns } from "./shared-TrGbd1FY.js";
|
|
5
5
|
import { t as Dropdown } from "./shared-gtzTT5Z7.js";
|
|
6
6
|
import * as React$1 from "react";
|
|
7
7
|
import { Fragment as Fragment$1, useCallback as useCallback$1, useContext as useContext$1, useEffect as useEffect$1, useId as useId$1, useMemo as useMemo$1, useReducer as useReducer$1, useRef as useRef$1, useState as useState$1 } from "react";
|
|
@@ -120,4 +120,4 @@ var sdk_exports = /* @__PURE__ */ __exportAll({
|
|
|
120
120
|
});
|
|
121
121
|
export { useContext$1 as a, useMemo$1 as c, useState$1 as d, UI_TOKENS as f, useCallback$1 as i, useReducer$1 as l, React$1 as n, useEffect$1 as o, sdk_exports as r, useId$1 as s, Fragment$1 as t, useRef$1 as u };
|
|
122
122
|
|
|
123
|
-
//# sourceMappingURL=shared-
|
|
123
|
+
//# sourceMappingURL=shared-CdiPYlTh.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared-
|
|
1
|
+
{"version":3,"file":"shared-CdiPYlTh.js","names":[],"sources":["../../../kit/src/shared/uiTokens.ts","../../src/client/components/sdk/index.ts"],"sourcesContent":["/**\n * The custom properties a custom component may read: `@mistriwork/mistri/ui` exports\n * them as `tokens`, and `mistri check` holds a component's `var(--…)` to\n * them. They are not listed by hand a second time — the theme's roles, faces\n * and corners are read off the tables the theme wears them from\n * (themeTokens.ts), so a role added there is a token here. Only the sheets'\n * own steps (space, type sizes, motion, depth, the larger corners) are named below,\n * because no theme role carries them.\n */\nimport { FONT_TOKENS, PALETTE_TOKENS, RADIUS_TOKENS } from '@mistriwork/engine/shared/themeTokens.js';\n\nconst SHEET_TOKENS = [\n '--radius-lg',\n '--radius-pop',\n '--radius-panel',\n '--radius-dialog',\n '--radius-item',\n '--type-ui',\n '--type-display',\n '--type-list-title',\n '--type-record-title',\n '--space-1',\n '--space-2',\n '--space-3',\n '--space-4',\n '--space-5',\n '--space-6',\n '--space-7',\n '--space-8',\n '--space-2h',\n '--space-3h',\n '--space-4h',\n '--section-seam',\n '--page-measure',\n '--room-inset',\n '--row-h',\n '--text-xs',\n '--text-sm',\n '--text-base',\n '--text-md',\n '--text-lg',\n '--text-xl',\n '--heading-weight',\n '--track-caps',\n '--track-display',\n '--track-title',\n '--t-hover',\n '--t-press',\n '--t-popover',\n '--t-panel',\n '--ease-out',\n '--ease-in-out',\n '--shadow-pop',\n '--shadow-panel',\n '--shadow-modal',\n '--scrim',\n '--scrim-light',\n '--focus-width',\n '--focus-offset',\n] as const;\n\n/** Every token a component may name, theme roles first, then faces, corners and the sheets' own steps. */\nexport const UI_TOKENS = [\n ...Object.values(PALETTE_TOKENS),\n ...Object.values(FONT_TOKENS),\n ...Object.values(RADIUS_TOKENS),\n ...SHEET_TOKENS,\n] as readonly string[];\n\n/** What a reader reaches for from another system's vocabulary, and the token that says it here. */\nconst WORDS: Record<string, string> = {\n negative: '--status-critical',\n danger: '--status-critical',\n error: '--status-critical',\n destructive: '--status-critical',\n red: '--status-critical',\n positive: '--status-good',\n success: '--status-good',\n green: '--status-good',\n warning: '--status-warning',\n caution: '--status-warning',\n info: '--status-info',\n text: '--ink',\n foreground: '--ink',\n fg: '--ink',\n 'text-muted': '--ink-muted',\n muted: '--ink-muted',\n secondary: '--ink-muted',\n subtle: '--ink-subtle',\n background: '--ground',\n bg: '--ground',\n page: '--ground',\n card: '--surface',\n panel: '--surface',\n border: '--line',\n divider: '--line',\n primary: '--accent',\n brand: '--accent',\n 'accent-color': '--accent',\n font: '--sans',\n 'font-family': '--sans',\n 'font-mono': '--mono',\n 'border-radius': '--radius',\n rounded: '--radius',\n // Renamed before 1.0, with `nav.currentInk`: words on a fill are on<Fill>.\n 'nav-current-ink': '--nav-on-current',\n};\n\nfunction distance(a: string, b: string): number {\n const row = Array.from({ length: b.length + 1 }, (_, i) => i);\n for (let i = 1; i <= a.length; i++) {\n let diagonal = row[0]!;\n row[0] = i;\n for (let j = 1; j <= b.length; j++) {\n const above = row[j]!;\n row[j] = Math.min(row[j]! + 1, row[j - 1]! + 1, diagonal + (a[i - 1] === b[j - 1] ? 0 : 1));\n diagonal = above;\n }\n }\n return row[b.length]!;\n}\n\n/** The token a name was most likely meant to be: the word another system uses for it, else the nearest spelling. */\nexport function nearestToken(name: string): string | undefined {\n const bare = name.replace(/^--/, '').toLowerCase();\n const said = WORDS[bare];\n if (said) return said;\n let best: string | undefined;\n let bestDistance = 3;\n for (const token of UI_TOKENS) {\n const gap = distance(bare, token.slice(2));\n if (gap < bestDistance) [best, bestDistance] = [token, gap];\n }\n return best;\n}\n","/**\n * `@mistriwork/mistri/ui`: everything a custom component imports from tablewalk. The\n * host's own React (re-exported, so a component can take its hooks from here\n * and never resolve a React of its own), the kit (kit.tsx) and the hooks\n * (hooks.ts). Nothing else of the client is reachable through it: no store,\n * no walk, no raw request.\n *\n * In the page this module is the page's own, handed to components through\n * the host modules (packages/mistri/src/server/app/componentSdk.ts); published, it is built to\n * dist/ui for a component's tests (config/vite.ui.config.ts), with its types in\n * packages/mistri/schema/ui.d.ts. Its value exports are `UI_EXPORTS` (shared/uiSdk.ts),\n * which a test holds to this list.\n */\nimport * as React from 'react';\n\nexport { React };\nexport { UI_TOKENS as tokens } from '@mistriwork/kit/shared/uiTokens.js';\nexport { Fragment, useCallback, useContext, useEffect, useId, useMemo, useReducer, useRef, useState } from 'react';\nexport {\n Button,\n Card,\n Columns,\n Dropdown,\n Empty,\n Heading,\n Icon,\n Loaded,\n Meter,\n Row,\n Segmented,\n SplitListDetail,\n Stack,\n Stat,\n Table,\n Tone,\n Value,\n} from './kit.js';\nexport {\n useAnalytics,\n useBreakdown,\n useComposer,\n useCommand,\n useFile,\n useFlags,\n useFormat,\n useLook,\n useMessage,\n useNavigate,\n useRecord,\n useRows,\n useSectionSize,\n useToken,\n useViewer,\n useVisitor,\n} from './hooks.js';\n"],"mappings":";;;;;;;;;;;;;;;;;AAWA,IAAM,eAAe;CACnB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;AAGA,IAAa,YAAY;CACvB,GAAG,OAAO,OAAO,cAAc;CAC/B,GAAG,OAAO,OAAO,WAAW;CAC5B,GAAG,OAAO,OAAO,aAAa;CAC9B,GAAG;AACL"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import "./shared-
|
|
1
|
+
import "./shared-BoLbc2WD.js";
|
|
2
2
|
import { Wn as viewportBox } from "./shared-CRr4kJXB.js";
|
|
3
3
|
import { useLayoutEffect, useRef, useState } from "react";
|
|
4
4
|
import { flushSync } from "react-dom";
|
|
@@ -125,4 +125,4 @@ function useTabFold(count, active) {
|
|
|
125
125
|
var NONE = /* @__PURE__ */ new Set();
|
|
126
126
|
export { useTabFold as t };
|
|
127
127
|
|
|
128
|
-
//# sourceMappingURL=shared-
|
|
128
|
+
//# sourceMappingURL=shared-CepLAhwm.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared-DA8_pVRZ.js","names":[],"sources":["../../../kit/src/client/components/useTabFold.ts"],"sourcesContent":["/**\n * A strip of tabs that fits its row: the tabs that do not fit go under a More menu at its end, never past the edge\n * for the reader to scroll to (design.md, \"Nothing scrolls sideways\"). A tenant App's strips ran 648px in a 627px room at a\n * desk, and past a phone's on its cases, alerts and approvals, and a strip that scrolls hides that there is more.\n *\n * Every tab stays drawn, so each can be measured as it is (its count arriving, the look's font loading): one that is\n * folded wears `data-folded`, which the stylesheet takes out of the row (absolute, hidden) without changing its width.\n * The tab chosen is never folded: it keeps its place in order, and the ones before it give way. The fold is decided\n * in a layout effect, before the first paint, and again before the paint after any size changes, so a tab is never\n * seen in one place and then another.\n */\nimport { useLayoutEffect, useRef, useState, type RefObject } from 'react';\nimport { flushSync } from 'react-dom';\nimport { viewportBox } from '../core.js';\n\n/**\n * Which items are shown: as many as fit in order, with room left for More where any do not, and the chosen one always\n * among them (the last that fit give way to it). `widths` are each item's own, `gap` the space between two.\n */\nexport function foldTabs(widths: readonly number[], room: number, more: number, gap: number, active: number): number[] {\n const all = widths.map((_, i) => i);\n const span = (items: readonly number[]) => items.reduce((sum, i) => sum + widths[i], 0) + gap * Math.max(0, items.length - 1);\n if (span(all) <= room) return all;\n /* More stands after the shown ones, a gap before it. */\n const budget = room - more - gap;\n const shown: number[] = [];\n for (const i of all) {\n if (span([...shown, i]) > budget) break;\n shown.push(i);\n }\n if (active >= 0 && active < widths.length && !shown.includes(active)) {\n while (shown.length && span([...shown, active]) > budget) shown.pop();\n shown.push(active);\n }\n return shown;\n}\n\n/**\n * The least a strip can be drawn at and still hold what it never folds: the chosen tab and, beside it, More, the gap\n * between them (no more than every tab takes). Narrower, the chosen tab ran under More: Compass's contacts at 320px drew\n * \"Primary contacts 150\" and More over each other, beside the Records/Table switch.\n */\nexport function leastStrip(widths: readonly number[], more: number, gap: number, active: number): number {\n const natural = widths.reduce((sum, width) => sum + width, 0) + gap * Math.max(0, widths.length - 1);\n const chosen = widths[active] ?? 0;\n return Math.min(natural, chosen + (chosen ? gap : 0) + more);\n}\n\n/* A tab's width is fractional (its words), and a strip's room is whole pixels: what a sum of fractions may lose. */\nconst SLACK = 0.5;\n\n/**\n * The fold of one strip. Its tabs wear `data-fold=\"<index>\"` (a wrapper, where a tab has a button beside it), in a row\n * whose gap is the strip's, and its More wears `data-fold-more`; `active` is the chosen tab's index, `count` how many.\n * Returns the ref for the strip and the indices folded under More.\n */\nexport function useTabFold(count: number, active: number): { strip: RefObject<HTMLDivElement | null>; folded: ReadonlySet<number> } {\n const strip = useRef<HTMLDivElement | null>(null);\n const [folded, setFolded] = useState<ReadonlySet<number>>(NONE);\n const latest = useRef({ active, folded });\n latest.current = { active, folded };\n\n useLayoutEffect(() => {\n const box = strip.current;\n if (!box) return;\n let frame = 0;\n /* `effect` is the layout effect, `observer` a ResizeObserver's callback, `frame` the next frame's start. */\n const measure = (from: 'effect' | 'observer' | 'frame') => {\n const items = [...box.querySelectorAll<HTMLElement>('[data-fold]')];\n const more = box.querySelector<HTMLElement>('[data-fold-more]');\n const style = getComputedStyle(box);\n /* Layout pixels throughout (the ruler's boxes, clientWidth, the computed gap), so the density zoom cancels out.\n Widths as drawn, fractions and all: offsetWidth rounds each tab, which overstated a row of six by 3px and moved\n the filters beside it. */\n const gap = parseFloat(style.columnGap || '0') || 0;\n const widths: number[] = [];\n for (const item of items) widths[Number(item.dataset.fold)] = viewportBox(item).width;\n for (let i = 0; i < widths.length; i++) widths[i] ??= 0;\n const natural = widths.reduce((sum, width) => sum + width, 0) + gap * Math.max(0, widths.length - 1);\n const room = box.clientWidth - parseFloat(style.paddingLeft || '0') - parseFloat(style.paddingRight || '0');\n if (room <= 0) return;\n const moreWidth = more ? viewportBox(more).width : 0;\n const shown = new Set(foldTabs(widths, room + SLACK, moreWidth, gap, latest.current.active));\n const next = new Set(widths.map((_, i) => i).filter((i) => !shown.has(i)));\n /* For a row that sizes the strip by its content (a list's controls): with nothing folded the strip is its tabs'\n width on its own; with some folded it goes on asking for every tab's, so it gives way only where the row\n cannot hold them, and takes the tabs back when the row can. Moving from one to the other leaves the strip\n the size it is, both being its tabs' width at that moment. */\n const edges = box.offsetWidth - box.clientWidth + parseFloat(style.paddingLeft || '0') + parseFloat(style.paddingRight || '0');\n const basis = next.size ? `${Math.round((natural + edges) * 100) / 100}px` : '';\n const asked = box.style.getPropertyValue('--tabs-natural');\n /* The strip's floor (`--tabs-least`, structure.css): a row that cannot hold it beside the strip's neighbors puts\n the neighbor on the next line, or scrolls, rather than draw More over the chosen tab. */\n const least = `${Math.ceil(leastStrip(widths, moreWidth, gap, latest.current.active) + edges)}px`;\n const floor = box.style.getPropertyValue('--tabs-least');\n if (floor !== least) {\n if (from === 'observer' && floor) {\n cancelAnimationFrame(frame);\n frame = requestAnimationFrame(() => measure('frame'));\n return;\n }\n box.style.setProperty('--tabs-least', least);\n }\n if (asked !== basis) {\n /* A new width while folded resizes the strip itself, which a ResizeObserver's callback may not do to an\n element it has just been told about (the browser reports a loop, and drops what the page's other observers\n were owed). The next frame asks for it, before that frame paints, and folds to the size it gives. */\n if (from === 'observer' && asked && basis) {\n cancelAnimationFrame(frame);\n frame = requestAnimationFrame(() => measure('frame'));\n return;\n }\n if (basis) box.style.setProperty('--tabs-natural', basis);\n else box.style.removeProperty('--tabs-natural');\n }\n const before = latest.current.folded;\n if (next.size === before.size && [...next].every((i) => before.has(i))) return;\n const value = next.size ? next : NONE;\n /* After a resize, before that frame paints: the strip is never drawn overrunning, or folded for a size gone.\n A fold takes tabs out of the row without resizing the strip, so it is safe inside the observer's callback. */\n if (from === 'effect') setFolded(value);\n else flushSync(() => setFolded(value));\n };\n measure('effect');\n if (typeof ResizeObserver === 'undefined') return;\n const watch = new ResizeObserver(() => measure('observer'));\n watch.observe(box);\n for (const item of box.querySelectorAll<HTMLElement>('[data-fold], [data-fold-more]')) watch.observe(item);\n return () => {\n cancelAnimationFrame(frame);\n watch.disconnect();\n };\n }, [count, active]);\n\n return { strip, folded };\n}\n\nconst NONE: ReadonlySet<number> = new Set();\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"shared-CepLAhwm.js","names":[],"sources":["../../../kit/src/client/components/useTabFold.ts"],"sourcesContent":["/**\n * A strip of tabs that fits its row: the tabs that do not fit go under a More menu at its end, never past the edge\n * for the reader to scroll to (design.md, \"Nothing scrolls sideways\"). A tenant App's strips ran 648px in a 627px room at a\n * desk, and past a phone's on its cases, alerts and approvals, and a strip that scrolls hides that there is more.\n *\n * Every tab stays drawn, so each can be measured as it is (its count arriving, the look's font loading): one that is\n * folded wears `data-folded`, which the stylesheet takes out of the row (absolute, hidden) without changing its width.\n * The tab chosen is never folded: it keeps its place in order, and the ones before it give way. The fold is decided\n * in a layout effect, before the first paint, and again before the paint after any size changes, so a tab is never\n * seen in one place and then another.\n */\nimport { useLayoutEffect, useRef, useState, type RefObject } from 'react';\nimport { flushSync } from 'react-dom';\nimport { viewportBox } from '../core.js';\n\n/**\n * Which items are shown: as many as fit in order, with room left for More where any do not, and the chosen one always\n * among them (the last that fit give way to it). `widths` are each item's own, `gap` the space between two.\n */\nexport function foldTabs(widths: readonly number[], room: number, more: number, gap: number, active: number): number[] {\n const all = widths.map((_, i) => i);\n const span = (items: readonly number[]) => items.reduce((sum, i) => sum + widths[i], 0) + gap * Math.max(0, items.length - 1);\n if (span(all) <= room) return all;\n /* More stands after the shown ones, a gap before it. */\n const budget = room - more - gap;\n const shown: number[] = [];\n for (const i of all) {\n if (span([...shown, i]) > budget) break;\n shown.push(i);\n }\n if (active >= 0 && active < widths.length && !shown.includes(active)) {\n while (shown.length && span([...shown, active]) > budget) shown.pop();\n shown.push(active);\n }\n return shown;\n}\n\n/**\n * The least a strip can be drawn at and still hold what it never folds: the chosen tab and, beside it, More, the gap\n * between them (no more than every tab takes). Narrower, the chosen tab ran under More: Compass's contacts at 320px drew\n * \"Primary contacts 150\" and More over each other, beside the Records/Table switch.\n */\nexport function leastStrip(widths: readonly number[], more: number, gap: number, active: number): number {\n const natural = widths.reduce((sum, width) => sum + width, 0) + gap * Math.max(0, widths.length - 1);\n const chosen = widths[active] ?? 0;\n return Math.min(natural, chosen + (chosen ? gap : 0) + more);\n}\n\n/* A tab's width is fractional (its words), and a strip's room is whole pixels: what a sum of fractions may lose. */\nconst SLACK = 0.5;\n\n/**\n * The fold of one strip. Its tabs wear `data-fold=\"<index>\"` (a wrapper, where a tab has a button beside it), in a row\n * whose gap is the strip's, and its More wears `data-fold-more`; `active` is the chosen tab's index, `count` how many.\n * Returns the ref for the strip and the indices folded under More.\n */\nexport function useTabFold(count: number, active: number): { strip: RefObject<HTMLDivElement | null>; folded: ReadonlySet<number> } {\n const strip = useRef<HTMLDivElement | null>(null);\n const [folded, setFolded] = useState<ReadonlySet<number>>(NONE);\n const latest = useRef({ active, folded });\n latest.current = { active, folded };\n\n useLayoutEffect(() => {\n const box = strip.current;\n if (!box) return;\n let frame = 0;\n /* `effect` is the layout effect, `observer` a ResizeObserver's callback, `frame` the next frame's start. */\n const measure = (from: 'effect' | 'observer' | 'frame') => {\n const items = [...box.querySelectorAll<HTMLElement>('[data-fold]')];\n const more = box.querySelector<HTMLElement>('[data-fold-more]');\n const style = getComputedStyle(box);\n /* Layout pixels throughout (the ruler's boxes, clientWidth, the computed gap), so the density zoom cancels out.\n Widths as drawn, fractions and all: offsetWidth rounds each tab, which overstated a row of six by 3px and moved\n the filters beside it. */\n const gap = parseFloat(style.columnGap || '0') || 0;\n const widths: number[] = [];\n for (const item of items) widths[Number(item.dataset.fold)] = viewportBox(item).width;\n for (let i = 0; i < widths.length; i++) widths[i] ??= 0;\n const natural = widths.reduce((sum, width) => sum + width, 0) + gap * Math.max(0, widths.length - 1);\n const room = box.clientWidth - parseFloat(style.paddingLeft || '0') - parseFloat(style.paddingRight || '0');\n if (room <= 0) return;\n const moreWidth = more ? viewportBox(more).width : 0;\n const shown = new Set(foldTabs(widths, room + SLACK, moreWidth, gap, latest.current.active));\n const next = new Set(widths.map((_, i) => i).filter((i) => !shown.has(i)));\n /* For a row that sizes the strip by its content (a list's controls): with nothing folded the strip is its tabs'\n width on its own; with some folded it goes on asking for every tab's, so it gives way only where the row\n cannot hold them, and takes the tabs back when the row can. Moving from one to the other leaves the strip\n the size it is, both being its tabs' width at that moment. */\n const edges = box.offsetWidth - box.clientWidth + parseFloat(style.paddingLeft || '0') + parseFloat(style.paddingRight || '0');\n const basis = next.size ? `${Math.round((natural + edges) * 100) / 100}px` : '';\n const asked = box.style.getPropertyValue('--tabs-natural');\n /* The strip's floor (`--tabs-least`, structure.css): a row that cannot hold it beside the strip's neighbors puts\n the neighbor on the next line, or scrolls, rather than draw More over the chosen tab. */\n const least = `${Math.ceil(leastStrip(widths, moreWidth, gap, latest.current.active) + edges)}px`;\n const floor = box.style.getPropertyValue('--tabs-least');\n if (floor !== least) {\n if (from === 'observer' && floor) {\n cancelAnimationFrame(frame);\n frame = requestAnimationFrame(() => measure('frame'));\n return;\n }\n box.style.setProperty('--tabs-least', least);\n }\n if (asked !== basis) {\n /* A new width while folded resizes the strip itself, which a ResizeObserver's callback may not do to an\n element it has just been told about (the browser reports a loop, and drops what the page's other observers\n were owed). The next frame asks for it, before that frame paints, and folds to the size it gives. */\n if (from === 'observer' && asked && basis) {\n cancelAnimationFrame(frame);\n frame = requestAnimationFrame(() => measure('frame'));\n return;\n }\n if (basis) box.style.setProperty('--tabs-natural', basis);\n else box.style.removeProperty('--tabs-natural');\n }\n const before = latest.current.folded;\n if (next.size === before.size && [...next].every((i) => before.has(i))) return;\n const value = next.size ? next : NONE;\n /* After a resize, before that frame paints: the strip is never drawn overrunning, or folded for a size gone.\n A fold takes tabs out of the row without resizing the strip, so it is safe inside the observer's callback. */\n if (from === 'effect') setFolded(value);\n else flushSync(() => setFolded(value));\n };\n measure('effect');\n if (typeof ResizeObserver === 'undefined') return;\n const watch = new ResizeObserver(() => measure('observer'));\n watch.observe(box);\n for (const item of box.querySelectorAll<HTMLElement>('[data-fold], [data-fold-more]')) watch.observe(item);\n return () => {\n cancelAnimationFrame(frame);\n watch.disconnect();\n };\n }, [count, active]);\n\n return { strip, folded };\n}\n\nconst NONE: ReadonlySet<number> = new Set();\n"],"mappings":"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"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { D as columnKind, M as labelColumn, Ot as popupContainer, ft as vocabularyWord, gt as defineMessages, x as wordFor } from "./shared-DJZjSi3J.js";
|
|
2
|
-
import { $ as ownedTails, Q as mentionsColumn, at as MenuPortal, it as MenuPositioner, nt as withCondition, ot as MenuPopup, rt as MenuRoot, st as MenuItem } from "./shared-
|
|
3
|
-
import { d as findTable, s as columnDisplay } from "./shared-
|
|
2
|
+
import { $ as ownedTails, Q as mentionsColumn, at as MenuPortal, it as MenuPositioner, nt as withCondition, ot as MenuPopup, rt as MenuRoot, st as MenuItem } from "./shared-BHsjawAG.js";
|
|
3
|
+
import { d as findTable, s as columnDisplay } from "./shared-BoLbc2WD.js";
|
|
4
4
|
import { i as zoomAnchor, r as layoutViewport } from "./shared-CRr4kJXB.js";
|
|
5
|
-
import { bt as togglePin, xt as Separator, yt as pinnedFor } from "./shared-
|
|
5
|
+
import { bt as togglePin, xt as Separator, yt as pinnedFor } from "./shared-XcSKDp6N.js";
|
|
6
6
|
import { i as PopoverRoot, n as PopoverPositioner, r as PopoverPortal, t as PopoverPopup } from "./shared-QCeL-Jxu.js";
|
|
7
7
|
import { a as nextSort, s as sortDirection } from "./shared-DOvMIC4W.js";
|
|
8
|
-
import { f as facetActive } from "./shared-
|
|
9
|
-
import { t as useConditionWords } from "./shared-
|
|
8
|
+
import { f as facetActive } from "./shared-BIQuK_nq.js";
|
|
9
|
+
import { t as useConditionWords } from "./shared-CrWv5JKH.js";
|
|
10
10
|
import { Fragment, useRef } from "react";
|
|
11
11
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
12
12
|
// packages/kit/src/client/copy/columnMenu/components/appColumnMenuModel.ts
|
|
@@ -226,4 +226,4 @@ function AppColumnMenuPopups({ host, button, open, setOpen, handBack, name, labe
|
|
|
226
226
|
}
|
|
227
227
|
export { AppColumnMenuPopups };
|
|
228
228
|
|
|
229
|
-
//# sourceMappingURL=shared-
|
|
229
|
+
//# sourceMappingURL=shared-Ch82h_Fu.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared-BrYKjrnM.js","names":["say","sayCopy","sayCopy","say","_Fragment","Menu.Root","Menu.Portal","Menu.Positioner","Menu.Popup","Menu.Separator","Menu.Item","Popover.Root","Popover.Portal","Popover.Positioner","Popover.Popup"],"sources":["../../../kit/src/client/copy/columnMenu/components/appColumnMenuModel.ts","../../../kit/src/client/components/appColumnMenuModel.ts","../../../kit/src/client/copy/columnMenu/components/AppColumnMenuPopups.ts","../../../kit/src/client/components/AppColumnMenuPopups.tsx"],"sourcesContent":["/** What appColumnMenuModel says, in the column menu room (packages/kit/src/client/messages.ts says how the catalog is split). */\nimport { defineMessages } from '../../../messages.js';\n\nexport const say = defineMessages({\n oldestFirst: 'Oldest first',\n newestFirst: 'Newest first',\n lowHigh: 'Low → high',\n highLow: 'High → low',\n filterMore: 'Filter…',\n clearFilter: 'Clear filter',\n unpinColumn: 'Unpin column',\n pinColumn: 'Pin column',\n});\n","/**\n * What an App list's column menu offers, before anything is drawn.\n *\n * The Workbench's header menu (ThMenu.tsx) is a power tool: every condition\n * the language has, sampled values, the language itself beside each entry.\n * In an App that was a dozen entries and a scrollbar under a reader who\n * wanted the column sorted or narrowed. So an App's menu has at most five:\n * the two sorts, worded by what the column holds; one Filter… that opens the\n * rail's own control for the column; Clear filter while there is one; and\n * Pin column, last. Pure, so the menu and its tests read one rule.\n */\nimport { columnKind, type ColumnMeta } from '@mistriwork/engine/shared/schema.js';\nimport { say as sayCopy } from '../copy/columnMenu/components/appColumnMenuModel.js';\n\nexport type AppMenuKey = 'asc' | 'desc' | 'filter' | 'clear' | 'pin';\ninterface AppMenuEntry {\n key: AppMenuKey;\n label: string;\n detail?: string;\n}\n\n/**\n * The words the two sorts say, fitted to what the column holds: text reads\n * A → Z, a figure Low → high, a date Oldest first. A flag and a vocabulary\n * name their ends — `No → Yes`, `New → Lost` — in the words the list shows\n * them by: a vocabulary sorts in the order it was declared, a native enum by\n * the engine and one over text through the read's ORDER BY (schema.ts\n * `declaredOrder`), so a pipeline reads as one rather than A → Z.\n */\nexport function sortWords(\n kind: string,\n meta: (Pick<ColumnMeta, 'type'> & { allowed?: readonly string[] }) | undefined,\n say: (value: string) => string = (value) => value,\n): readonly [asc: string, desc: string] {\n const allowed = meta?.allowed;\n if (allowed && allowed.length > 1) {\n const [first, last] = [say(allowed[0]), say(allowed[allowed.length - 1])];\n return [`${first} → ${last}`, `${last} → ${first}`];\n }\n if (kind === 'boolean') {\n const [no, yes] = [say('false'), say('true')];\n return [`${no} → ${yes}`, `${yes} → ${no}`];\n }\n if (kind === 'date') return [sayCopy('oldestFirst'), sayCopy('newestFirst')];\n if (kind === 'number' || (meta && columnKind(meta.type) === 'number')) return [sayCopy('lowHigh'), sayCopy('highLow')];\n return ['A → Z', 'Z → A'];\n}\n\ninterface EntryInput {\n words: readonly [string, string];\n /** Whether the header may sort this column at all (an index, a small table, an API's `sortable`). */\n sortable: boolean;\n /** The order the list is in on this column now, explicit or the default one. */\n current: 'asc' | 'desc' | null;\n /** Whether the column takes a filter (a real column; over an API, one it documents). */\n filterable: boolean;\n /** Whether the reader's question narrows this column beyond the lit tab. */\n filtered: boolean;\n /** What Clear filter takes off, in the reader's words: \"Status is not Done\". */\n cleared?: string;\n pinned: boolean;\n}\n\n/** The menu, in order. An entry that repeats the current sort is dropped: it would do nothing. */\nexport function appMenuEntries({ words, sortable, current, filterable, filtered, cleared, pinned }: EntryInput): AppMenuEntry[] {\n const entries: AppMenuEntry[] = [];\n if (sortable && current !== 'asc') entries.push({ key: 'asc', label: words[0] });\n if (sortable && current !== 'desc') entries.push({ key: 'desc', label: words[1] });\n if (filterable) entries.push({ key: 'filter', label: sayCopy('filterMore') });\n if (filterable && filtered) entries.push({ key: 'clear', label: sayCopy('clearFilter'), ...(cleared ? { detail: cleared } : {}) });\n entries.push({ key: 'pin', label: pinned ? sayCopy('unpinColumn') : sayCopy('pinColumn') });\n return entries;\n}\n","/** What AppColumnMenuPopups says, in the column menu room (packages/kit/src/client/messages.ts says how the catalog is split). */\nimport { defineMessages } from '../../../messages.js';\n\nexport const say = defineMessages({\n labelColumn: '{label} column',\n filterBy: 'Filter by {label}',\n});\n","/**\n * The App column menu's open half: its entries, and the rail's control\n * Filter… opens (AppColumnMenu.tsx draws the ⌄ that opens it).\n *\n * Every column of an App list's grid draws a ⌄, and a reader opens few of\n * them; so what a menu says and does arrives on demand, the first time one\n * is hovered, focused or opened, and a list's first page carries only the\n * buttons.\n */\nimport { Fragment, useRef, type RefObject } from 'react';\nimport { Menu } from '@base-ui/react/menu';\nimport { Popover } from '@base-ui/react/popover';\nimport { layoutViewport, zoomAnchor } from '@mistriwork/ui/internal/anchor.js';\nimport { columnDisplay, findTable, labelColumn } from '../core.js';\nimport { nextSort, sortDirection } from '../clauses.js';\nimport { mentionsColumn, ownedTails, withCondition } from '../filterbar.js';\nimport { pinnedFor, togglePin } from '../pins.js';\nimport { vocabularyWord } from '@mistriwork/engine/shared/model.js';\nimport type { ColumnMeta, TableMeta } from '@mistriwork/engine/shared/schema.js';\nimport { wordFor, type DisplayRule } from './valueModel.js';\nimport { appMenuEntries, sortWords, type AppMenuKey } from './appColumnMenuModel.js';\nimport { facetActive } from './filterRailModel.js';\nimport { useConditionWords } from './useConditionWords.js';\nimport type { AppColumnMenuHost, ColumnMenuProps } from './AppColumnMenu.js';\nimport { say as sayCopy } from '../copy/columnMenu/components/AppColumnMenuPopups.js';\nimport { popupContainer } from '../shellHost.js';\n\n/* How a flag's two values read where no display rule words them. */\nconst FLAG_WORDS: Record<string, string> = { true: sayCopy('common.yes'), false: sayCopy('common.no') };\n\ninterface PopupsProps extends ColumnMenuProps {\n host: RefObject<AppColumnMenuHost | null>;\n button: RefObject<HTMLButtonElement | null>;\n open: 'menu' | 'filter' | null;\n setOpen: (next: 'menu' | 'filter' | null | ((was: 'menu' | 'filter' | null) => 'menu' | 'filter' | null)) => void;\n /** Where the focus goes as the menu closes: back to the ⌄, or on into the popover or the rail. */\n handBack: RefObject<boolean>;\n}\n\nexport function AppColumnMenuPopups({\n host,\n button,\n open,\n setOpen,\n handBack,\n name,\n label,\n kind,\n meta,\n sortable,\n current,\n columns,\n drawnBy,\n}: PopupsProps) {\n const popup = useRef<HTMLDivElement>(null);\n /* The column's own conditions, said as its chip says them, beside Clear filter. */\n const tails = host.current ? (ownedTails(host.current.refinement, name) as string[]) : [];\n const { speaker, sayTails } = useConditionWords(\n host.current?.table,\n tails.map((tail) => `${name} ${tail}`),\n );\n const h = host.current;\n if (!h) return null;\n const box = h.boxFor(name);\n const column = (box?.meta ?? meta) as (ColumnMeta & { allowed?: string[] }) | undefined;\n const rule = columnDisplay(h.table.id, name) as DisplayRule | null;\n const say = (value: string) => wordFor(rule, value) ?? (column?.allowed?.length ? vocabularyWord(value) : (FLAG_WORDS[value] ?? value));\n /* A reference sorts by the name it is drawn by, not the id under it: an\n order by `owner_id` is an order nobody reading the list can see. */\n const target = column?.references ? (findTable(column.references.table) as TableMeta | undefined) : undefined;\n const byName = drawnBy ?? (target && labelColumn(target) ? `${name}.${labelColumn(target)}` : undefined);\n const sortPath = column?.references ? byName : name;\n const order = sortPath && sortPath !== name ? (sortDirection(h.query, sortPath) as 'asc' | 'desc' | null) : current;\n const filterable = Boolean(box?.meta) && (!h.table.filterable || h.table.filterable.includes(name));\n const pinned = pinnedFor(h.table, columns, h.listKey).includes(name);\n const entries = appMenuEntries({\n words: sortPath === name ? sortWords(kind, column, say) : sortWords('text', undefined),\n sortable: sortable && Boolean(sortPath),\n current: order,\n filterable,\n filtered: facetActive(h.refinement, name, h.tabQuery),\n cleared: speaker && tails.length ? sayTails(speaker, name, tails) : undefined,\n pinned,\n });\n\n const choose = (key: AppMenuKey) => {\n if (key === 'filter') {\n handBack.current = false;\n const facet = h.railFacet(name);\n /* The value already chosen, else the facet's first field: its Clear comes first in the markup, not in the reading. */\n const control =\n facet?.querySelector<HTMLElement>('input:checked') ??\n facet?.querySelector<HTMLElement>('input:not([type=\"hidden\"])') ??\n facet?.querySelector<HTMLElement>('button');\n if (!facet || !control) {\n setOpen('filter');\n return;\n }\n setOpen(null);\n /* Once the menu has gone: while it is open the page outside it is inert, and takes no focus. */\n setTimeout(() => {\n facet.scrollIntoView?.({ block: 'nearest' });\n control.focus();\n }, 0);\n return;\n }\n setOpen(null);\n if ((key === 'asc' || key === 'desc') && sortPath) h.navigate(nextSort(h.query, sortPath, key), name);\n else if (key === 'clear') h.apply(withCondition(h.refinement, name, ''), name);\n else if (key === 'pin') togglePin(h.table, columns, name, h.listKey);\n };\n\n return (\n <>\n {/* Base UI owns the menu's keyboard: focus moves in on open, the arrows\n walk the entries, Escape closes it and hands the focus back to the ⌄. */}\n <Menu.Root\n open={open === 'menu'}\n onOpenChange={(next) => {\n if (!next) setOpen((was) => (was === 'menu' ? null : was));\n }}\n >\n <Menu.Portal container={popupContainer()}>\n <Menu.Positioner\n anchor={() => (button.current ? zoomAnchor(button.current) : null)}\n positionMethod=\"fixed\"\n side=\"bottom\"\n align=\"start\"\n sideOffset={4}\n collisionBoundary={layoutViewport()}\n collisionPadding={12}\n style={{ zIndex: 40 }}\n >\n <Menu.Popup\n className=\"th-menu th-menu-app\"\n aria-label={sayCopy('labelColumn', { label })}\n finalFocus={() => (handBack.current && button.current?.isConnected ? button.current : false)}\n >\n {entries.map((entry, i) => (\n <Fragment key={entry.key}>\n {/* The pin is about reading the table, not narrowing it: last, and set apart. */}\n {entry.key === 'pin' && i > 0 ? <Menu.Separator className=\"th-menu-sep\" /> : null}\n <Menu.Item\n render={<button type=\"button\" className={`th-menu-item${entry.key === 'pin' ? ' th-menu-quiet' : ''}`} />}\n nativeButton\n closeOnClick={false}\n onClick={() => choose(entry.key)}\n aria-label={entry.detail ? `${entry.label}: ${entry.detail}` : undefined}\n >\n <span className=\"th-menu-label\">{entry.label}</span>\n {entry.detail ? <span className=\"th-menu-said\">{entry.detail}</span> : null}\n </Menu.Item>\n </Fragment>\n ))}\n </Menu.Popup>\n </Menu.Positioner>\n </Menu.Portal>\n </Menu.Root>\n {box && open === 'filter' && (\n <Popover.Root\n open\n onOpenChange={(next) => {\n if (!next) setOpen(null);\n }}\n >\n <Popover.Portal container={popupContainer()}>\n <Popover.Positioner\n anchor={() => (button.current ? zoomAnchor(button.current) : null)}\n positionMethod=\"fixed\"\n side=\"bottom\"\n align=\"start\"\n sideOffset={6}\n collisionBoundary={layoutViewport()}\n collisionPadding={8}\n style={{ zIndex: 40 }}\n >\n <Popover.Popup\n ref={popup}\n className=\"filter-pop\"\n aria-label={sayCopy('filterBy', { label })}\n initialFocus={() =>\n popup.current?.querySelector<HTMLElement>('input:not([type=\"hidden\"]):not([aria-hidden=\"true\"])') ?? popup.current ?? true\n }\n finalFocus={() => (button.current?.isConnected ? button.current : false)}\n >\n <h.Picker\n box={box}\n table={h.table}\n refinement={h.refinement}\n standing={h.standing}\n unit={h.unitOf(name)}\n owned={mentionsColumn(h.tabQuery, name)}\n apply={(text) => h.apply(text, name)}\n close={() => setOpen(null)}\n />\n </Popover.Popup>\n </Popover.Positioner>\n </Popover.Portal>\n </Popover.Root>\n )}\n </>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"shared-Ch82h_Fu.js","names":["say","sayCopy","sayCopy","say","_Fragment","Menu.Root","Menu.Portal","Menu.Positioner","Menu.Popup","Menu.Separator","Menu.Item","Popover.Root","Popover.Portal","Popover.Positioner","Popover.Popup"],"sources":["../../../kit/src/client/copy/columnMenu/components/appColumnMenuModel.ts","../../../kit/src/client/components/appColumnMenuModel.ts","../../../kit/src/client/copy/columnMenu/components/AppColumnMenuPopups.ts","../../../kit/src/client/components/AppColumnMenuPopups.tsx"],"sourcesContent":["/** What appColumnMenuModel says, in the column menu room (packages/kit/src/client/messages.ts says how the catalog is split). */\nimport { defineMessages } from '../../../messages.js';\n\nexport const say = defineMessages({\n oldestFirst: 'Oldest first',\n newestFirst: 'Newest first',\n lowHigh: 'Low → high',\n highLow: 'High → low',\n filterMore: 'Filter…',\n clearFilter: 'Clear filter',\n unpinColumn: 'Unpin column',\n pinColumn: 'Pin column',\n});\n","/**\n * What an App list's column menu offers, before anything is drawn.\n *\n * The Workbench's header menu (ThMenu.tsx) is a power tool: every condition\n * the language has, sampled values, the language itself beside each entry.\n * In an App that was a dozen entries and a scrollbar under a reader who\n * wanted the column sorted or narrowed. So an App's menu has at most five:\n * the two sorts, worded by what the column holds; one Filter… that opens the\n * rail's own control for the column; Clear filter while there is one; and\n * Pin column, last. Pure, so the menu and its tests read one rule.\n */\nimport { columnKind, type ColumnMeta } from '@mistriwork/engine/shared/schema.js';\nimport { say as sayCopy } from '../copy/columnMenu/components/appColumnMenuModel.js';\n\nexport type AppMenuKey = 'asc' | 'desc' | 'filter' | 'clear' | 'pin';\ninterface AppMenuEntry {\n key: AppMenuKey;\n label: string;\n detail?: string;\n}\n\n/**\n * The words the two sorts say, fitted to what the column holds: text reads\n * A → Z, a figure Low → high, a date Oldest first. A flag and a vocabulary\n * name their ends — `No → Yes`, `New → Lost` — in the words the list shows\n * them by: a vocabulary sorts in the order it was declared, a native enum by\n * the engine and one over text through the read's ORDER BY (schema.ts\n * `declaredOrder`), so a pipeline reads as one rather than A → Z.\n */\nexport function sortWords(\n kind: string,\n meta: (Pick<ColumnMeta, 'type'> & { allowed?: readonly string[] }) | undefined,\n say: (value: string) => string = (value) => value,\n): readonly [asc: string, desc: string] {\n const allowed = meta?.allowed;\n if (allowed && allowed.length > 1) {\n const [first, last] = [say(allowed[0]), say(allowed[allowed.length - 1])];\n return [`${first} → ${last}`, `${last} → ${first}`];\n }\n if (kind === 'boolean') {\n const [no, yes] = [say('false'), say('true')];\n return [`${no} → ${yes}`, `${yes} → ${no}`];\n }\n if (kind === 'date') return [sayCopy('oldestFirst'), sayCopy('newestFirst')];\n if (kind === 'number' || (meta && columnKind(meta.type) === 'number')) return [sayCopy('lowHigh'), sayCopy('highLow')];\n return ['A → Z', 'Z → A'];\n}\n\ninterface EntryInput {\n words: readonly [string, string];\n /** Whether the header may sort this column at all (an index, a small table, an API's `sortable`). */\n sortable: boolean;\n /** The order the list is in on this column now, explicit or the default one. */\n current: 'asc' | 'desc' | null;\n /** Whether the column takes a filter (a real column; over an API, one it documents). */\n filterable: boolean;\n /** Whether the reader's question narrows this column beyond the lit tab. */\n filtered: boolean;\n /** What Clear filter takes off, in the reader's words: \"Status is not Done\". */\n cleared?: string;\n pinned: boolean;\n}\n\n/** The menu, in order. An entry that repeats the current sort is dropped: it would do nothing. */\nexport function appMenuEntries({ words, sortable, current, filterable, filtered, cleared, pinned }: EntryInput): AppMenuEntry[] {\n const entries: AppMenuEntry[] = [];\n if (sortable && current !== 'asc') entries.push({ key: 'asc', label: words[0] });\n if (sortable && current !== 'desc') entries.push({ key: 'desc', label: words[1] });\n if (filterable) entries.push({ key: 'filter', label: sayCopy('filterMore') });\n if (filterable && filtered) entries.push({ key: 'clear', label: sayCopy('clearFilter'), ...(cleared ? { detail: cleared } : {}) });\n entries.push({ key: 'pin', label: pinned ? sayCopy('unpinColumn') : sayCopy('pinColumn') });\n return entries;\n}\n","/** What AppColumnMenuPopups says, in the column menu room (packages/kit/src/client/messages.ts says how the catalog is split). */\nimport { defineMessages } from '../../../messages.js';\n\nexport const say = defineMessages({\n labelColumn: '{label} column',\n filterBy: 'Filter by {label}',\n});\n","/**\n * The App column menu's open half: its entries, and the rail's control\n * Filter… opens (AppColumnMenu.tsx draws the ⌄ that opens it).\n *\n * Every column of an App list's grid draws a ⌄, and a reader opens few of\n * them; so what a menu says and does arrives on demand, the first time one\n * is hovered, focused or opened, and a list's first page carries only the\n * buttons.\n */\nimport { Fragment, useRef, type RefObject } from 'react';\nimport { Menu } from '@base-ui/react/menu';\nimport { Popover } from '@base-ui/react/popover';\nimport { layoutViewport, zoomAnchor } from '@mistriwork/ui/internal/anchor.js';\nimport { columnDisplay, findTable, labelColumn } from '../core.js';\nimport { nextSort, sortDirection } from '../clauses.js';\nimport { mentionsColumn, ownedTails, withCondition } from '../filterbar.js';\nimport { pinnedFor, togglePin } from '../pins.js';\nimport { vocabularyWord } from '@mistriwork/engine/shared/model.js';\nimport type { ColumnMeta, TableMeta } from '@mistriwork/engine/shared/schema.js';\nimport { wordFor, type DisplayRule } from './valueModel.js';\nimport { appMenuEntries, sortWords, type AppMenuKey } from './appColumnMenuModel.js';\nimport { facetActive } from './filterRailModel.js';\nimport { useConditionWords } from './useConditionWords.js';\nimport type { AppColumnMenuHost, ColumnMenuProps } from './AppColumnMenu.js';\nimport { say as sayCopy } from '../copy/columnMenu/components/AppColumnMenuPopups.js';\nimport { popupContainer } from '../shellHost.js';\n\n/* How a flag's two values read where no display rule words them. */\nconst FLAG_WORDS: Record<string, string> = { true: sayCopy('common.yes'), false: sayCopy('common.no') };\n\ninterface PopupsProps extends ColumnMenuProps {\n host: RefObject<AppColumnMenuHost | null>;\n button: RefObject<HTMLButtonElement | null>;\n open: 'menu' | 'filter' | null;\n setOpen: (next: 'menu' | 'filter' | null | ((was: 'menu' | 'filter' | null) => 'menu' | 'filter' | null)) => void;\n /** Where the focus goes as the menu closes: back to the ⌄, or on into the popover or the rail. */\n handBack: RefObject<boolean>;\n}\n\nexport function AppColumnMenuPopups({\n host,\n button,\n open,\n setOpen,\n handBack,\n name,\n label,\n kind,\n meta,\n sortable,\n current,\n columns,\n drawnBy,\n}: PopupsProps) {\n const popup = useRef<HTMLDivElement>(null);\n /* The column's own conditions, said as its chip says them, beside Clear filter. */\n const tails = host.current ? (ownedTails(host.current.refinement, name) as string[]) : [];\n const { speaker, sayTails } = useConditionWords(\n host.current?.table,\n tails.map((tail) => `${name} ${tail}`),\n );\n const h = host.current;\n if (!h) return null;\n const box = h.boxFor(name);\n const column = (box?.meta ?? meta) as (ColumnMeta & { allowed?: string[] }) | undefined;\n const rule = columnDisplay(h.table.id, name) as DisplayRule | null;\n const say = (value: string) => wordFor(rule, value) ?? (column?.allowed?.length ? vocabularyWord(value) : (FLAG_WORDS[value] ?? value));\n /* A reference sorts by the name it is drawn by, not the id under it: an\n order by `owner_id` is an order nobody reading the list can see. */\n const target = column?.references ? (findTable(column.references.table) as TableMeta | undefined) : undefined;\n const byName = drawnBy ?? (target && labelColumn(target) ? `${name}.${labelColumn(target)}` : undefined);\n const sortPath = column?.references ? byName : name;\n const order = sortPath && sortPath !== name ? (sortDirection(h.query, sortPath) as 'asc' | 'desc' | null) : current;\n const filterable = Boolean(box?.meta) && (!h.table.filterable || h.table.filterable.includes(name));\n const pinned = pinnedFor(h.table, columns, h.listKey).includes(name);\n const entries = appMenuEntries({\n words: sortPath === name ? sortWords(kind, column, say) : sortWords('text', undefined),\n sortable: sortable && Boolean(sortPath),\n current: order,\n filterable,\n filtered: facetActive(h.refinement, name, h.tabQuery),\n cleared: speaker && tails.length ? sayTails(speaker, name, tails) : undefined,\n pinned,\n });\n\n const choose = (key: AppMenuKey) => {\n if (key === 'filter') {\n handBack.current = false;\n const facet = h.railFacet(name);\n /* The value already chosen, else the facet's first field: its Clear comes first in the markup, not in the reading. */\n const control =\n facet?.querySelector<HTMLElement>('input:checked') ??\n facet?.querySelector<HTMLElement>('input:not([type=\"hidden\"])') ??\n facet?.querySelector<HTMLElement>('button');\n if (!facet || !control) {\n setOpen('filter');\n return;\n }\n setOpen(null);\n /* Once the menu has gone: while it is open the page outside it is inert, and takes no focus. */\n setTimeout(() => {\n facet.scrollIntoView?.({ block: 'nearest' });\n control.focus();\n }, 0);\n return;\n }\n setOpen(null);\n if ((key === 'asc' || key === 'desc') && sortPath) h.navigate(nextSort(h.query, sortPath, key), name);\n else if (key === 'clear') h.apply(withCondition(h.refinement, name, ''), name);\n else if (key === 'pin') togglePin(h.table, columns, name, h.listKey);\n };\n\n return (\n <>\n {/* Base UI owns the menu's keyboard: focus moves in on open, the arrows\n walk the entries, Escape closes it and hands the focus back to the ⌄. */}\n <Menu.Root\n open={open === 'menu'}\n onOpenChange={(next) => {\n if (!next) setOpen((was) => (was === 'menu' ? null : was));\n }}\n >\n <Menu.Portal container={popupContainer()}>\n <Menu.Positioner\n anchor={() => (button.current ? zoomAnchor(button.current) : null)}\n positionMethod=\"fixed\"\n side=\"bottom\"\n align=\"start\"\n sideOffset={4}\n collisionBoundary={layoutViewport()}\n collisionPadding={12}\n style={{ zIndex: 40 }}\n >\n <Menu.Popup\n className=\"th-menu th-menu-app\"\n aria-label={sayCopy('labelColumn', { label })}\n finalFocus={() => (handBack.current && button.current?.isConnected ? button.current : false)}\n >\n {entries.map((entry, i) => (\n <Fragment key={entry.key}>\n {/* The pin is about reading the table, not narrowing it: last, and set apart. */}\n {entry.key === 'pin' && i > 0 ? <Menu.Separator className=\"th-menu-sep\" /> : null}\n <Menu.Item\n render={<button type=\"button\" className={`th-menu-item${entry.key === 'pin' ? ' th-menu-quiet' : ''}`} />}\n nativeButton\n closeOnClick={false}\n onClick={() => choose(entry.key)}\n aria-label={entry.detail ? `${entry.label}: ${entry.detail}` : undefined}\n >\n <span className=\"th-menu-label\">{entry.label}</span>\n {entry.detail ? <span className=\"th-menu-said\">{entry.detail}</span> : null}\n </Menu.Item>\n </Fragment>\n ))}\n </Menu.Popup>\n </Menu.Positioner>\n </Menu.Portal>\n </Menu.Root>\n {box && open === 'filter' && (\n <Popover.Root\n open\n onOpenChange={(next) => {\n if (!next) setOpen(null);\n }}\n >\n <Popover.Portal container={popupContainer()}>\n <Popover.Positioner\n anchor={() => (button.current ? zoomAnchor(button.current) : null)}\n positionMethod=\"fixed\"\n side=\"bottom\"\n align=\"start\"\n sideOffset={6}\n collisionBoundary={layoutViewport()}\n collisionPadding={8}\n style={{ zIndex: 40 }}\n >\n <Popover.Popup\n ref={popup}\n className=\"filter-pop\"\n aria-label={sayCopy('filterBy', { label })}\n initialFocus={() =>\n popup.current?.querySelector<HTMLElement>('input:not([type=\"hidden\"]):not([aria-hidden=\"true\"])') ?? popup.current ?? true\n }\n finalFocus={() => (button.current?.isConnected ? button.current : false)}\n >\n <h.Picker\n box={box}\n table={h.table}\n refinement={h.refinement}\n standing={h.standing}\n unit={h.unitOf(name)}\n owned={mentionsColumn(h.tabQuery, name)}\n apply={(text) => h.apply(text, name)}\n close={() => setOpen(null)}\n />\n </Popover.Popup>\n </Popover.Positioner>\n </Popover.Portal>\n </Popover.Root>\n )}\n </>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { D as subscribeSessionIdentity, E as sessionIdentity, K as tagChips, N as andQuery } from "./shared-poc11xxo.js";
|
|
2
2
|
import { Ct as addHostListener, F as primaryKey, J as rowCurrency, _ as ruleSays, d as dressFor, en as plural, g as maskedText, gt as defineMessages, h as linkFor, jt as shellBody, rn as shell } from "./shared-DJZjSi3J.js";
|
|
3
|
-
import { a as JsonValue, i as Said, n as Dressed } from "./shared-
|
|
4
|
-
import { D as refsFrom, L as state, _ as openRecord, at as historyToken, d as findTable, i as api, s as columnDisplay, st as ownedBy, u as emptyWord, w as quote } from "./shared-
|
|
3
|
+
import { a as JsonValue, i as Said, n as Dressed } from "./shared-CMjK-Ucd.js";
|
|
4
|
+
import { D as refsFrom, L as state, _ as openRecord, at as historyToken, d as findTable, i as api, s as columnDisplay, st as ownedBy, u as emptyWord, w as quote } from "./shared-BoLbc2WD.js";
|
|
5
5
|
import { o as previewOf, r as jsonValueOf } from "./shared-DP0_R8KD.js";
|
|
6
6
|
import { n as commandKeyText } from "./shared-Du2YAQk4.js";
|
|
7
7
|
import { r as recordKey } from "./shared-_IMKuuvy.js";
|
|
@@ -734,4 +734,4 @@ function bulkSummary(label, result) {
|
|
|
734
734
|
}
|
|
735
735
|
export { registerCommandHost as _, countedLabel as a, updateAttempts as c, RefJump as d, Value as f, pageBridge as g, dueOpen as h, bulkSummary as i, updateOwnerKey as l, componentSlot as m, bulkCommandSummary as n, matchingKeys as o, ValueSlot as p, bulkKey as r, prepareBulkCommand as s, applyBulk as t, safeFieldErrors as u, registerViewOpener as v, opensRecord as y };
|
|
736
736
|
|
|
737
|
-
//# sourceMappingURL=shared-
|
|
737
|
+
//# sourceMappingURL=shared-Chp88all.js.map
|