@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.
Files changed (221) hide show
  1. package/README.md +4 -3
  2. package/dist/client/assets/LayoutBuilder-MPzkVU2e.js.map +1 -1
  3. package/dist/client/assets/index-D2dHI6hR.js.map +1 -1
  4. package/dist/client/assets/shell-TreN_uLs.js.map +1 -1
  5. package/dist/docs/access-model.md +1 -1
  6. package/dist/docs/build-and-deploy.md +0 -1
  7. package/dist/docs/cli.md +1 -1
  8. package/dist/docs/glossary.md +3 -3
  9. package/dist/docs/query.md +9 -21
  10. package/dist/docs/status.md +3 -3
  11. package/dist/embed/react/chunks/LayoutBuilder-Cbxa_wve.js.map +1 -1
  12. package/dist/embed/react/chunks/app-0UZ1Re1k.js.map +1 -1
  13. package/dist/embed/react/chunks/page-Bx4o1kpQ.js.map +1 -1
  14. package/dist/embed/react/chunks/palette-Bb7Lf6eo.js.map +1 -1
  15. package/dist/embed/react/chunks/shell-DZRACiB9.js.map +1 -1
  16. package/dist/embed/react/chunks/write-BQO4CFc9.js.map +1 -1
  17. package/dist/embed/react/index.js +1 -1
  18. package/dist/server/build/dockerfile.js +1 -1
  19. package/dist/server/cli/usage.js +2 -2
  20. package/dist/ui/index.js +2 -2
  21. package/dist/ui/page.js +2 -2
  22. package/dist/ui/{shared-N4Ej8yRD.js → shared-1PD7TOTJ.js} +5 -5
  23. package/dist/ui/{shared-N4Ej8yRD.js.map → shared-1PD7TOTJ.js.map} +1 -1
  24. package/dist/ui/{shared-D5m86-4o.js → shared-1gMnOu9J.js} +6 -6
  25. package/dist/ui/{shared-D5m86-4o.js.map → shared-1gMnOu9J.js.map} +1 -1
  26. package/dist/ui/{shared-Ctaj8mR2.js → shared-5RQMi4BR.js} +3 -3
  27. package/dist/ui/{shared-Ctaj8mR2.js.map → shared-5RQMi4BR.js.map} +1 -1
  28. package/dist/ui/{shared-DpLeIATZ.js → shared-B-BUF9fx.js} +2 -2
  29. package/dist/ui/{shared-DpLeIATZ.js.map → shared-B-BUF9fx.js.map} +1 -1
  30. package/dist/ui/{shared-DWYnjItP.js → shared-B-MhiPIN.js} +9 -9
  31. package/dist/ui/{shared-DWYnjItP.js.map → shared-B-MhiPIN.js.map} +1 -1
  32. package/dist/ui/{shared-0fNuhSbG.js → shared-B07qIMlE.js} +5 -5
  33. package/dist/ui/{shared-0fNuhSbG.js.map → shared-B07qIMlE.js.map} +1 -1
  34. package/dist/ui/{shared-lYtMadRU.js → shared-B1SAS_J-.js} +3 -3
  35. package/dist/ui/{shared-lYtMadRU.js.map → shared-B1SAS_J-.js.map} +1 -1
  36. package/dist/ui/{shared-CpI0Y8M5.js → shared-B4jgU8h9.js} +6 -6
  37. package/dist/ui/{shared-CpI0Y8M5.js.map → shared-B4jgU8h9.js.map} +1 -1
  38. package/dist/ui/{shared-Cxu1c35l.js → shared-B5aBCUi7.js} +30 -30
  39. package/dist/ui/{shared-Cxu1c35l.js.map → shared-B5aBCUi7.js.map} +1 -1
  40. package/dist/ui/{shared-CAe-US1q.js → shared-B9H7_Pji.js} +5 -5
  41. package/dist/ui/{shared-CAe-US1q.js.map → shared-B9H7_Pji.js.map} +1 -1
  42. package/dist/ui/{shared-Q2bgBaYo.js → shared-BAXr20S-.js} +4 -4
  43. package/dist/ui/{shared-Q2bgBaYo.js.map → shared-BAXr20S-.js.map} +1 -1
  44. package/dist/ui/{shared-CyEefFFb.js → shared-BDDUzH-f.js} +19 -19
  45. package/dist/ui/{shared-CyEefFFb.js.map → shared-BDDUzH-f.js.map} +1 -1
  46. package/dist/ui/{shared-BdhPI6dq.js → shared-BGmkeDeW.js} +3 -3
  47. package/dist/ui/{shared-BdhPI6dq.js.map → shared-BGmkeDeW.js.map} +1 -1
  48. package/dist/ui/{shared-DONIpq2q.js → shared-BHCQ60yN.js} +2 -2
  49. package/dist/ui/{shared-DONIpq2q.js.map → shared-BHCQ60yN.js.map} +1 -1
  50. package/dist/ui/{shared-CNmaAv64.js → shared-BHsjawAG.js} +8 -8
  51. package/dist/ui/{shared-CNmaAv64.js.map → shared-BHsjawAG.js.map} +1 -1
  52. package/dist/ui/{shared-DgjU9kOy.js → shared-BIQuK_nq.js} +4 -4
  53. package/dist/ui/{shared-DgjU9kOy.js.map → shared-BIQuK_nq.js.map} +1 -1
  54. package/dist/ui/{shared-icSQAj21.js → shared-BOe4W2FI.js} +3 -3
  55. package/dist/ui/{shared-icSQAj21.js.map → shared-BOe4W2FI.js.map} +1 -1
  56. package/dist/ui/{shared-BlxoOJSk.js → shared-BPpC08ip.js} +3 -3
  57. package/dist/ui/{shared-BlxoOJSk.js.map → shared-BPpC08ip.js.map} +1 -1
  58. package/dist/ui/{shared-BtiFL37J.js → shared-BdA3LPCB.js} +2 -2
  59. package/dist/ui/{shared-BtiFL37J.js.map → shared-BdA3LPCB.js.map} +1 -1
  60. package/dist/ui/{shared-CvR94vn4.js → shared-Be3nbWsd.js} +11 -11
  61. package/dist/ui/{shared-CvR94vn4.js.map → shared-Be3nbWsd.js.map} +1 -1
  62. package/dist/ui/{shared-Bl_nF_IH.js → shared-Bf30ZLoS.js} +8 -4
  63. package/dist/ui/shared-Bf30ZLoS.js.map +1 -0
  64. package/dist/ui/{shared-DijrJ_V-.js → shared-BguP_BaR.js} +7 -7
  65. package/dist/ui/{shared-DijrJ_V-.js.map → shared-BguP_BaR.js.map} +1 -1
  66. package/dist/ui/{shared-DPAVoWY0.js → shared-BoLbc2WD.js} +17 -2
  67. package/dist/ui/{shared-DPAVoWY0.js.map → shared-BoLbc2WD.js.map} +1 -1
  68. package/dist/ui/{shared-BkdBTYwx.js → shared-BttyOW4W.js} +3 -3
  69. package/dist/ui/{shared-BkdBTYwx.js.map → shared-BttyOW4W.js.map} +1 -1
  70. package/dist/ui/{shared-CQWLz8uT.js → shared-BumxsBlA.js} +10 -10
  71. package/dist/ui/{shared-CQWLz8uT.js.map → shared-BumxsBlA.js.map} +1 -1
  72. package/dist/ui/{shared-Dzu7tFiC.js → shared-Bw73ktBk.js} +3 -3
  73. package/dist/ui/{shared-Dzu7tFiC.js.map → shared-Bw73ktBk.js.map} +1 -1
  74. package/dist/ui/{shared-BhAYErSx.js → shared-C1B0GH0e.js} +4 -4
  75. package/dist/ui/{shared-BhAYErSx.js.map → shared-C1B0GH0e.js.map} +1 -1
  76. package/dist/ui/{shared-BQJQcGgj.js → shared-C2FsyYr7.js} +4 -4
  77. package/dist/ui/{shared-BQJQcGgj.js.map → shared-C2FsyYr7.js.map} +1 -1
  78. package/dist/ui/{shared-B9lw2Ryh.js → shared-C2RU1qjv.js} +4 -4
  79. package/dist/ui/{shared-B9lw2Ryh.js.map → shared-C2RU1qjv.js.map} +1 -1
  80. package/dist/ui/{shared-DQYNI9wO.js → shared-C42f07hJ.js} +5 -5
  81. package/dist/ui/{shared-DQYNI9wO.js.map → shared-C42f07hJ.js.map} +1 -1
  82. package/dist/ui/{shared-CqCZ8wMY.js → shared-C4LkPCU4.js} +3 -3
  83. package/dist/ui/{shared-CqCZ8wMY.js.map → shared-C4LkPCU4.js.map} +1 -1
  84. package/dist/ui/{shared-BhtpgOpa.js → shared-C4wSfz6k.js} +9 -9
  85. package/dist/ui/{shared-BhtpgOpa.js.map → shared-C4wSfz6k.js.map} +1 -1
  86. package/dist/ui/{shared-BHc2Izkj.js → shared-C9DZtSFH.js} +2 -2
  87. package/dist/ui/{shared-BHc2Izkj.js.map → shared-C9DZtSFH.js.map} +1 -1
  88. package/dist/ui/{shared-DW1YuiNS.js → shared-CA52ClGo.js} +2 -2
  89. package/dist/ui/{shared-DW1YuiNS.js.map → shared-CA52ClGo.js.map} +1 -1
  90. package/dist/ui/{shared-BbSbilkh.js → shared-CBciTwm6.js} +9 -9
  91. package/dist/ui/{shared-BbSbilkh.js.map → shared-CBciTwm6.js.map} +1 -1
  92. package/dist/ui/{shared-C-J32eBn.js → shared-CL3RLKDA.js} +16 -16
  93. package/dist/ui/{shared-C-J32eBn.js.map → shared-CL3RLKDA.js.map} +1 -1
  94. package/dist/ui/{shared-Ck8S4OxW.js → shared-CLq3-_hW.js} +3 -3
  95. package/dist/ui/{shared-Ck8S4OxW.js.map → shared-CLq3-_hW.js.map} +1 -1
  96. package/dist/ui/{shared-Q5WefT7G.js → shared-CMjK-Ucd.js} +3 -3
  97. package/dist/ui/{shared-Q5WefT7G.js.map → shared-CMjK-Ucd.js.map} +1 -1
  98. package/dist/ui/{shared-D3MAuEA3.js → shared-CPjpSFGh.js} +2 -2
  99. package/dist/ui/{shared-D3MAuEA3.js.map → shared-CPjpSFGh.js.map} +1 -1
  100. package/dist/ui/{shared-VshXGwXP.js → shared-CSPhENq3.js} +2 -2
  101. package/dist/ui/{shared-VshXGwXP.js.map → shared-CSPhENq3.js.map} +1 -1
  102. package/dist/ui/{shared-DJrJaE73.js → shared-CZJE4Bmp.js} +3 -3
  103. package/dist/ui/{shared-DJrJaE73.js.map → shared-CZJE4Bmp.js.map} +1 -1
  104. package/dist/ui/{shared-D7ONOwI7.js → shared-C_BhUL2I.js} +7 -7
  105. package/dist/ui/{shared-D7ONOwI7.js.map → shared-C_BhUL2I.js.map} +1 -1
  106. package/dist/ui/{shared-j-2peBIB.js → shared-CbeujwdU.js} +4 -4
  107. package/dist/ui/{shared-j-2peBIB.js.map → shared-CbeujwdU.js.map} +1 -1
  108. package/dist/ui/{shared-D5GrOEa2.js → shared-Cbf-o4Dt.js} +4 -4
  109. package/dist/ui/{shared-D5GrOEa2.js.map → shared-Cbf-o4Dt.js.map} +1 -1
  110. package/dist/ui/{shared-HwiPIajr.js → shared-CdNmeNHh.js} +3 -3
  111. package/dist/ui/{shared-HwiPIajr.js.map → shared-CdNmeNHh.js.map} +1 -1
  112. package/dist/ui/{shared-ZCFt-CPb.js → shared-CdQOMD8J.js} +3 -3
  113. package/dist/ui/{shared-ZCFt-CPb.js.map → shared-CdQOMD8J.js.map} +1 -1
  114. package/dist/ui/{shared-ClhXSGGK.js → shared-CdiPYlTh.js} +2 -2
  115. package/dist/ui/{shared-ClhXSGGK.js.map → shared-CdiPYlTh.js.map} +1 -1
  116. package/dist/ui/{shared-DA8_pVRZ.js → shared-CepLAhwm.js} +2 -2
  117. package/dist/ui/{shared-DA8_pVRZ.js.map → shared-CepLAhwm.js.map} +1 -1
  118. package/dist/ui/{shared-BrYKjrnM.js → shared-Ch82h_Fu.js} +6 -6
  119. package/dist/ui/{shared-BrYKjrnM.js.map → shared-Ch82h_Fu.js.map} +1 -1
  120. package/dist/ui/{shared-C4UrE8Fb.js → shared-Chp88all.js} +3 -3
  121. package/dist/ui/{shared-C4UrE8Fb.js.map → shared-Chp88all.js.map} +1 -1
  122. package/dist/ui/{shared-CWa80DTO.js → shared-Ci16s2rN.js} +9 -9
  123. package/dist/ui/{shared-CWa80DTO.js.map → shared-Ci16s2rN.js.map} +1 -1
  124. package/dist/ui/{shared-tksTLD6Q.js → shared-CiqNkoE1.js} +5 -5
  125. package/dist/ui/{shared-tksTLD6Q.js.map → shared-CiqNkoE1.js.map} +1 -1
  126. package/dist/ui/{shared-yt7DjSrq.js → shared-CpMhOq8F.js} +2 -2
  127. package/dist/ui/{shared-yt7DjSrq.js.map → shared-CpMhOq8F.js.map} +1 -1
  128. package/dist/ui/{shared-Dm0z5WUl.js → shared-CrWv5JKH.js} +6 -6
  129. package/dist/ui/{shared-Dm0z5WUl.js.map → shared-CrWv5JKH.js.map} +1 -1
  130. package/dist/ui/{shared-CQL3FGHc.js → shared-Csfi3Pti.js} +2 -2
  131. package/dist/ui/{shared-CQL3FGHc.js.map → shared-Csfi3Pti.js.map} +1 -1
  132. package/dist/ui/{shared-BKNRbm-V.js → shared-CuZt26rm.js} +2 -2
  133. package/dist/ui/{shared-BKNRbm-V.js.map → shared-CuZt26rm.js.map} +1 -1
  134. package/dist/ui/{shared-Guq3upiR.js → shared-Cws_z-TS.js} +2 -2
  135. package/dist/ui/{shared-Guq3upiR.js.map → shared-Cws_z-TS.js.map} +1 -1
  136. package/dist/ui/{shared-Bw_qZeIj.js → shared-D1KWuCg6.js} +2 -2
  137. package/dist/ui/{shared-Bw_qZeIj.js.map → shared-D1KWuCg6.js.map} +1 -1
  138. package/dist/ui/{shared-CuCZKwXW.js → shared-D66ju_Cb.js} +23 -23
  139. package/dist/ui/{shared-CuCZKwXW.js.map → shared-D66ju_Cb.js.map} +1 -1
  140. package/dist/ui/{shared-DYfX7NSM.js → shared-DGaQZXnw.js} +2 -2
  141. package/dist/ui/{shared-DYfX7NSM.js.map → shared-DGaQZXnw.js.map} +1 -1
  142. package/dist/ui/{shared-B3Hp8tOv.js → shared-DHy41sET.js} +6 -6
  143. package/dist/ui/{shared-B3Hp8tOv.js.map → shared-DHy41sET.js.map} +1 -1
  144. package/dist/ui/{shared-CXyd7IKi.js → shared-DKEOMQ6l.js} +2 -2
  145. package/dist/ui/{shared-CXyd7IKi.js.map → shared-DKEOMQ6l.js.map} +1 -1
  146. package/dist/ui/{shared-Ccmc8YO0.js → shared-DSUICuaJ.js} +33 -33
  147. package/dist/ui/{shared-Ccmc8YO0.js.map → shared-DSUICuaJ.js.map} +1 -1
  148. package/dist/ui/{shared-CL2iw_js.js → shared-DUPMRoO0.js} +13 -13
  149. package/dist/ui/{shared-CL2iw_js.js.map → shared-DUPMRoO0.js.map} +1 -1
  150. package/dist/ui/{shared-Dtp4eRul.js → shared-DVfdm6ah.js} +2 -2
  151. package/dist/ui/{shared-Dtp4eRul.js.map → shared-DVfdm6ah.js.map} +1 -1
  152. package/dist/ui/{shared-BJ5Ex32G.js → shared-DXM7d7lJ.js} +3 -3
  153. package/dist/ui/{shared-BJ5Ex32G.js.map → shared-DXM7d7lJ.js.map} +1 -1
  154. package/dist/ui/{shared-BFr6ld0e.js → shared-DXbMlcev.js} +2 -2
  155. package/dist/ui/{shared-BFr6ld0e.js.map → shared-DXbMlcev.js.map} +1 -1
  156. package/dist/ui/{shared-BUp3jv-N.js → shared-D_SkPtJ9.js} +6 -6
  157. package/dist/ui/{shared-BUp3jv-N.js.map → shared-D_SkPtJ9.js.map} +1 -1
  158. package/dist/ui/{shared-CdNomVzH.js → shared-Dd21k2ic.js} +4 -4
  159. package/dist/ui/{shared-CdNomVzH.js.map → shared-Dd21k2ic.js.map} +1 -1
  160. package/dist/ui/{shared-gRMbxmpu.js → shared-Dh0nHtLZ.js} +8 -8
  161. package/dist/ui/{shared-gRMbxmpu.js.map → shared-Dh0nHtLZ.js.map} +1 -1
  162. package/dist/ui/{shared-BKGJgjog.js → shared-DkOdSpSK.js} +3 -3
  163. package/dist/ui/{shared-BKGJgjog.js.map → shared-DkOdSpSK.js.map} +1 -1
  164. package/dist/ui/{shared-BMsh72Uq.js → shared-Dkph5ckT.js} +2 -2
  165. package/dist/ui/{shared-BMsh72Uq.js.map → shared-Dkph5ckT.js.map} +1 -1
  166. package/dist/ui/{shared-Be1HpDOB.js → shared-Dl1_Nx--.js} +3 -3
  167. package/dist/ui/{shared-Be1HpDOB.js.map → shared-Dl1_Nx--.js.map} +1 -1
  168. package/dist/ui/{shared-BQIZWOoJ.js → shared-Dm0IGbAf.js} +2 -2
  169. package/dist/ui/{shared-BQIZWOoJ.js.map → shared-Dm0IGbAf.js.map} +1 -1
  170. package/dist/ui/{shared-DSUtcU5S.js → shared-DnIkTpPr.js} +5 -5
  171. package/dist/ui/{shared-DSUtcU5S.js.map → shared-DnIkTpPr.js.map} +1 -1
  172. package/dist/ui/{shared-DsxGbYlV.js → shared-Docl_0tq.js} +3 -3
  173. package/dist/ui/{shared-DsxGbYlV.js.map → shared-Docl_0tq.js.map} +1 -1
  174. package/dist/ui/{shared-DZskrV26.js → shared-DprrHC72.js} +2 -2
  175. package/dist/ui/{shared-DZskrV26.js.map → shared-DprrHC72.js.map} +1 -1
  176. package/dist/ui/{shared-Bmw43Hwf.js → shared-DyKsJTZs.js} +2 -2
  177. package/dist/ui/{shared-Bmw43Hwf.js.map → shared-DyKsJTZs.js.map} +1 -1
  178. package/dist/ui/{shared-BLG88Pya.js → shared-FO7vfI3F.js} +4 -4
  179. package/dist/ui/{shared-BLG88Pya.js.map → shared-FO7vfI3F.js.map} +1 -1
  180. package/dist/ui/{shared-DLSd80D1.js → shared-HalAVHjv.js} +3 -3
  181. package/dist/ui/{shared-DLSd80D1.js.map → shared-HalAVHjv.js.map} +1 -1
  182. package/dist/ui/{shared-D1mMBLdj.js → shared-JvcI-LWp.js} +15 -15
  183. package/dist/ui/{shared-D1mMBLdj.js.map → shared-JvcI-LWp.js.map} +1 -1
  184. package/dist/ui/{shared-C6Hv_4O0.js → shared-K7Ym27yg.js} +2 -2
  185. package/dist/ui/{shared-C6Hv_4O0.js.map → shared-K7Ym27yg.js.map} +1 -1
  186. package/dist/ui/{shared-B39ln7oi.js → shared-SzlnwfJO.js} +3 -3
  187. package/dist/ui/{shared-B39ln7oi.js.map → shared-SzlnwfJO.js.map} +1 -1
  188. package/dist/ui/{shared-DgPn_Jll.js → shared-TrGbd1FY.js} +3 -3
  189. package/dist/ui/{shared-DgPn_Jll.js.map → shared-TrGbd1FY.js.map} +1 -1
  190. package/dist/ui/{shared-DrFb-XtA.js → shared-WhbuObEW.js} +2 -2
  191. package/dist/ui/{shared-DrFb-XtA.js.map → shared-WhbuObEW.js.map} +1 -1
  192. package/dist/ui/{shared-DiFQljcq.js → shared-XcSKDp6N.js} +11 -11
  193. package/dist/ui/{shared-DiFQljcq.js.map → shared-XcSKDp6N.js.map} +1 -1
  194. package/dist/ui/{shared-CMAg58rY.js → shared-Z4uBJU6I.js} +7 -6
  195. package/dist/ui/shared-Z4uBJU6I.js.map +1 -0
  196. package/dist/ui/{shared-BnUptuUp.js → shared-bAgeiRa5.js} +2 -2
  197. package/dist/ui/{shared-BnUptuUp.js.map → shared-bAgeiRa5.js.map} +1 -1
  198. package/dist/ui/{shared-BxMvSjey.js → shared-cgXG7OgZ.js} +5 -5
  199. package/dist/ui/{shared-BxMvSjey.js.map → shared-cgXG7OgZ.js.map} +1 -1
  200. package/dist/ui/{shared-u4CG2kQJ.js → shared-eZ0SB_zm.js} +2 -2
  201. package/dist/ui/{shared-u4CG2kQJ.js.map → shared-eZ0SB_zm.js.map} +1 -1
  202. package/dist/ui/{shared-L90bWW8e.js → shared-frKFb79C.js} +2 -2
  203. package/dist/ui/{shared-L90bWW8e.js.map → shared-frKFb79C.js.map} +1 -1
  204. package/dist/ui/{shared-Dd34nhkw.js → shared-hAayNSRA.js} +3 -3
  205. package/dist/ui/{shared-Dd34nhkw.js.map → shared-hAayNSRA.js.map} +1 -1
  206. package/dist/ui/{shared-DzC64cpp.js → shared-j_J16p2B.js} +2 -2
  207. package/dist/ui/{shared-DzC64cpp.js.map → shared-j_J16p2B.js.map} +1 -1
  208. package/dist/ui/{shared-DX7HRIV-.js → shared-tqpl5N3g.js} +6 -6
  209. package/dist/ui/{shared-DX7HRIV-.js.map → shared-tqpl5N3g.js.map} +1 -1
  210. package/dist/ui/{shared-BS5dBMpA.js → shared-y-6_ZDts.js} +2 -2
  211. package/dist/ui/{shared-BS5dBMpA.js.map → shared-y-6_ZDts.js.map} +1 -1
  212. package/dist/ui/{shared-Cv5v_MP1.js → shared-zG6e1Rhz.js} +13 -13
  213. package/dist/ui/{shared-Cv5v_MP1.js.map → shared-zG6e1Rhz.js.map} +1 -1
  214. package/dist/ui/testing.js +1 -1
  215. package/package.json +4 -4
  216. package/dist/docs/cli-browser.md +0 -232
  217. package/dist/docs/database-browser.md +0 -115
  218. package/dist/docs/keyboard.md +0 -63
  219. package/dist/docs/mcp.md +0 -86
  220. package/dist/ui/shared-Bl_nF_IH.js.map +0 -1
  221. package/dist/ui/shared-CMAg58rY.js.map +0 -1
@@ -5,8 +5,8 @@ import "./shared-CERG8O1B.js";
5
5
  import "./shared-DH_I1US0.js";
6
6
  /* empty css */
7
7
  import { c as amountIn, l as maskShown, s as PLACE, u as moneySymbol } from "./shared-CxovRZz5.js";
8
- import { run } from "./shared-DQYNI9wO.js";
9
- import { x as isAppIcon } from "./shared-C-J32eBn.js";
8
+ import { run } from "./shared-C42f07hJ.js";
9
+ import { x as isAppIcon } from "./shared-CL3RLKDA.js";
10
10
  import { useRef, useState } from "react";
11
11
  import { jsx, jsxs } from "react/jsx-runtime";
12
12
  // packages/ui/src/Choices.tsx
@@ -498,4 +498,4 @@ function IntakeControl(props) {
498
498
  }
499
499
  export { IntakeControl, drawnHere };
500
500
 
501
- //# sourceMappingURL=shared-Ck8S4OxW.js.map
501
+ //# sourceMappingURL=shared-CLq3-_hW.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"shared-Ck8S4OxW.js","names":[],"sources":["../../../ui/src/Choices.tsx","../../src/client/copy/forms/components/IntakeControls.ts","../../src/client/components/IntakeControls.tsx"],"sourcesContent":["/**\n * Choices drawn as buttons, cards and checkboxes: Yes/No, icon cards (one or several), a checkbox and a consent. One\n * answer is a native radio dressed, so the arrows, Space and the form's own semantics are the browser's, and the focus\n * ring shows on the face when the keyboard is on the input. Several cards are one group as the radios are (CheckCards):\n * one Tab stop, the arrows move between them, Space turns one on or off, and each says `aria-checked`. Props only.\n * Preview: @mistriwork/ui is Preview at 1.0.\n */\nimport { useId, useRef, useState, type AriaAttributes, type KeyboardEvent, type ReactNode } from 'react';\nimport { Field } from './Field.js';\nimport { frameOf, type FieldFrame } from './fieldFrame.js';\n\nexport interface ChoiceOption {\n value: string;\n label: string;\n /** A picture for a card. */\n icon?: ReactNode;\n}\n\nexport interface YesNoProps extends Omit<FieldFrame, 'label'> {\n /** The question. */\n label: ReactNode;\n value: 'yes' | 'no' | '';\n onChange: (value: 'yes' | 'no') => void;\n /** The two words, in the caller's language. */\n yes: string;\n no: string;\n}\n\n/** Two buttons answering a question. */\nexport function YesNo(props: YesNoProps): ReactNode {\n const name = useId();\n return (\n <Field {...frameOf(props)} group>\n {(control) => (\n <div\n className=\"choice-pair\"\n role=\"radiogroup\"\n aria-labelledby={control['aria-labelledby']}\n aria-describedby={control['aria-describedby']}\n aria-invalid={control['aria-invalid']}\n >\n {(['yes', 'no'] as const).map((v) => (\n <label key={v} className={`choice-pick${props.value === v ? ' is-on' : ''}`}>\n <input type=\"radio\" name={name} className=\"choice-input\" checked={props.value === v} onChange={() => props.onChange(v)} />\n {props[v]}\n </label>\n ))}\n </div>\n )}\n </Field>\n );\n}\n\nexport interface ChoiceCardsProps extends FieldFrame {\n options: ChoiceOption[];\n value: string[];\n onChange: (value: string[]) => void;\n /** Several may be on. */\n multiple?: boolean;\n /** The card that stands alone (\"None\"): choosing it clears the rest, and choosing another clears it. */\n exclusive?: string;\n}\n\n/** Cards with an icon, a label and a box. One choice is a radio group; `multiple` a group of checkboxes. */\nexport function ChoiceCards(props: ChoiceCardsProps): ReactNode {\n const name = useId();\n const toggle = (v: string, on: boolean): void => {\n if (!props.multiple) return props.onChange(on ? [v] : []);\n if (v === props.exclusive) return props.onChange(on ? [v] : []);\n const rest = props.value.filter((x) => x !== v && x !== props.exclusive);\n props.onChange(on ? props.options.map((o) => o.value).filter((x) => x === v || rest.includes(x)) : rest);\n };\n if (props.multiple)\n return (\n <Field {...frameOf(props)} group>\n {(control) => (\n <CheckCards\n aria-labelledby={control['aria-labelledby']}\n aria-describedby={control['aria-describedby']}\n aria-invalid={control['aria-invalid']}\n cards={props.options.map((o) => ({ key: o.value, label: o.label, icon: o.icon, on: props.value.includes(o.value) }))}\n onToggle={(index, on) => toggle(props.options[index].value, on)}\n />\n )}\n </Field>\n );\n return (\n <Field {...frameOf(props)} group>\n {(control) => (\n <div\n className=\"choice-cards\"\n role=\"radiogroup\"\n aria-labelledby={control['aria-labelledby']}\n aria-describedby={control['aria-describedby']}\n aria-invalid={control['aria-invalid']}\n >\n {props.options.map((o) => {\n const on = props.value.includes(o.value);\n return (\n <label key={o.value} className={`choice-card${on ? ' is-on' : ''}`}>\n {o.icon ? (\n <span className=\"choice-card-icon\" aria-hidden=\"true\">\n {o.icon}\n </span>\n ) : null}\n <span className=\"choice-card-label\">{o.label}</span>\n <input type=\"radio\" name={name} className=\"choice-input\" checked={on} onChange={(e) => toggle(o.value, e.target.checked)} />\n <span className=\"choice-box\" aria-hidden=\"true\" />\n </label>\n );\n })}\n </div>\n )}\n </Field>\n );\n}\n\n/** One card of several: its words, its picture and whether it is on. */\nexport interface CheckCard {\n key: string;\n label: ReactNode;\n icon?: ReactNode;\n /** A line under the label. */\n help?: ReactNode;\n on: boolean;\n}\n\nexport interface CheckCardsProps {\n cards: readonly CheckCard[];\n /** The card at `index` turned on or off. */\n onToggle: (index: number, on: boolean) => void;\n id?: string;\n disabled?: boolean;\n 'aria-labelledby'?: string;\n 'aria-describedby'?: string;\n 'aria-invalid'?: AriaAttributes['aria-invalid'];\n /** How short every card's words are, so a wide page can set them side by side (`data-fit`; the page's stylesheet\n * decides what that means): `short` is a label alone, `brief` a label and a line that fit half a column. */\n fit?: 'short' | 'brief';\n}\n\n/**\n * Several cards, any of them on: full-width cards, each an icon, its words and a square at its end that fills when it\n * is on. They are one group to the keyboard, as radios are — one Tab stop (the card last moved to, else the first one\n * on, else the first), the arrows and Home and End move between them, and Space turns the one in hand on or off — and\n * each is a `checkbox` saying `aria-checked`, so a screen reader hears \"checked\" as it moves.\n */\nexport function CheckCards(props: CheckCardsProps): ReactNode {\n const { cards } = props;\n const [held, setHeld] = useState<number | undefined>(undefined);\n const faces = useRef<(HTMLDivElement | null)[]>([]);\n const first = cards.findIndex((card) => card.on);\n const stop = held !== undefined && held < cards.length ? held : Math.max(first, 0);\n const move = (to: number) => {\n const next = (to + cards.length) % cards.length;\n setHeld(next);\n faces.current[next]?.focus();\n };\n const keys = (event: KeyboardEvent<HTMLDivElement>, index: number) => {\n const to =\n event.key === 'ArrowDown' || event.key === 'ArrowRight'\n ? index + 1\n : event.key === 'ArrowUp' || event.key === 'ArrowLeft'\n ? index - 1\n : event.key === 'Home'\n ? 0\n : event.key === 'End'\n ? cards.length - 1\n : undefined;\n if (to !== undefined) {\n event.preventDefault();\n move(to);\n } else if (event.key === ' ') {\n // Space is the box's own key; the page does not scroll under it.\n event.preventDefault();\n if (!props.disabled) props.onToggle(index, !cards[index].on);\n }\n };\n return (\n <div\n className=\"choice-cards\"\n role=\"group\"\n data-fit={props.fit}\n id={props.id}\n aria-labelledby={props['aria-labelledby']}\n aria-describedby={props['aria-describedby']}\n aria-invalid={props['aria-invalid']}\n >\n {cards.map((card, index) => (\n <div\n key={card.key}\n ref={(face) => {\n faces.current[index] = face;\n }}\n role=\"checkbox\"\n aria-checked={card.on}\n aria-disabled={props.disabled || undefined}\n tabIndex={index === stop ? 0 : -1}\n className={`choice-card${card.on ? ' is-on' : ''}`}\n onClick={() => {\n setHeld(index);\n if (!props.disabled) props.onToggle(index, !card.on);\n }}\n onFocus={() => setHeld(index)}\n onKeyDown={(event) => keys(event, index)}\n >\n {card.icon ? (\n <span className=\"choice-card-icon\" aria-hidden=\"true\">\n {card.icon}\n </span>\n ) : null}\n <span className=\"choice-card-label\">\n {card.label}\n {card.help ? <span className=\"choice-card-help\">{card.help}</span> : null}\n </span>\n <span className=\"choice-box\" aria-hidden=\"true\" />\n </div>\n ))}\n </div>\n );\n}\n\nexport interface CheckboxProps extends Omit<FieldFrame, 'label'> {\n checked: boolean;\n onChange: (on: boolean) => void;\n /** The text beside the box; it is the label, so it is a click target too. */\n label: ReactNode;\n disabled?: boolean;\n}\n\n/** A checkbox beside its text. */\nexport function Checkbox(props: CheckboxProps): ReactNode {\n return (\n <Field {...frameOf(props)} check>\n {(control) => (\n <input\n {...control}\n type=\"checkbox\"\n className=\"field-check\"\n checked={props.checked}\n disabled={props.disabled}\n onChange={(e) => props.onChange(e.target.checked)}\n />\n )}\n </Field>\n );\n}\n\n/** A checkbox for a long notice: the paragraph is the label, in the body's weight. */\nexport function Consent(props: CheckboxProps): ReactNode {\n return <Checkbox {...props} className={['form-field-consent', props.className].filter(Boolean).join(' ')} />;\n}\n","/** What IntakeControls says, in the forms room (packages/kit/src/client/messages.ts says how the catalog is split). */\nimport { defineMessages } from '@mistriwork/kit/client/messages.js';\n\nexport const say = defineMessages({\n choosePlaceholder: 'Choose {label}',\n chooseOne: 'Choose one',\n showValue: 'Show',\n hideValue: 'Hide',\n yesWord: 'Yes',\n noWord: 'No',\n // A month's box, before anything is typed: the order its digits go in.\n monthPlaceholder: 'MM/YYYY',\n});\n","/**\n * The controls of the newer field vocabulary, drawn: an amount of money, a month, a text typed through its mask, a\n * sensitive number kept out of sight, a choice as cards or buttons, several choices, a yes-or-no as two buttons, a\n * consent beside its statement, and a number on a slider. A chunk of its own (CommandFields.tsx), fetched the first\n * time a form asks one, with the form controls' stylesheet: a form of plain boxes carries none of it.\n *\n * Each draws the control alone; the Field around it (CommandFields.tsx) is the label, the help and the problem. The\n * value each hands back is the one the shared reader (commandInput.ts) reads: an amount and a slider's number as\n * typed text or a number, a month as `YYYY-MM`, a masked text as the characters its places hold, choices as a list of\n * option values. A sensitive value lives in the form's state alone: nothing here keeps, logs or prefills it.\n */\nimport { useState, type AriaAttributes, type CSSProperties } from 'react';\nimport { useQuery } from '@tanstack/react-query';\nimport { Dropdown, readsAsName } from '@mistriwork/kit/client/components/Dropdown.js';\nimport { CheckCards } from '@mistriwork/ui/Choices.js';\nimport { run, type ChoiceSource } from './CommandReference.js';\nimport '@mistriwork/kit/client/formControls.css';\nimport './IntakeControls.css';\nimport type { AppCommandField } from '../../shared/command.js';\nimport type { CommandValue } from '../commandState.js';\nimport { defaultCurrency, formatLocale } from '@mistriwork/kit/client/locale.js';\nimport { currencyDigits } from '@mistriwork/engine/shared/money.js';\nimport { Icon } from '@mistriwork/kit/client/components/Icon.js';\nimport { isAppIcon } from '@mistriwork/engine/shared/appIcons.js';\nimport { say } from '../copy/forms/components/IntakeControls.js';\nimport { amountIn, maskShown, moneySymbol, PLACE } from './fieldShown.js';\n\ntype Field = AppCommandField;\ntype Choice = Extract<Field, { type: 'choice' | 'choices' }>['options'][number];\n\ninterface IntakeControlProps {\n field: Field;\n id: string;\n 'aria-describedby'?: string;\n 'aria-invalid'?: AriaAttributes['aria-invalid'];\n value: CommandValue | undefined;\n disabled?: boolean;\n onChange: (value: CommandValue) => void;\n /** The App's currency, ISO 4217; an amount is said in it. */\n currency?: string;\n /** Where a choice from a table reads its rows: the reader's connection, or a public form's App as its visitor. */\n source?: ChoiceSource;\n}\n\n/** At most this many rows are offered by a choice from a table; past it the form is a reference's to ask. */\nconst SOURCED_MOST = 200;\n/** Cards for a few, the listbox past this many. */\nconst CARDS_MOST = 6;\n\n/* A choice from a table's rows: read once per form through the reader's own read (a visitor's, on a public form,\n answers only what `auth.public` opens), each row's key its value and its label column its words. */\nfunction useSourced(field: Field, source: ChoiceSource | undefined): readonly Choice[] | undefined {\n const from = (field.type === 'choice' || field.type === 'choices') && field.source ? field.source : undefined;\n /* A public form is served its rows with it (server forms/formChoices.ts, tenantPublicChoices.ts), under the form's own\n ETag: nothing to read. `served` says the list is the whole answer, so an empty one offers nothing rather than\n reading — a tenant's visitor on the shared host has no read of its own to ask. */\n const served =\n from && (field.type === 'choice' || field.type === 'choices') && (from.served || field.options.length) ? field.options : undefined;\n const read = useQuery({\n queryKey: ['command-choices', typeof source === 'string' ? source : source?.visitor, from?.from, from?.by, from?.labelColumn],\n enabled: from !== undefined && source !== undefined && served === undefined,\n staleTime: 60_000,\n queryFn: async () => {\n const columns = [...new Set([from!.by, from!.labelColumn])].join(', ');\n const data = await run(source!, {\n q: `${from!.from} show ${columns} sort ${from!.labelColumn}`,\n limit: SOURCED_MOST,\n offset: 0,\n count: 'none',\n });\n const rows = Array.isArray(data.rows) ? (data.rows as Record<string, unknown>[]) : [];\n return rows.flatMap((row) => {\n const value = row[from!.by];\n return typeof value === 'string' || typeof value === 'number' ? [{ value, label: String(row[from!.labelColumn] ?? value) }] : [];\n });\n },\n });\n return from ? (served ?? read.data) : undefined;\n}\n\n/** Whether the field is one this module draws (the rest are CommandFields' own). */\nexport function drawnHere(field: Field): boolean {\n switch (field.type) {\n case 'money':\n case 'month':\n case 'choices':\n return true;\n case 'number':\n return field.as === 'slider';\n case 'text':\n return field.mask !== undefined || field.sensitive !== undefined;\n case 'boolean':\n return field.as === 'buttons' || field.statement !== undefined;\n case 'choice':\n return field.as === 'cards' || field.as === 'buttons' || field.source !== undefined;\n default:\n return false;\n }\n}\n\n/** The characters `typed` holds that the mask's places take, in order, as many as it has places. */\nfunction maskRaw(mask: string, typed: string): string {\n const places = [...mask].filter((c) => PLACE.test(c));\n let out = '';\n for (const ch of typed) {\n const place = places[out.length];\n if (!place) break;\n if (place === '0' ? /\\d/.test(ch) : place === 'a' ? /[A-Za-z]/.test(ch) : /[A-Za-z0-9]/.test(ch)) out += ch;\n }\n return out;\n}\n\n/** The keyboard a mask asks for: digits alone are the number pad. */\nconst maskKeys = (mask: string): 'numeric' | 'text' => ([...mask].every((c) => !PLACE.test(c) || c === '0') ? 'numeric' : 'text');\n\n/** A month typed `MM/YYYY` as the `YYYY-MM` the reader reads; anything short of one is handed on as typed. */\nfunction monthValue(typed: string): string {\n const digits = typed.replace(/\\D/g, '').slice(0, 6);\n return digits.length === 6 ? `${digits.slice(2)}-${digits.slice(0, 2)}` : digits;\n}\nconst monthShown = (value: string): string => {\n const iso = /^(\\d{4})-(\\d{2})$/.exec(value);\n const digits = iso ? `${iso[2]}${iso[1]}` : value.replace(/\\D/g, '');\n return digits.length > 2 ? `${digits.slice(0, 2)}/${digits.slice(2)}` : digits;\n};\n\nconst optionKey = (option: Choice) => `${typeof option.value}:${option.value}`;\n\n/* How short a set of cards' words are. A wide page sets short ones side by side (structure.css) rather than stretching\n \"Tile\" across 40rem; a phone and a dialog keep one card a row whatever this says. Lengths are characters because\n the measure is the column, not a font: a label of 14 fits a third of it beside its icon and its mark, one of 24 and\n a line of 40 a half. */\nconst SHORT_LABEL = 14;\nconst BRIEF_LABEL = 24;\nconst BRIEF_HELP = 40;\nfunction cardFit(options: readonly Choice[]): 'short' | 'brief' | undefined {\n if (options.length < 3 || options.some((option) => option.label.length > BRIEF_LABEL)) return undefined;\n if (options.every((option) => !option.help && option.label.length <= SHORT_LABEL)) return 'short';\n return options.every((option) => (option.help?.length ?? 0) <= BRIEF_HELP) ? 'brief' : undefined;\n}\n\n/* A choice from a table: its rows read (the one control here that reads anything), then drawn as written choices. */\nfunction SourcedControl(props: IntakeControlProps) {\n const sourced = useSourced(props.field, props.source);\n const { field, id, value, disabled, onChange } = props;\n if (field.type !== 'choice' && field.type !== 'choices') return null;\n if (!sourced) return null;\n const options = sourced;\n const drawn = { ...field, options, source: undefined } as typeof field;\n // A few rows are cards; more are the listbox (one) or checks (several), unless the field says how.\n if (field.type === 'choice' && field.as !== 'cards' && field.as !== 'buttons' && (field.as === 'select' || options.length > CARDS_MOST)) {\n const chosen = options.findIndex((option) => option.value === value);\n return (\n <Dropdown\n id={id}\n ariaLabelledBy={`${id}-label`}\n ariaInvalid={props['aria-invalid'] === true || props['aria-invalid'] === 'true'}\n ariaDescribedBy={props['aria-describedby']}\n disabled={disabled}\n value={chosen < 0 ? '' : String(chosen)}\n valueClassName={chosen < 0 ? 'is-empty' : undefined}\n items={[\n ...(chosen < 0\n ? [\n {\n value: '',\n label: readsAsName(field.label) ? say('choosePlaceholder', { label: field.label.toLowerCase() }) : say('chooseOne'),\n },\n ]\n : []),\n ...options.map((option, index) => ({ value: String(index), label: option.label })),\n ]}\n onChange={(next) => {\n if (next !== '') onChange(options[Number(next)].value);\n }}\n />\n );\n }\n return <IntakeControl {...props} field={drawn} />;\n}\n\n/* An amount as it is read once typed, grouped in the App's locale (`2,500`); while it is typed, the digits alone, so the\n caret never jumps over a separator that arrived under it. */\nfunction amountShown(value: unknown): string {\n const raw = String(value ?? '');\n const amount = Number(raw);\n return raw.trim() && Number.isFinite(amount) ? amount.toLocaleString(formatLocale(), { maximumFractionDigits: 20 }) : raw;\n}\n\n/* A minor-unit amount as it is read once typed: grouped, and always to the currency's own places ($12.50, ¥1,500), the\n decimal text handed to Intl whole so a figure past 2^53 is not rounded by a float on the way. */\nfunction minorShown(value: unknown, digits: number): string {\n const raw = String(value ?? '');\n if (!/^-?\\d*\\.?\\d*$/.test(raw.trim()) || !/\\d/.test(raw)) return raw;\n try {\n return new Intl.NumberFormat(formatLocale(), { minimumFractionDigits: digits, maximumFractionDigits: digits }).format(\n raw.trim() as unknown as number,\n );\n } catch {\n return raw;\n }\n}\n\n/* What a person types into a minor-unit box: digits and one point, at most the currency's places after it. */\nfunction minorTyped(text: string, digits: number): string {\n const [whole, ...rest] = text.replace(/[^\\d.-]/g, '').split('.');\n return digits && rest.length ? `${whole}.${rest.join('').slice(0, digits)}` : whole;\n}\n\nexport function IntakeControl(props: IntakeControlProps) {\n const { field, id, value, disabled, onChange } = props;\n const aria = { 'aria-describedby': props['aria-describedby'], 'aria-invalid': props['aria-invalid'] };\n const [shown, setShown] = useState(false);\n const [typing, setTyping] = useState(false);\n\n if (field.type === 'money' && field.as !== 'slider') {\n /* The symbol stands inside the box, over its start, hidden from a screen reader so it hears the amount alone; the\n box's words start after it, by the sign's length in the box's own digits (a \"CHF\" takes three). */\n const currency = (field.currency || props.currency) ?? undefined;\n const symbol = moneySymbol(currency);\n const places = field.minor ? currencyDigits(currency || defaultCurrency()) : undefined;\n return (\n <div className=\"intake-money\">\n <span className=\"intake-money-symbol\" aria-hidden=\"true\">\n {symbol}\n </span>\n <input\n {...aria}\n id={id}\n className=\"field-control\"\n style={{ paddingInlineStart: `calc(var(--money-pad) + ${symbol.length}ch + var(--space-2))` }}\n type=\"text\"\n inputMode={\n (places === undefined ? field.step !== undefined && Number.isInteger(field.step) : places === 0) ? 'numeric' : 'decimal'\n }\n enterKeyHint=\"next\"\n autoComplete=\"off\"\n disabled={disabled}\n required={field.required}\n value={typing ? String(value ?? '') : places === undefined ? amountShown(value) : minorShown(value, places)}\n onFocus={() => setTyping(true)}\n onBlur={() => setTyping(false)}\n onChange={(event) =>\n onChange(places === undefined ? event.target.value.replace(/[^\\d.-]/g, '') : minorTyped(event.target.value, places))\n }\n />\n </div>\n );\n }\n if (field.type === 'month') {\n return (\n <input\n {...aria}\n id={id}\n className=\"field-control intake-month\"\n type=\"text\"\n inputMode=\"numeric\"\n enterKeyHint=\"next\"\n autoComplete=\"off\"\n placeholder={say('monthPlaceholder')}\n disabled={disabled}\n required={field.required}\n value={monthShown(typeof value === 'string' ? value : '')}\n onChange={(event) => onChange(monthValue(event.target.value))}\n />\n );\n }\n if ((field.type === 'number' || field.type === 'money') && field.as === 'slider') {\n const min = field.min ?? 0;\n const max = field.max ?? 100;\n const at = typeof value === 'number' ? value : value === undefined || value === '' ? min : Number(value);\n const share = max > min ? ((at - min) / (max - min)) * 100 : 0;\n // An amount reads as one, in the App's currency ($500); a number as the locale writes it.\n const saying = (n: number) => (field.type === 'money' ? amountIn(n, props.currency, field.step) : n.toLocaleString(formatLocale()));\n const said = saying(at);\n return (\n <div className=\"intake-slider\">\n <output className=\"field-control field-readout\" htmlFor={id} aria-hidden=\"true\">\n {said}\n </output>\n <input\n {...aria}\n id={id}\n type=\"range\"\n className=\"field-range\"\n min={min}\n max={max}\n step={field.step ?? (field.type === 'money' ? 1 : field.integer ? 1 : 'any')}\n value={at}\n disabled={disabled}\n aria-valuetext={said}\n style={{ '--range-share': `${share}%` } as CSSProperties}\n onChange={(event) => onChange(Number(event.target.value))}\n />\n {/* The two ends, read off the track; the range's own min and max say them to a screen reader. */}\n <div className=\"intake-slider-ends\" aria-hidden=\"true\">\n <span>{saying(min)}</span>\n <span>{saying(max)}</span>\n </div>\n </div>\n );\n }\n if (field.type === 'text' && field.sensitive) {\n const raw = typeof value === 'string' ? value : '';\n const drawn = field.mask ? maskShown(field.mask, raw) : raw;\n return (\n <div className=\"field-with-action\">\n <input\n {...aria}\n id={id}\n className={`field-control${shown ? '' : ' field-hidden'}`}\n type={shown ? 'text' : 'password'}\n inputMode={field.mask ? maskKeys(field.mask) : 'text'}\n enterKeyHint=\"next\"\n autoComplete=\"off\"\n autoCorrect=\"off\"\n autoCapitalize=\"off\"\n spellCheck={false}\n data-1p-ignore\n data-lpignore=\"true\"\n disabled={disabled}\n required={field.required}\n value={drawn}\n onChange={(event) => onChange(field.mask ? maskRaw(field.mask, event.target.value) : event.target.value)}\n />\n <button type=\"button\" className=\"btn btn-quiet\" aria-controls={id} aria-pressed={shown} onClick={() => setShown(!shown)}>\n {shown ? say('hideValue') : say('showValue')}\n </button>\n </div>\n );\n }\n if (field.type === 'text' && field.mask) {\n const mask = field.mask;\n return (\n <input\n {...aria}\n id={id}\n className=\"field-control\"\n type=\"text\"\n inputMode={maskKeys(mask)}\n enterKeyHint=\"next\"\n autoComplete=\"off\"\n placeholder={mask.replace(/[0a*]/g, '_')}\n disabled={disabled}\n required={field.required}\n value={maskShown(mask, typeof value === 'string' ? value : '')}\n onChange={(event) => onChange(maskRaw(mask, event.target.value))}\n />\n );\n }\n if (field.type === 'boolean') {\n if (field.as === 'buttons') {\n return (\n <div className=\"choice-pair\" role=\"radiogroup\" id={id} aria-labelledby={`${id}-label`} {...aria}>\n {([true, false] as const).map((answer) => (\n <label key={String(answer)} className={`choice-pick${value === answer ? ' is-on' : ''}`}>\n <input\n type=\"radio\"\n name={id}\n className=\"choice-input\"\n checked={value === answer}\n disabled={disabled}\n onChange={() => onChange(answer)}\n />\n {answer ? say('yesWord') : say('noWord')}\n </label>\n ))}\n </div>\n );\n }\n // A consent: the statement is the box's own words, so the box is named by them.\n return (\n <span className=\"intake-consent\">\n <input\n {...aria}\n id={id}\n type=\"checkbox\"\n className=\"command-check field-check\"\n required={field.accept === true}\n checked={value === true}\n disabled={disabled}\n onChange={(event) => onChange(event.target.checked)}\n />\n <span className=\"intake-statement\">{field.statement}</span>\n </span>\n );\n }\n if ((field.type === 'choice' || field.type === 'choices') && field.source) return <SourcedControl {...props} />;\n if (field.type === 'choice' || field.type === 'choices') {\n const several = field.type === 'choices';\n const chosen: readonly unknown[] = several ? (Array.isArray(value) ? value : []) : value === undefined ? [] : [value];\n const exclusive = field.type === 'choices' ? (field.exclusive ?? []) : [];\n const toggle = (option: Choice, on: boolean) => {\n if (!several) return onChange(option.value);\n if (exclusive.includes(option.value)) return onChange(on ? [option.value] : []);\n const rest = chosen.filter((v) => v !== option.value && !exclusive.includes(v as string | number));\n onChange(field.options.map((o) => o.value).filter((v) => (on && v === option.value) || rest.includes(v)) as CommandValue);\n };\n const buttons = field.as === 'buttons';\n /* Several cards are one group to the keyboard, as one choice's radios are (CheckCards): one Tab stop, the arrows\n between them, Space to turn one on or off, each saying aria-checked. */\n if (several)\n return (\n <CheckCards\n id={id}\n aria-labelledby={`${id}-label`}\n aria-describedby={props['aria-describedby']}\n aria-invalid={props['aria-invalid']}\n disabled={disabled}\n fit={cardFit(field.options)}\n cards={field.options.map((option) => ({\n key: optionKey(option),\n label: option.label,\n icon: option.icon && isAppIcon(option.icon) ? <Icon name={option.icon} /> : undefined,\n help: option.help,\n on: chosen.includes(option.value),\n }))}\n onToggle={(index, on) => toggle(field.options[index], on)}\n />\n );\n return (\n <div\n className={buttons ? 'choice-pair intake-buttons' : 'choice-cards'}\n data-fit={buttons ? undefined : cardFit(field.options)}\n role={several ? 'group' : 'radiogroup'}\n id={id}\n aria-labelledby={`${id}-label`}\n aria-required={(!several && field.required) || undefined}\n {...aria}\n >\n {field.options.map((option) => {\n const on = chosen.includes(option.value);\n return (\n <label key={optionKey(option)} className={`${buttons ? 'choice-pick' : 'choice-card'}${on ? ' is-on' : ''}`}>\n {option.icon && !buttons && isAppIcon(option.icon) ? (\n <span className=\"choice-card-icon\" aria-hidden=\"true\">\n <Icon name={option.icon} />\n </span>\n ) : null}\n <span className=\"choice-card-label\">\n {option.label}\n {option.help && !buttons ? <span className=\"intake-choice-help\">{option.help}</span> : null}\n </span>\n <input\n type={several ? 'checkbox' : 'radio'}\n name={several ? undefined : id}\n className=\"choice-input\"\n checked={on}\n disabled={disabled}\n onChange={(event) => toggle(option, event.target.checked)}\n />\n {buttons ? null : <span className=\"choice-box\" aria-hidden=\"true\" />}\n </label>\n );\n })}\n </div>\n );\n }\n return null;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"shared-CLq3-_hW.js","names":[],"sources":["../../../ui/src/Choices.tsx","../../src/client/copy/forms/components/IntakeControls.ts","../../src/client/components/IntakeControls.tsx"],"sourcesContent":["/**\n * Choices drawn as buttons, cards and checkboxes: Yes/No, icon cards (one or several), a checkbox and a consent. One\n * answer is a native radio dressed, so the arrows, Space and the form's own semantics are the browser's, and the focus\n * ring shows on the face when the keyboard is on the input. Several cards are one group as the radios are (CheckCards):\n * one Tab stop, the arrows move between them, Space turns one on or off, and each says `aria-checked`. Props only.\n * Preview: @mistriwork/ui is Preview at 1.0.\n */\nimport { useId, useRef, useState, type AriaAttributes, type KeyboardEvent, type ReactNode } from 'react';\nimport { Field } from './Field.js';\nimport { frameOf, type FieldFrame } from './fieldFrame.js';\n\nexport interface ChoiceOption {\n value: string;\n label: string;\n /** A picture for a card. */\n icon?: ReactNode;\n}\n\nexport interface YesNoProps extends Omit<FieldFrame, 'label'> {\n /** The question. */\n label: ReactNode;\n value: 'yes' | 'no' | '';\n onChange: (value: 'yes' | 'no') => void;\n /** The two words, in the caller's language. */\n yes: string;\n no: string;\n}\n\n/** Two buttons answering a question. */\nexport function YesNo(props: YesNoProps): ReactNode {\n const name = useId();\n return (\n <Field {...frameOf(props)} group>\n {(control) => (\n <div\n className=\"choice-pair\"\n role=\"radiogroup\"\n aria-labelledby={control['aria-labelledby']}\n aria-describedby={control['aria-describedby']}\n aria-invalid={control['aria-invalid']}\n >\n {(['yes', 'no'] as const).map((v) => (\n <label key={v} className={`choice-pick${props.value === v ? ' is-on' : ''}`}>\n <input type=\"radio\" name={name} className=\"choice-input\" checked={props.value === v} onChange={() => props.onChange(v)} />\n {props[v]}\n </label>\n ))}\n </div>\n )}\n </Field>\n );\n}\n\nexport interface ChoiceCardsProps extends FieldFrame {\n options: ChoiceOption[];\n value: string[];\n onChange: (value: string[]) => void;\n /** Several may be on. */\n multiple?: boolean;\n /** The card that stands alone (\"None\"): choosing it clears the rest, and choosing another clears it. */\n exclusive?: string;\n}\n\n/** Cards with an icon, a label and a box. One choice is a radio group; `multiple` a group of checkboxes. */\nexport function ChoiceCards(props: ChoiceCardsProps): ReactNode {\n const name = useId();\n const toggle = (v: string, on: boolean): void => {\n if (!props.multiple) return props.onChange(on ? [v] : []);\n if (v === props.exclusive) return props.onChange(on ? [v] : []);\n const rest = props.value.filter((x) => x !== v && x !== props.exclusive);\n props.onChange(on ? props.options.map((o) => o.value).filter((x) => x === v || rest.includes(x)) : rest);\n };\n if (props.multiple)\n return (\n <Field {...frameOf(props)} group>\n {(control) => (\n <CheckCards\n aria-labelledby={control['aria-labelledby']}\n aria-describedby={control['aria-describedby']}\n aria-invalid={control['aria-invalid']}\n cards={props.options.map((o) => ({ key: o.value, label: o.label, icon: o.icon, on: props.value.includes(o.value) }))}\n onToggle={(index, on) => toggle(props.options[index].value, on)}\n />\n )}\n </Field>\n );\n return (\n <Field {...frameOf(props)} group>\n {(control) => (\n <div\n className=\"choice-cards\"\n role=\"radiogroup\"\n aria-labelledby={control['aria-labelledby']}\n aria-describedby={control['aria-describedby']}\n aria-invalid={control['aria-invalid']}\n >\n {props.options.map((o) => {\n const on = props.value.includes(o.value);\n return (\n <label key={o.value} className={`choice-card${on ? ' is-on' : ''}`}>\n {o.icon ? (\n <span className=\"choice-card-icon\" aria-hidden=\"true\">\n {o.icon}\n </span>\n ) : null}\n <span className=\"choice-card-label\">{o.label}</span>\n <input type=\"radio\" name={name} className=\"choice-input\" checked={on} onChange={(e) => toggle(o.value, e.target.checked)} />\n <span className=\"choice-box\" aria-hidden=\"true\" />\n </label>\n );\n })}\n </div>\n )}\n </Field>\n );\n}\n\n/** One card of several: its words, its picture and whether it is on. */\nexport interface CheckCard {\n key: string;\n label: ReactNode;\n icon?: ReactNode;\n /** A line under the label. */\n help?: ReactNode;\n on: boolean;\n}\n\nexport interface CheckCardsProps {\n cards: readonly CheckCard[];\n /** The card at `index` turned on or off. */\n onToggle: (index: number, on: boolean) => void;\n id?: string;\n disabled?: boolean;\n 'aria-labelledby'?: string;\n 'aria-describedby'?: string;\n 'aria-invalid'?: AriaAttributes['aria-invalid'];\n /** How short every card's words are, so a wide page can set them side by side (`data-fit`; the page's stylesheet\n * decides what that means): `short` is a label alone, `brief` a label and a line that fit half a column. */\n fit?: 'short' | 'brief';\n}\n\n/**\n * Several cards, any of them on: full-width cards, each an icon, its words and a square at its end that fills when it\n * is on. They are one group to the keyboard, as radios are — one Tab stop (the card last moved to, else the first one\n * on, else the first), the arrows and Home and End move between them, and Space turns the one in hand on or off — and\n * each is a `checkbox` saying `aria-checked`, so a screen reader hears \"checked\" as it moves.\n */\nexport function CheckCards(props: CheckCardsProps): ReactNode {\n const { cards } = props;\n const [held, setHeld] = useState<number | undefined>(undefined);\n const faces = useRef<(HTMLDivElement | null)[]>([]);\n const first = cards.findIndex((card) => card.on);\n const stop = held !== undefined && held < cards.length ? held : Math.max(first, 0);\n const move = (to: number) => {\n const next = (to + cards.length) % cards.length;\n setHeld(next);\n faces.current[next]?.focus();\n };\n const keys = (event: KeyboardEvent<HTMLDivElement>, index: number) => {\n const to =\n event.key === 'ArrowDown' || event.key === 'ArrowRight'\n ? index + 1\n : event.key === 'ArrowUp' || event.key === 'ArrowLeft'\n ? index - 1\n : event.key === 'Home'\n ? 0\n : event.key === 'End'\n ? cards.length - 1\n : undefined;\n if (to !== undefined) {\n event.preventDefault();\n move(to);\n } else if (event.key === ' ') {\n // Space is the box's own key; the page does not scroll under it.\n event.preventDefault();\n if (!props.disabled) props.onToggle(index, !cards[index].on);\n }\n };\n return (\n <div\n className=\"choice-cards\"\n role=\"group\"\n data-fit={props.fit}\n id={props.id}\n aria-labelledby={props['aria-labelledby']}\n aria-describedby={props['aria-describedby']}\n aria-invalid={props['aria-invalid']}\n >\n {cards.map((card, index) => (\n <div\n key={card.key}\n ref={(face) => {\n faces.current[index] = face;\n }}\n role=\"checkbox\"\n aria-checked={card.on}\n aria-disabled={props.disabled || undefined}\n tabIndex={index === stop ? 0 : -1}\n className={`choice-card${card.on ? ' is-on' : ''}`}\n onClick={() => {\n setHeld(index);\n if (!props.disabled) props.onToggle(index, !card.on);\n }}\n onFocus={() => setHeld(index)}\n onKeyDown={(event) => keys(event, index)}\n >\n {card.icon ? (\n <span className=\"choice-card-icon\" aria-hidden=\"true\">\n {card.icon}\n </span>\n ) : null}\n <span className=\"choice-card-label\">\n {card.label}\n {card.help ? <span className=\"choice-card-help\">{card.help}</span> : null}\n </span>\n <span className=\"choice-box\" aria-hidden=\"true\" />\n </div>\n ))}\n </div>\n );\n}\n\nexport interface CheckboxProps extends Omit<FieldFrame, 'label'> {\n checked: boolean;\n onChange: (on: boolean) => void;\n /** The text beside the box; it is the label, so it is a click target too. */\n label: ReactNode;\n disabled?: boolean;\n}\n\n/** A checkbox beside its text. */\nexport function Checkbox(props: CheckboxProps): ReactNode {\n return (\n <Field {...frameOf(props)} check>\n {(control) => (\n <input\n {...control}\n type=\"checkbox\"\n className=\"field-check\"\n checked={props.checked}\n disabled={props.disabled}\n onChange={(e) => props.onChange(e.target.checked)}\n />\n )}\n </Field>\n );\n}\n\n/** A checkbox for a long notice: the paragraph is the label, in the body's weight. */\nexport function Consent(props: CheckboxProps): ReactNode {\n return <Checkbox {...props} className={['form-field-consent', props.className].filter(Boolean).join(' ')} />;\n}\n","/** What IntakeControls says, in the forms room (packages/kit/src/client/messages.ts says how the catalog is split). */\nimport { defineMessages } from '@mistriwork/kit/client/messages.js';\n\nexport const say = defineMessages({\n choosePlaceholder: 'Choose {label}',\n chooseOne: 'Choose one',\n showValue: 'Show',\n hideValue: 'Hide',\n yesWord: 'Yes',\n noWord: 'No',\n // A month's box, before anything is typed: the order its digits go in.\n monthPlaceholder: 'MM/YYYY',\n});\n","/**\n * The controls of the newer field vocabulary, drawn: an amount of money, a month, a text typed through its mask, a\n * sensitive number kept out of sight, a choice as cards or buttons, several choices, a yes-or-no as two buttons, a\n * consent beside its statement, and a number on a slider. A chunk of its own (CommandFields.tsx), fetched the first\n * time a form asks one, with the form controls' stylesheet: a form of plain boxes carries none of it.\n *\n * Each draws the control alone; the Field around it (CommandFields.tsx) is the label, the help and the problem. The\n * value each hands back is the one the shared reader (commandInput.ts) reads: an amount and a slider's number as\n * typed text or a number, a month as `YYYY-MM`, a masked text as the characters its places hold, choices as a list of\n * option values. A sensitive value lives in the form's state alone: nothing here keeps, logs or prefills it.\n */\nimport { useState, type AriaAttributes, type CSSProperties } from 'react';\nimport { useQuery } from '@tanstack/react-query';\nimport { Dropdown, readsAsName } from '@mistriwork/kit/client/components/Dropdown.js';\nimport { CheckCards } from '@mistriwork/ui/Choices.js';\nimport { run, type ChoiceSource } from './CommandReference.js';\nimport '@mistriwork/kit/client/formControls.css';\nimport './IntakeControls.css';\nimport type { AppCommandField } from '../../shared/command.js';\nimport type { CommandValue } from '../commandState.js';\nimport { defaultCurrency, formatLocale } from '@mistriwork/kit/client/locale.js';\nimport { currencyDigits } from '@mistriwork/engine/shared/money.js';\nimport { Icon } from '@mistriwork/kit/client/components/Icon.js';\nimport { isAppIcon } from '@mistriwork/engine/shared/appIcons.js';\nimport { say } from '../copy/forms/components/IntakeControls.js';\nimport { amountIn, maskShown, moneySymbol, PLACE } from './fieldShown.js';\n\ntype Field = AppCommandField;\ntype Choice = Extract<Field, { type: 'choice' | 'choices' }>['options'][number];\n\ninterface IntakeControlProps {\n field: Field;\n id: string;\n 'aria-describedby'?: string;\n 'aria-invalid'?: AriaAttributes['aria-invalid'];\n value: CommandValue | undefined;\n disabled?: boolean;\n onChange: (value: CommandValue) => void;\n /** The App's currency, ISO 4217; an amount is said in it. */\n currency?: string;\n /** Where a choice from a table reads its rows: the reader's connection, or a public form's App as its visitor. */\n source?: ChoiceSource;\n}\n\n/** At most this many rows are offered by a choice from a table; past it the form is a reference's to ask. */\nconst SOURCED_MOST = 200;\n/** Cards for a few, the listbox past this many. */\nconst CARDS_MOST = 6;\n\n/* A choice from a table's rows: read once per form through the reader's own read (a visitor's, on a public form,\n answers only what `auth.public` opens), each row's key its value and its label column its words. */\nfunction useSourced(field: Field, source: ChoiceSource | undefined): readonly Choice[] | undefined {\n const from = (field.type === 'choice' || field.type === 'choices') && field.source ? field.source : undefined;\n /* A public form is served its rows with it (server forms/formChoices.ts, tenantPublicChoices.ts), under the form's own\n ETag: nothing to read. `served` says the list is the whole answer, so an empty one offers nothing rather than\n reading — a tenant's visitor on the shared host has no read of its own to ask. */\n const served =\n from && (field.type === 'choice' || field.type === 'choices') && (from.served || field.options.length) ? field.options : undefined;\n const read = useQuery({\n queryKey: ['command-choices', typeof source === 'string' ? source : source?.visitor, from?.from, from?.by, from?.labelColumn],\n enabled: from !== undefined && source !== undefined && served === undefined,\n staleTime: 60_000,\n queryFn: async () => {\n const columns = [...new Set([from!.by, from!.labelColumn])].join(', ');\n const data = await run(source!, {\n q: `${from!.from} show ${columns} sort ${from!.labelColumn}`,\n limit: SOURCED_MOST,\n offset: 0,\n count: 'none',\n });\n const rows = Array.isArray(data.rows) ? (data.rows as Record<string, unknown>[]) : [];\n return rows.flatMap((row) => {\n const value = row[from!.by];\n return typeof value === 'string' || typeof value === 'number' ? [{ value, label: String(row[from!.labelColumn] ?? value) }] : [];\n });\n },\n });\n return from ? (served ?? read.data) : undefined;\n}\n\n/** Whether the field is one this module draws (the rest are CommandFields' own). */\nexport function drawnHere(field: Field): boolean {\n switch (field.type) {\n case 'money':\n case 'month':\n case 'choices':\n return true;\n case 'number':\n return field.as === 'slider';\n case 'text':\n return field.mask !== undefined || field.sensitive !== undefined;\n case 'boolean':\n return field.as === 'buttons' || field.statement !== undefined;\n case 'choice':\n return field.as === 'cards' || field.as === 'buttons' || field.source !== undefined;\n default:\n return false;\n }\n}\n\n/** The characters `typed` holds that the mask's places take, in order, as many as it has places. */\nfunction maskRaw(mask: string, typed: string): string {\n const places = [...mask].filter((c) => PLACE.test(c));\n let out = '';\n for (const ch of typed) {\n const place = places[out.length];\n if (!place) break;\n if (place === '0' ? /\\d/.test(ch) : place === 'a' ? /[A-Za-z]/.test(ch) : /[A-Za-z0-9]/.test(ch)) out += ch;\n }\n return out;\n}\n\n/** The keyboard a mask asks for: digits alone are the number pad. */\nconst maskKeys = (mask: string): 'numeric' | 'text' => ([...mask].every((c) => !PLACE.test(c) || c === '0') ? 'numeric' : 'text');\n\n/** A month typed `MM/YYYY` as the `YYYY-MM` the reader reads; anything short of one is handed on as typed. */\nfunction monthValue(typed: string): string {\n const digits = typed.replace(/\\D/g, '').slice(0, 6);\n return digits.length === 6 ? `${digits.slice(2)}-${digits.slice(0, 2)}` : digits;\n}\nconst monthShown = (value: string): string => {\n const iso = /^(\\d{4})-(\\d{2})$/.exec(value);\n const digits = iso ? `${iso[2]}${iso[1]}` : value.replace(/\\D/g, '');\n return digits.length > 2 ? `${digits.slice(0, 2)}/${digits.slice(2)}` : digits;\n};\n\nconst optionKey = (option: Choice) => `${typeof option.value}:${option.value}`;\n\n/* How short a set of cards' words are. A wide page sets short ones side by side (structure.css) rather than stretching\n \"Tile\" across 40rem; a phone and a dialog keep one card a row whatever this says. Lengths are characters because\n the measure is the column, not a font: a label of 14 fits a third of it beside its icon and its mark, one of 24 and\n a line of 40 a half. */\nconst SHORT_LABEL = 14;\nconst BRIEF_LABEL = 24;\nconst BRIEF_HELP = 40;\nfunction cardFit(options: readonly Choice[]): 'short' | 'brief' | undefined {\n if (options.length < 3 || options.some((option) => option.label.length > BRIEF_LABEL)) return undefined;\n if (options.every((option) => !option.help && option.label.length <= SHORT_LABEL)) return 'short';\n return options.every((option) => (option.help?.length ?? 0) <= BRIEF_HELP) ? 'brief' : undefined;\n}\n\n/* A choice from a table: its rows read (the one control here that reads anything), then drawn as written choices. */\nfunction SourcedControl(props: IntakeControlProps) {\n const sourced = useSourced(props.field, props.source);\n const { field, id, value, disabled, onChange } = props;\n if (field.type !== 'choice' && field.type !== 'choices') return null;\n if (!sourced) return null;\n const options = sourced;\n const drawn = { ...field, options, source: undefined } as typeof field;\n // A few rows are cards; more are the listbox (one) or checks (several), unless the field says how.\n if (field.type === 'choice' && field.as !== 'cards' && field.as !== 'buttons' && (field.as === 'select' || options.length > CARDS_MOST)) {\n const chosen = options.findIndex((option) => option.value === value);\n return (\n <Dropdown\n id={id}\n ariaLabelledBy={`${id}-label`}\n ariaInvalid={props['aria-invalid'] === true || props['aria-invalid'] === 'true'}\n ariaDescribedBy={props['aria-describedby']}\n disabled={disabled}\n value={chosen < 0 ? '' : String(chosen)}\n valueClassName={chosen < 0 ? 'is-empty' : undefined}\n items={[\n ...(chosen < 0\n ? [\n {\n value: '',\n label: readsAsName(field.label) ? say('choosePlaceholder', { label: field.label.toLowerCase() }) : say('chooseOne'),\n },\n ]\n : []),\n ...options.map((option, index) => ({ value: String(index), label: option.label })),\n ]}\n onChange={(next) => {\n if (next !== '') onChange(options[Number(next)].value);\n }}\n />\n );\n }\n return <IntakeControl {...props} field={drawn} />;\n}\n\n/* An amount as it is read once typed, grouped in the App's locale (`2,500`); while it is typed, the digits alone, so the\n caret never jumps over a separator that arrived under it. */\nfunction amountShown(value: unknown): string {\n const raw = String(value ?? '');\n const amount = Number(raw);\n return raw.trim() && Number.isFinite(amount) ? amount.toLocaleString(formatLocale(), { maximumFractionDigits: 20 }) : raw;\n}\n\n/* A minor-unit amount as it is read once typed: grouped, and always to the currency's own places ($12.50, ¥1,500), the\n decimal text handed to Intl whole so a figure past 2^53 is not rounded by a float on the way. */\nfunction minorShown(value: unknown, digits: number): string {\n const raw = String(value ?? '');\n if (!/^-?\\d*\\.?\\d*$/.test(raw.trim()) || !/\\d/.test(raw)) return raw;\n try {\n return new Intl.NumberFormat(formatLocale(), { minimumFractionDigits: digits, maximumFractionDigits: digits }).format(\n raw.trim() as unknown as number,\n );\n } catch {\n return raw;\n }\n}\n\n/* What a person types into a minor-unit box: digits and one point, at most the currency's places after it. */\nfunction minorTyped(text: string, digits: number): string {\n const [whole, ...rest] = text.replace(/[^\\d.-]/g, '').split('.');\n return digits && rest.length ? `${whole}.${rest.join('').slice(0, digits)}` : whole;\n}\n\nexport function IntakeControl(props: IntakeControlProps) {\n const { field, id, value, disabled, onChange } = props;\n const aria = { 'aria-describedby': props['aria-describedby'], 'aria-invalid': props['aria-invalid'] };\n const [shown, setShown] = useState(false);\n const [typing, setTyping] = useState(false);\n\n if (field.type === 'money' && field.as !== 'slider') {\n /* The symbol stands inside the box, over its start, hidden from a screen reader so it hears the amount alone; the\n box's words start after it, by the sign's length in the box's own digits (a \"CHF\" takes three). */\n const currency = (field.currency || props.currency) ?? undefined;\n const symbol = moneySymbol(currency);\n const places = field.minor ? currencyDigits(currency || defaultCurrency()) : undefined;\n return (\n <div className=\"intake-money\">\n <span className=\"intake-money-symbol\" aria-hidden=\"true\">\n {symbol}\n </span>\n <input\n {...aria}\n id={id}\n className=\"field-control\"\n style={{ paddingInlineStart: `calc(var(--money-pad) + ${symbol.length}ch + var(--space-2))` }}\n type=\"text\"\n inputMode={\n (places === undefined ? field.step !== undefined && Number.isInteger(field.step) : places === 0) ? 'numeric' : 'decimal'\n }\n enterKeyHint=\"next\"\n autoComplete=\"off\"\n disabled={disabled}\n required={field.required}\n value={typing ? String(value ?? '') : places === undefined ? amountShown(value) : minorShown(value, places)}\n onFocus={() => setTyping(true)}\n onBlur={() => setTyping(false)}\n onChange={(event) =>\n onChange(places === undefined ? event.target.value.replace(/[^\\d.-]/g, '') : minorTyped(event.target.value, places))\n }\n />\n </div>\n );\n }\n if (field.type === 'month') {\n return (\n <input\n {...aria}\n id={id}\n className=\"field-control intake-month\"\n type=\"text\"\n inputMode=\"numeric\"\n enterKeyHint=\"next\"\n autoComplete=\"off\"\n placeholder={say('monthPlaceholder')}\n disabled={disabled}\n required={field.required}\n value={monthShown(typeof value === 'string' ? value : '')}\n onChange={(event) => onChange(monthValue(event.target.value))}\n />\n );\n }\n if ((field.type === 'number' || field.type === 'money') && field.as === 'slider') {\n const min = field.min ?? 0;\n const max = field.max ?? 100;\n const at = typeof value === 'number' ? value : value === undefined || value === '' ? min : Number(value);\n const share = max > min ? ((at - min) / (max - min)) * 100 : 0;\n // An amount reads as one, in the App's currency ($500); a number as the locale writes it.\n const saying = (n: number) => (field.type === 'money' ? amountIn(n, props.currency, field.step) : n.toLocaleString(formatLocale()));\n const said = saying(at);\n return (\n <div className=\"intake-slider\">\n <output className=\"field-control field-readout\" htmlFor={id} aria-hidden=\"true\">\n {said}\n </output>\n <input\n {...aria}\n id={id}\n type=\"range\"\n className=\"field-range\"\n min={min}\n max={max}\n step={field.step ?? (field.type === 'money' ? 1 : field.integer ? 1 : 'any')}\n value={at}\n disabled={disabled}\n aria-valuetext={said}\n style={{ '--range-share': `${share}%` } as CSSProperties}\n onChange={(event) => onChange(Number(event.target.value))}\n />\n {/* The two ends, read off the track; the range's own min and max say them to a screen reader. */}\n <div className=\"intake-slider-ends\" aria-hidden=\"true\">\n <span>{saying(min)}</span>\n <span>{saying(max)}</span>\n </div>\n </div>\n );\n }\n if (field.type === 'text' && field.sensitive) {\n const raw = typeof value === 'string' ? value : '';\n const drawn = field.mask ? maskShown(field.mask, raw) : raw;\n return (\n <div className=\"field-with-action\">\n <input\n {...aria}\n id={id}\n className={`field-control${shown ? '' : ' field-hidden'}`}\n type={shown ? 'text' : 'password'}\n inputMode={field.mask ? maskKeys(field.mask) : 'text'}\n enterKeyHint=\"next\"\n autoComplete=\"off\"\n autoCorrect=\"off\"\n autoCapitalize=\"off\"\n spellCheck={false}\n data-1p-ignore\n data-lpignore=\"true\"\n disabled={disabled}\n required={field.required}\n value={drawn}\n onChange={(event) => onChange(field.mask ? maskRaw(field.mask, event.target.value) : event.target.value)}\n />\n <button type=\"button\" className=\"btn btn-quiet\" aria-controls={id} aria-pressed={shown} onClick={() => setShown(!shown)}>\n {shown ? say('hideValue') : say('showValue')}\n </button>\n </div>\n );\n }\n if (field.type === 'text' && field.mask) {\n const mask = field.mask;\n return (\n <input\n {...aria}\n id={id}\n className=\"field-control\"\n type=\"text\"\n inputMode={maskKeys(mask)}\n enterKeyHint=\"next\"\n autoComplete=\"off\"\n placeholder={mask.replace(/[0a*]/g, '_')}\n disabled={disabled}\n required={field.required}\n value={maskShown(mask, typeof value === 'string' ? value : '')}\n onChange={(event) => onChange(maskRaw(mask, event.target.value))}\n />\n );\n }\n if (field.type === 'boolean') {\n if (field.as === 'buttons') {\n return (\n <div className=\"choice-pair\" role=\"radiogroup\" id={id} aria-labelledby={`${id}-label`} {...aria}>\n {([true, false] as const).map((answer) => (\n <label key={String(answer)} className={`choice-pick${value === answer ? ' is-on' : ''}`}>\n <input\n type=\"radio\"\n name={id}\n className=\"choice-input\"\n checked={value === answer}\n disabled={disabled}\n onChange={() => onChange(answer)}\n />\n {answer ? say('yesWord') : say('noWord')}\n </label>\n ))}\n </div>\n );\n }\n // A consent: the statement is the box's own words, so the box is named by them.\n return (\n <span className=\"intake-consent\">\n <input\n {...aria}\n id={id}\n type=\"checkbox\"\n className=\"command-check field-check\"\n required={field.accept === true}\n checked={value === true}\n disabled={disabled}\n onChange={(event) => onChange(event.target.checked)}\n />\n <span className=\"intake-statement\">{field.statement}</span>\n </span>\n );\n }\n if ((field.type === 'choice' || field.type === 'choices') && field.source) return <SourcedControl {...props} />;\n if (field.type === 'choice' || field.type === 'choices') {\n const several = field.type === 'choices';\n const chosen: readonly unknown[] = several ? (Array.isArray(value) ? value : []) : value === undefined ? [] : [value];\n const exclusive = field.type === 'choices' ? (field.exclusive ?? []) : [];\n const toggle = (option: Choice, on: boolean) => {\n if (!several) return onChange(option.value);\n if (exclusive.includes(option.value)) return onChange(on ? [option.value] : []);\n const rest = chosen.filter((v) => v !== option.value && !exclusive.includes(v as string | number));\n onChange(field.options.map((o) => o.value).filter((v) => (on && v === option.value) || rest.includes(v)) as CommandValue);\n };\n const buttons = field.as === 'buttons';\n /* Several cards are one group to the keyboard, as one choice's radios are (CheckCards): one Tab stop, the arrows\n between them, Space to turn one on or off, each saying aria-checked. */\n if (several)\n return (\n <CheckCards\n id={id}\n aria-labelledby={`${id}-label`}\n aria-describedby={props['aria-describedby']}\n aria-invalid={props['aria-invalid']}\n disabled={disabled}\n fit={cardFit(field.options)}\n cards={field.options.map((option) => ({\n key: optionKey(option),\n label: option.label,\n icon: option.icon && isAppIcon(option.icon) ? <Icon name={option.icon} /> : undefined,\n help: option.help,\n on: chosen.includes(option.value),\n }))}\n onToggle={(index, on) => toggle(field.options[index], on)}\n />\n );\n return (\n <div\n className={buttons ? 'choice-pair intake-buttons' : 'choice-cards'}\n data-fit={buttons ? undefined : cardFit(field.options)}\n role={several ? 'group' : 'radiogroup'}\n id={id}\n aria-labelledby={`${id}-label`}\n aria-required={(!several && field.required) || undefined}\n {...aria}\n >\n {field.options.map((option) => {\n const on = chosen.includes(option.value);\n return (\n <label key={optionKey(option)} className={`${buttons ? 'choice-pick' : 'choice-card'}${on ? ' is-on' : ''}`}>\n {option.icon && !buttons && isAppIcon(option.icon) ? (\n <span className=\"choice-card-icon\" aria-hidden=\"true\">\n <Icon name={option.icon} />\n </span>\n ) : null}\n <span className=\"choice-card-label\">\n {option.label}\n {option.help && !buttons ? <span className=\"intake-choice-help\">{option.help}</span> : null}\n </span>\n <input\n type={several ? 'checkbox' : 'radio'}\n name={several ? undefined : id}\n className=\"choice-input\"\n checked={on}\n disabled={disabled}\n onChange={(event) => toggle(option, event.target.checked)}\n />\n {buttons ? null : <span className=\"choice-box\" aria-hidden=\"true\" />}\n </label>\n );\n })}\n </div>\n );\n }\n return null;\n}\n"],"mappings":"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"}
@@ -1,8 +1,8 @@
1
1
  import { ht as Icon, w as captureSessionIdentity } from "./shared-poc11xxo.js";
2
2
  import { $ as richTextAttribute, C as identifierLike, X as RICH_TEXT_DROPPED, Z as RICH_TEXT_ELEMENTS, ft as vocabularyWord, gt as defineMessages, kt as portalRoot, m as initialsOf, p as hueOf, tt as richTextImage, y as sayValue } from "./shared-DJZjSi3J.js";
3
- import { L as state, i as api, st as ownedBy } from "./shared-DPAVoWY0.js";
3
+ import { L as state, i as api, st as ownedBy } from "./shared-BoLbc2WD.js";
4
4
  import { a as served } from "./shared-sZ8B7ZTw.js";
5
- import { t as onDemand } from "./shared-DpLeIATZ.js";
5
+ import { t as onDemand } from "./shared-B-BUF9fx.js";
6
6
  import { createElement, memo, useEffect, useMemo, useState } from "react";
7
7
  import { jsx, jsxs } from "react/jsx-runtime";
8
8
  // packages/kit/src/client/copy/record/components/Dressed.ts
@@ -548,4 +548,4 @@ function Said({ col, value, compact = false, app }) {
548
548
  }
549
549
  export { JsonValue as a, Said as i, Dressed as n, filesOnLease as o, LeadMark as r, saveFileOnLease as s, AvatarText as t };
550
550
 
551
- //# sourceMappingURL=shared-Q5WefT7G.js.map
551
+ //# sourceMappingURL=shared-CMjK-Ucd.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"shared-Q5WefT7G.js","names":["say","say","say","say"],"sources":["../../../kit/src/client/copy/record/components/Dressed.ts","../../../kit/src/client/copy/record/fileSource.ts","../../../kit/src/client/fileSource.ts","../../../kit/src/client/copy/record/components/RichText.ts","../../../kit/src/client/components/RichText.tsx","../../../kit/src/client/components/JsonValue.tsx","../../../kit/src/client/components/Dressed.tsx"],"sourcesContent":["/** What Dressed says, in the record page room (packages/kit/src/client/messages.ts says how the catalog is split). */\nimport { defineMessages } from '../../../messages.js';\n\nexport const say = defineMessages({\n showAllCharacters: 'Show all {textCount} characters',\n yes: '✓ yes',\n no: '✗ no',\n});\n","/** What fileSource says, in the record page room (packages/kit/src/client/messages.ts says how the catalog is split). */\nimport { defineMessages } from '../../messages.js';\n\nexport const say = defineMessages({\n unreadable: 'The file could not be read.',\n});\n","/**\n * Where a file of a file resource is drawn from, and how it is saved.\n *\n * In an App on its own server a file is an address — the file route, under\n * the reader's grants (`/api/file?table=…&key=…`) — so a picture is an\n * `<img src>` and a download is a link. A tenant App has no such address: its\n * every read is a request on the tab's lease, which names the tenant and is\n * answered only for it (tenantTransport.ts). There a file is read on the\n * lease as base64 (`/api/file/read`), made a blob here, and drawn or saved\n * from the blob's own address, which no other page and no other tenant can\n * open. A picture read once is kept for the page's life, a few hundred at\n * most, so a list that scrolls back does not read it again.\n */\nimport { useEffect, useState } from 'react';\nimport { api } from './core.js';\nimport { served } from './addressMount.js';\nimport { ownedBy } from './requestIdentity.js';\nimport { captureSessionIdentity } from './sessionIdentity.js';\nimport { say } from './copy/record/fileSource.js';\nimport { portalRoot } from './shellHost.js';\n\n/** Whether files here travel on a tenant lease rather than by address. */\nexport const filesOnLease = (): boolean => captureSessionIdentity().tenantRequired === true;\n\n/** One file's address in the file route, for an App on its own server. */\nfunction fileAddress(\n table: string,\n key: Record<string, unknown>,\n connection: string | null | undefined,\n options: { inline?: boolean; variant?: 'thumb' } = {},\n): string {\n return served(\n `/api/file?${new URLSearchParams({\n ...ownedBy(connection ?? null),\n table,\n key: JSON.stringify(key),\n ...(options.inline ? { inline: '1' } : {}),\n ...(options.variant ? { variant: options.variant } : {}),\n })}`,\n );\n}\n\nfunction bytesOf(base64: string): Uint8Array<ArrayBuffer> {\n const text = atob(base64);\n const bytes = new Uint8Array(text.length);\n for (let i = 0; i < text.length; i++) bytes[i] = text.charCodeAt(i);\n return bytes;\n}\n\n/** One file read on the lease, as a blob: a picture typed as its bytes say when asked for in place, anything else a download. */\nasync function fileOnLease(\n table: string,\n key: Record<string, unknown>,\n options: { inline?: boolean; variant?: 'thumb' } = {},\n): Promise<{ blob: Blob; name: string }> {\n const reply = (await api('/api/file/read', {\n table,\n key,\n ...(options.inline ? { inline: true } : {}),\n ...(options.variant ? { variant: options.variant } : {}),\n })) as { name?: unknown; type?: unknown; data?: unknown; error?: unknown };\n if (typeof reply.error === 'string') throw new Error(reply.error);\n if (typeof reply.data !== 'string' || typeof reply.name !== 'string') throw new Error(say('unreadable'));\n const type =\n typeof reply.type === 'string' && /^image\\/(png|jpeg|gif|webp|avif|bmp)$/.test(reply.type) ? reply.type : 'application/octet-stream';\n return { blob: new Blob([bytesOf(reply.data)], { type }), name: reply.name };\n}\n\n/* Pictures read on the lease, by what they were read as; the oldest is let go past the most kept. */\nconst KEPT = 300;\nconst pictures = new Map<string, Promise<string>>();\n/* The lease a picture was read on: another account or tenant reads its own. */\nlet keptFor: unknown;\n\nfunction pictureOnLease(table: string, key: Record<string, unknown>, variant?: 'thumb'): Promise<string> {\n const identity = captureSessionIdentity();\n if (keptFor !== identity) {\n for (const kept of pictures.values()) void kept.then(URL.revokeObjectURL, () => {});\n pictures.clear();\n keptFor = identity;\n }\n const name = JSON.stringify([table, key, variant ?? '']);\n const kept = pictures.get(name);\n if (kept) return kept;\n const read = fileOnLease(table, key, { inline: true, ...(variant ? { variant } : {}) }).then(({ blob }) => URL.createObjectURL(blob));\n read.catch(() => pictures.delete(name));\n pictures.set(name, read);\n if (pictures.size > KEPT) {\n const [oldest, gone] = pictures.entries().next().value!;\n pictures.delete(oldest);\n void gone.then(URL.revokeObjectURL, () => {});\n }\n return read;\n}\n\n/**\n * A picture's address, to draw in place: the file route's inline mode, or on\n * a lease the blob it was read into — undefined until it has been, and when\n * it could not be (the picture then draws as its words).\n */\nexport function usePictureAddress(\n table: string | undefined,\n key: Record<string, unknown> | undefined,\n connection: string | null | undefined,\n variant?: 'thumb',\n): string | undefined {\n const lease = filesOnLease();\n const direct =\n table && key && !lease ? fileAddress(table, key, connection, { inline: true, ...(variant ? { variant } : {}) }) : undefined;\n const [drawn, setDrawn] = useState<{ name: string; src: string }>();\n const name = table && key ? JSON.stringify([table, key, variant ?? '']) : '';\n useEffect(() => {\n if (!lease || !table || !key) return;\n let current = true;\n pictureOnLease(table, key, variant).then(\n (src) => current && setDrawn({ name, src }),\n () => current && setDrawn(undefined),\n );\n return () => {\n current = false;\n };\n }, [lease, name]);\n return direct ?? (drawn?.name === name ? drawn.src : undefined);\n}\n\n/** Save one file as the reader's own: on a lease, read and handed to the browser as a download. */\nexport async function saveFileOnLease(table: string, key: Record<string, unknown>): Promise<void> {\n const { blob, name } = await fileOnLease(table, key);\n const href = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = href;\n link.download = name;\n link.rel = 'noopener';\n portalRoot().append(link);\n link.click();\n link.remove();\n setTimeout(() => URL.revokeObjectURL(href), 60_000);\n}\n","/** What RichText says, in the record page room (packages/kit/src/client/messages.ts says how the catalog is split). */\nimport { defineMessages } from '../../../messages.js';\n\nexport const say = defineMessages({\n done: 'Done',\n notDone: 'Not done',\n});\n","/**\n * A rich text value, drawn: the stored HTML read by the browser's own parser\n * into an inert document, then walked into React elements through the one\n * allowlist (shared/richText.ts). Never `dangerouslySetInnerHTML`, and never\n * on trust that the server cleaned it: the server sanitizes every write it\n * makes, but a column may hold what SQL, another program or an older App put\n * there, and that is drawn through the same list. An element outside it is\n * its words; an attribute outside it is not drawn; a link opens beside the\n * App and tells the page nothing; a picture is one of the App's attachments,\n * read under the reader's grants, or its description.\n */\nimport { createElement, memo, useMemo, type ReactNode } from 'react';\nimport { RICH_TEXT_DROPPED, RICH_TEXT_ELEMENTS, richTextAttribute, richTextImage } from '@mistriwork/engine/shared/richText.js';\nimport { usePictureAddress } from '../fileSource.js';\nimport { state } from '../core.js';\nimport { say } from '../copy/record/components/RichText.js';\n\n/* React's names for the attributes the list keeps. */\nconst PROPS: Readonly<Record<string, string>> = { colspan: 'colSpan', rowspan: 'rowSpan', class: 'className' };\nconst DROPPED = new Set(RICH_TEXT_DROPPED);\n\nfunction Picture({ src, alt, connection }: { src: string; alt: string; connection?: string | null }) {\n const named = richTextImage(src);\n const address = usePictureAddress(named?.table, named?.key, connection === undefined ? state.activeConnection : connection);\n if (!address) return alt ? <span className=\"rich-text-missing\">{alt}</span> : null;\n return <img src={address} alt={alt} loading=\"lazy\" decoding=\"async\" />;\n}\n\nfunction children(node: Node, connection: string | null | undefined, path: string): ReactNode[] {\n return [...node.childNodes].map((child, index) => drawn(child, connection, `${path}.${index}`));\n}\n\nfunction drawn(node: Node, connection: string | null | undefined, key: string): ReactNode {\n if (node.nodeType === 3) return node.textContent;\n if (node.nodeType !== 1) return null;\n const element = node as Element;\n const tag = element.localName;\n if (DROPPED.has(tag)) return null;\n const allowed = Object.hasOwn(RICH_TEXT_ELEMENTS, tag) ? RICH_TEXT_ELEMENTS[tag] : undefined;\n /* An element the list does not hold is its words, as the server's sanitizer leaves it. */\n if (!allowed) return createElement('span', { key }, ...children(element, connection, key));\n const props: Record<string, unknown> = { key };\n for (const name of allowed) {\n const raw = element.getAttribute(name);\n if (raw === null) continue;\n const value = richTextAttribute(tag, name, raw);\n if (value !== undefined) props[PROPS[name] ?? name] = value;\n }\n if (tag === 'img') {\n if (typeof props.src !== 'string') return typeof props.alt === 'string' && props.alt ? <span key={key}>{props.alt}</span> : null;\n return <Picture key={key} src={props.src} alt={typeof props.alt === 'string' ? props.alt : ''} connection={connection} />;\n }\n if (tag === 'a') {\n if (typeof props.href !== 'string') return createElement('span', { key }, ...children(element, connection, key));\n Object.assign(props, { target: '_blank', rel: 'noopener noreferrer' });\n }\n if (tag === 'span' && props['data-type'] !== 'mention') return createElement('span', { key }, ...children(element, connection, key));\n if (tag === 'span') props.className = 'rich-text-mention';\n /* A task's box says whether it is done; it is not a control here, the editor is. */\n if (tag === 'li' && props['data-type'] === 'taskItem') {\n const done = props['data-checked'] === 'true';\n return createElement(\n 'li',\n props,\n <input type=\"checkbox\" checked={done} disabled readOnly aria-label={say(done ? 'done' : 'notDone')} />,\n <div>{children(element, connection, key)}</div>,\n );\n }\n if (tag === 'br') return createElement('br', props);\n return createElement(tag, props, ...children(element, connection, key));\n}\n\n/** The stored value, read into an inert document and drawn through the allowlist. */\nexport const RichText = memo(function RichText({\n html,\n connection,\n className,\n}: {\n html: string;\n /** The connection (an App) the value's pictures are read from. */\n connection?: string | null;\n className?: string;\n}) {\n const body = useMemo(() => (html ? new DOMParser().parseFromString(html, 'text/html').body : undefined), [html]);\n if (!body) return null;\n return <div className={`rich-text${className ? ` ${className}` : ''}`}>{children(body, connection, 'r')}</div>;\n});\n","/* Compact cells keep their text preview. Fetch the tree only for a full value. */\nimport { onDemand } from './onDemand.js';\n\nexport const JsonValue = onDemand(() => import('./JsonView.js'), 'JsonView');\n","/**\n * A value drawn from what is said about it, and nothing else: a display\n * rule's dress (`Dressed`), or the grid planner's reading of a plain value\n * (`Said`). Every input is a prop — the column, the value, whether an App is\n * drawing — so this reads no global of the walk's.\n *\n * That is what lets one set of rules draw a value everywhere: `Value` (the\n * record and the page, which find the rule and the column in the App's\n * payload), and the public kit's `Value` (components/sdk), which a custom\n * component draws in the page and in its own tests, where there is no walk.\n */\nimport { memo, useState } from 'react';\nimport type { ColumnMeta } from '@mistriwork/engine/shared/schema.js';\nimport { Icon, type IconName } from './Icon.js';\nimport { vocabularyWord } from '@mistriwork/engine/shared/model.js';\nimport { hueOf, initialsOf, sayValue, type Dress } from './valueModel.js';\nimport { identifierLike } from '../columns.js';\nimport { say } from '../copy/record/components/Dressed.js';\nimport { RichText } from './RichText.js';\nimport { JsonValue } from './JsonValue.js';\nimport { onDemand } from './onDemand.js';\n\n/* The QR encoder is a library of its own: fetched by the first value that is drawn as a code. */\nconst QrPart = onDemand(() => import('./QrCode.js'), 'QrCode', { quiet: true });\n\n/* A ring's circumference at r = 6: the dash that fills it to a percent. */\nconst RING = 2 * Math.PI * 6;\n\n/** A name with its initials disc, or the person's photo where one is found (avatarPhotos.tsx); the disc is\n decoration, the name is the text. A photo that will not load gives way to the initials. */\nexport const AvatarText = memo(function AvatarText({ text, photo }: { text: string; photo?: string }) {\n const [failed, setFailed] = useState<string | undefined>();\n const drawn = photo && photo !== failed ? photo : undefined;\n return (\n <span className=\"avatar-value\">\n {drawn ? (\n <img\n className={`avatar avatar-photo avatar-c${hueOf(text)}`}\n src={drawn}\n alt=\"\"\n loading=\"lazy\"\n decoding=\"async\"\n onError={() => setFailed(drawn)}\n />\n ) : (\n <span className={`avatar avatar-c${hueOf(text)}`} aria-hidden=\"true\">\n {initialsOf(text)}\n </span>\n )}\n <span className=\"avatar-text\">{text}</span>\n </span>\n );\n});\n\n/** A lead icon: the mark in a small square tinted by the row's tone, the accent's where the row says none. Decoration\n beside the value, which stays the text. */\nexport const LeadMark = memo(function LeadMark({ mark, tone }: { mark: string; tone?: string }) {\n return (\n <span className={`lead-icon${tone ? ` tone-${tone}` : ''}`} aria-hidden=\"true\">\n <Icon name={mark as IconName} size={14} />\n </span>\n );\n});\n\n/* A dress is made fresh for every value it dresses (valueModel.ts), so it is\n compared by what it says: a redraw that dressed the same value the same\n way draws nothing. */\nconst sameDress = (a: { dress: Dress; compact?: boolean }, b: { dress: Dress; compact?: boolean }) =>\n a.compact === b.compact &&\n Object.keys(a.dress).length === Object.keys(b.dress).length &&\n (Object.keys(a.dress) as Array<keyof Dress>).every((key) => {\n const x = a.dress[key],\n y = b.dress[key];\n return x === y || (Array.isArray(x) && Array.isArray(y) && x.length === y.length && x.every((item, i) => item === y[i]));\n });\n\nexport const Dressed = memo(function Dressed({ dress, compact = false }: { dress: Dress; compact?: boolean }) {\n switch (dress.kind) {\n /* One item per line: a list where there is room to read it, the items\n joined in one line where there is not (a cell, a card). */\n /* Formatted text where there is room for it; its words in one line where there is not. */\n case 'richText':\n return compact ? <span className=\"rich-text-excerpt\">{dress.text}</span> : <RichText html={dress.html} />;\n case 'items':\n return compact ? (\n <span title={dress.items.join('\\n')}>{dress.text}</span>\n ) : (\n <ul className=\"value-items\">\n {dress.items.map((item, index) => (\n <li key={index}>{item}</li>\n ))}\n </ul>\n );\n /* A mark stands where the tone's dot would, in its colour; the word stays the value, for every reader. */\n case 'tone':\n return dress.icon ? (\n <span className={`tone tone-${dress.tone} tone-marked`} title={dress.label === dress.text ? undefined : dress.text}>\n <Icon name={dress.icon as IconName} size={14} className=\"value-mark-icon\" />\n {dress.label}\n </span>\n ) : (\n <span\n className={`tone tone-${dress.tone}${dress.figure ? ' tone-figure' : ''}`}\n title={dress.label === dress.text ? undefined : dress.text}\n >\n {dress.label}\n </span>\n );\n case 'mark':\n return (\n <span className=\"value-mark\" title={dress.label === dress.text ? undefined : dress.text}>\n <Icon name={dress.icon as IconName} size={14} className=\"value-mark-icon\" />\n {dress.label}\n </span>\n );\n case 'word':\n return <span title={dress.label === dress.text ? undefined : dress.text}>{dress.label}</span>;\n case 'money':\n return (\n <span className=\"num-value\" title={dress.title}>\n {dress.text}\n </span>\n );\n case 'number':\n return (\n <span className=\"num-value\" title={dress.title}>\n {dress.text}\n </span>\n );\n case 'date':\n return (\n <span className=\"date-value\" title={dress.title}>\n {dress.text}\n </span>\n );\n case 'relative':\n return (\n <span className={`date-value relative${dress.overdue ? ' overdue' : ''}`} title={dress.title}>\n {dress.text}\n </span>\n );\n case 'avatar':\n return <AvatarText text={dress.text} photo={dress.photo} />;\n /* The names are the text, for every reader; the discs and the count are what a glance takes in. */\n case 'avatars':\n return (\n <span className=\"avatar-stack\" title={dress.text} role=\"img\" aria-label={dress.text}>\n {dress.names.map((name, index) => (\n <span key={index} className={`avatar avatar-c${hueOf(name)}`} aria-hidden=\"true\">\n {initialsOf(name)}\n </span>\n ))}\n {dress.more ? (\n <span className=\"avatar avatar-more\" aria-hidden=\"true\">\n +{dress.more}\n </span>\n ) : null}\n </span>\n );\n /* No title and no reveal: the placeholder is all that is drawn. */\n case 'masked':\n return <span className=\"value-masked\">{dress.text}</span>;\n case 'meter':\n return (\n <span className={`meter-wrap${dress.tone ? ` meter-${dress.tone}` : ''}`} title={dress.title}>\n <span className=\"pct-bar\">\n <span className=\"pct-fill\" style={{ width: `${dress.fill}%` }} />\n </span>\n <span className=\"num-value\">{dress.text}</span>\n </span>\n );\n /* Stars as one picture, said as words: \"4 of 5 stars\". A tone colors the filled ones. */\n case 'rating':\n return (\n <span className={`rating-value${dress.tone ? ` rating-${dress.tone}` : ''}`} role=\"img\" aria-label={dress.text} title={dress.text}>\n {Array.from({ length: dress.outOf }, (_, index) => (\n <span key={index} className={index < dress.value ? 'rating-star is-on' : 'rating-star'} aria-hidden=\"true\">\n ★\n </span>\n ))}\n </span>\n );\n case 'color':\n return (\n <span className=\"color-value\">\n <span className=\"color-swatch\" style={{ background: dress.hex }} aria-hidden=\"true\" />\n <span className=\"num-value\">{dress.text}</span>\n </span>\n );\n case 'json':\n return compact ? <span className=\"json-preview-text\">{dress.excerpt}</span> : <JsonValue value={JSON.parse(dress.text) as object} />;\n /* In a list the value is its text; a record draws the code to scan, the text under it. */\n case 'qr':\n return compact ? <span className=\"num-value\">{dress.text}</span> : <QrPart text={dress.text} />;\n /* In a list a signature is the word; a record draws the picture, ink on the card's own ground. */\n case 'signature':\n return compact ? (\n <span>{dress.text}</span>\n ) : (\n <img\n className=\"signature-value\"\n src={dress.src}\n alt={dress.text}\n loading=\"lazy\"\n // Ink kept on paper in every look, as a QR code's ground is; inline, so no first sheet carries it.\n style={{ display: 'block', maxWidth: 240, maxHeight: 96, padding: 4, background: '#fff', borderRadius: 'var(--radius)' }}\n />\n );\n case 'percent':\n if (dress.ring !== undefined)\n return (\n <span className=\"pct-ring-wrap\" title={dress.text}>\n <svg className=\"pct-ring\" viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <circle className=\"pct-ring-track\" cx=\"8\" cy=\"8\" r=\"6\" />\n <circle\n className=\"pct-ring-fill\"\n cx=\"8\"\n cy=\"8\"\n r=\"6\"\n strokeDasharray={`${(dress.ring / 100) * RING} ${RING}`}\n transform=\"rotate(-90 8 8)\"\n />\n </svg>\n <span className=\"num-value\">{dress.text}</span>\n </span>\n );\n if (dress.bar === undefined) return <span className=\"num-value\">{dress.text}</span>;\n return (\n <span className=\"pct-wrap\" title={dress.text}>\n <span className=\"pct-bar\">\n <span className=\"pct-fill\" style={{ width: `${dress.bar}%` }} />\n </span>\n <span className=\"num-value\">{dress.text}</span>\n </span>\n );\n }\n}, sameDress);\n\n/** A long unbroken token, said by its start and its length; the whole of it on request, wrapping anywhere. */\nfunction Opaque({ text, head, compact }: { text: string; head: string; compact: boolean }) {\n const [open, setOpen] = useState(false);\n if (compact) return <span className=\"value-opaque\">{head}…</span>;\n if (open) return <div className=\"value-opaque value-opaque-open\">{text}</div>;\n return (\n <span className=\"value-opaque\">\n {head}…{' '}\n <button type=\"button\" className=\"value-opaque-more\" onClick={() => setOpen(true)}>\n {say('showAllCharacters', { textCount: text.length.toLocaleString() })}\n </button>\n </span>\n );\n}\n\n/**\n * A value no rule dresses, as the grid's planner reads it on a row of one: a\n * flag, a figure (every digit of one past 2^53 kept — it arrives as a string\n * and is never run through Number()), a date in the reader's words, prose, a\n * token. In an App a value of the column's own vocabulary is a word, as its\n * chip says it; the Workbench shows the data exactly.\n */\nexport function Said({\n col,\n value,\n compact = false,\n app,\n}: {\n col: ColumnMeta | undefined;\n value: unknown;\n compact?: boolean;\n app: boolean;\n}) {\n const said = sayValue(col, value);\n switch (said.kind) {\n case 'boolean':\n return (\n <span className={`bool-value ${said.on ? 'yes' : 'no'}`} title={said.title}>\n {said.on ? say('yes') : say('no')}\n </span>\n );\n case 'number':\n return (\n <span className=\"num-value\" title={said.title}>\n {said.text}\n </span>\n );\n case 'date':\n return (\n <span className=\"date-value\" title={said.title}>\n {said.text}\n </span>\n );\n case 'long':\n return compact ? <span title={said.text}>{said.text}</span> : <div className=\"long-value prose\">{said.text}</div>;\n case 'opaque':\n return <Opaque text={said.text} head={said.head} compact={compact} />;\n default: {\n const word = app && col?.allowed?.includes(said.text) ? vocabularyWord(said.text) : said.text;\n return (\n /* A key, a code or a serial is a figure to the data face's reach (themeFamilies.css): `id-value` says so. */\n <span\n className={said.prose || (app && !identifierLike(col, col?.name ?? '')) ? 'prose' : app ? 'id-value' : undefined}\n title={said.text}\n >\n {word}\n </span>\n );\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"shared-CMjK-Ucd.js","names":["say","say","say","say"],"sources":["../../../kit/src/client/copy/record/components/Dressed.ts","../../../kit/src/client/copy/record/fileSource.ts","../../../kit/src/client/fileSource.ts","../../../kit/src/client/copy/record/components/RichText.ts","../../../kit/src/client/components/RichText.tsx","../../../kit/src/client/components/JsonValue.tsx","../../../kit/src/client/components/Dressed.tsx"],"sourcesContent":["/** What Dressed says, in the record page room (packages/kit/src/client/messages.ts says how the catalog is split). */\nimport { defineMessages } from '../../../messages.js';\n\nexport const say = defineMessages({\n showAllCharacters: 'Show all {textCount} characters',\n yes: '✓ yes',\n no: '✗ no',\n});\n","/** What fileSource says, in the record page room (packages/kit/src/client/messages.ts says how the catalog is split). */\nimport { defineMessages } from '../../messages.js';\n\nexport const say = defineMessages({\n unreadable: 'The file could not be read.',\n});\n","/**\n * Where a file of a file resource is drawn from, and how it is saved.\n *\n * In an App on its own server a file is an address — the file route, under\n * the reader's grants (`/api/file?table=…&key=…`) — so a picture is an\n * `<img src>` and a download is a link. A tenant App has no such address: its\n * every read is a request on the tab's lease, which names the tenant and is\n * answered only for it (tenantTransport.ts). There a file is read on the\n * lease as base64 (`/api/file/read`), made a blob here, and drawn or saved\n * from the blob's own address, which no other page and no other tenant can\n * open. A picture read once is kept for the page's life, a few hundred at\n * most, so a list that scrolls back does not read it again.\n */\nimport { useEffect, useState } from 'react';\nimport { api } from './core.js';\nimport { served } from './addressMount.js';\nimport { ownedBy } from './requestIdentity.js';\nimport { captureSessionIdentity } from './sessionIdentity.js';\nimport { say } from './copy/record/fileSource.js';\nimport { portalRoot } from './shellHost.js';\n\n/** Whether files here travel on a tenant lease rather than by address. */\nexport const filesOnLease = (): boolean => captureSessionIdentity().tenantRequired === true;\n\n/** One file's address in the file route, for an App on its own server. */\nfunction fileAddress(\n table: string,\n key: Record<string, unknown>,\n connection: string | null | undefined,\n options: { inline?: boolean; variant?: 'thumb' } = {},\n): string {\n return served(\n `/api/file?${new URLSearchParams({\n ...ownedBy(connection ?? null),\n table,\n key: JSON.stringify(key),\n ...(options.inline ? { inline: '1' } : {}),\n ...(options.variant ? { variant: options.variant } : {}),\n })}`,\n );\n}\n\nfunction bytesOf(base64: string): Uint8Array<ArrayBuffer> {\n const text = atob(base64);\n const bytes = new Uint8Array(text.length);\n for (let i = 0; i < text.length; i++) bytes[i] = text.charCodeAt(i);\n return bytes;\n}\n\n/** One file read on the lease, as a blob: a picture typed as its bytes say when asked for in place, anything else a download. */\nasync function fileOnLease(\n table: string,\n key: Record<string, unknown>,\n options: { inline?: boolean; variant?: 'thumb' } = {},\n): Promise<{ blob: Blob; name: string }> {\n const reply = (await api('/api/file/read', {\n table,\n key,\n ...(options.inline ? { inline: true } : {}),\n ...(options.variant ? { variant: options.variant } : {}),\n })) as { name?: unknown; type?: unknown; data?: unknown; error?: unknown };\n if (typeof reply.error === 'string') throw new Error(reply.error);\n if (typeof reply.data !== 'string' || typeof reply.name !== 'string') throw new Error(say('unreadable'));\n const type =\n typeof reply.type === 'string' && /^image\\/(png|jpeg|gif|webp|avif|bmp)$/.test(reply.type) ? reply.type : 'application/octet-stream';\n return { blob: new Blob([bytesOf(reply.data)], { type }), name: reply.name };\n}\n\n/* Pictures read on the lease, by what they were read as; the oldest is let go past the most kept. */\nconst KEPT = 300;\nconst pictures = new Map<string, Promise<string>>();\n/* The lease a picture was read on: another account or tenant reads its own. */\nlet keptFor: unknown;\n\nfunction pictureOnLease(table: string, key: Record<string, unknown>, variant?: 'thumb'): Promise<string> {\n const identity = captureSessionIdentity();\n if (keptFor !== identity) {\n for (const kept of pictures.values()) void kept.then(URL.revokeObjectURL, () => {});\n pictures.clear();\n keptFor = identity;\n }\n const name = JSON.stringify([table, key, variant ?? '']);\n const kept = pictures.get(name);\n if (kept) return kept;\n const read = fileOnLease(table, key, { inline: true, ...(variant ? { variant } : {}) }).then(({ blob }) => URL.createObjectURL(blob));\n read.catch(() => pictures.delete(name));\n pictures.set(name, read);\n if (pictures.size > KEPT) {\n const [oldest, gone] = pictures.entries().next().value!;\n pictures.delete(oldest);\n void gone.then(URL.revokeObjectURL, () => {});\n }\n return read;\n}\n\n/**\n * A picture's address, to draw in place: the file route's inline mode, or on\n * a lease the blob it was read into — undefined until it has been, and when\n * it could not be (the picture then draws as its words).\n */\nexport function usePictureAddress(\n table: string | undefined,\n key: Record<string, unknown> | undefined,\n connection: string | null | undefined,\n variant?: 'thumb',\n): string | undefined {\n const lease = filesOnLease();\n const direct =\n table && key && !lease ? fileAddress(table, key, connection, { inline: true, ...(variant ? { variant } : {}) }) : undefined;\n const [drawn, setDrawn] = useState<{ name: string; src: string }>();\n const name = table && key ? JSON.stringify([table, key, variant ?? '']) : '';\n useEffect(() => {\n if (!lease || !table || !key) return;\n let current = true;\n pictureOnLease(table, key, variant).then(\n (src) => current && setDrawn({ name, src }),\n () => current && setDrawn(undefined),\n );\n return () => {\n current = false;\n };\n }, [lease, name]);\n return direct ?? (drawn?.name === name ? drawn.src : undefined);\n}\n\n/** Save one file as the reader's own: on a lease, read and handed to the browser as a download. */\nexport async function saveFileOnLease(table: string, key: Record<string, unknown>): Promise<void> {\n const { blob, name } = await fileOnLease(table, key);\n const href = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = href;\n link.download = name;\n link.rel = 'noopener';\n portalRoot().append(link);\n link.click();\n link.remove();\n setTimeout(() => URL.revokeObjectURL(href), 60_000);\n}\n","/** What RichText says, in the record page room (packages/kit/src/client/messages.ts says how the catalog is split). */\nimport { defineMessages } from '../../../messages.js';\n\nexport const say = defineMessages({\n done: 'Done',\n notDone: 'Not done',\n});\n","/**\n * A rich text value, drawn: the stored HTML read by the browser's own parser\n * into an inert document, then walked into React elements through the one\n * allowlist (shared/richText.ts). Never `dangerouslySetInnerHTML`, and never\n * on trust that the server cleaned it: the server sanitizes every write it\n * makes, but a column may hold what SQL, another program or an older App put\n * there, and that is drawn through the same list. An element outside it is\n * its words; an attribute outside it is not drawn; a link opens beside the\n * App and tells the page nothing; a picture is one of the App's attachments,\n * read under the reader's grants, or its description.\n */\nimport { createElement, memo, useMemo, type ReactNode } from 'react';\nimport { RICH_TEXT_DROPPED, RICH_TEXT_ELEMENTS, richTextAttribute, richTextImage } from '@mistriwork/engine/shared/richText.js';\nimport { usePictureAddress } from '../fileSource.js';\nimport { state } from '../core.js';\nimport { say } from '../copy/record/components/RichText.js';\n\n/* React's names for the attributes the list keeps. */\nconst PROPS: Readonly<Record<string, string>> = { colspan: 'colSpan', rowspan: 'rowSpan', class: 'className' };\nconst DROPPED = new Set(RICH_TEXT_DROPPED);\n\nfunction Picture({ src, alt, connection }: { src: string; alt: string; connection?: string | null }) {\n const named = richTextImage(src);\n const address = usePictureAddress(named?.table, named?.key, connection === undefined ? state.activeConnection : connection);\n if (!address) return alt ? <span className=\"rich-text-missing\">{alt}</span> : null;\n return <img src={address} alt={alt} loading=\"lazy\" decoding=\"async\" />;\n}\n\nfunction children(node: Node, connection: string | null | undefined, path: string): ReactNode[] {\n return [...node.childNodes].map((child, index) => drawn(child, connection, `${path}.${index}`));\n}\n\nfunction drawn(node: Node, connection: string | null | undefined, key: string): ReactNode {\n if (node.nodeType === 3) return node.textContent;\n if (node.nodeType !== 1) return null;\n const element = node as Element;\n const tag = element.localName;\n if (DROPPED.has(tag)) return null;\n const allowed = Object.hasOwn(RICH_TEXT_ELEMENTS, tag) ? RICH_TEXT_ELEMENTS[tag] : undefined;\n /* An element the list does not hold is its words, as the server's sanitizer leaves it. */\n if (!allowed) return createElement('span', { key }, ...children(element, connection, key));\n const props: Record<string, unknown> = { key };\n for (const name of allowed) {\n const raw = element.getAttribute(name);\n if (raw === null) continue;\n const value = richTextAttribute(tag, name, raw);\n if (value !== undefined) props[PROPS[name] ?? name] = value;\n }\n if (tag === 'img') {\n if (typeof props.src !== 'string') return typeof props.alt === 'string' && props.alt ? <span key={key}>{props.alt}</span> : null;\n return <Picture key={key} src={props.src} alt={typeof props.alt === 'string' ? props.alt : ''} connection={connection} />;\n }\n if (tag === 'a') {\n if (typeof props.href !== 'string') return createElement('span', { key }, ...children(element, connection, key));\n Object.assign(props, { target: '_blank', rel: 'noopener noreferrer' });\n }\n if (tag === 'span' && props['data-type'] !== 'mention') return createElement('span', { key }, ...children(element, connection, key));\n if (tag === 'span') props.className = 'rich-text-mention';\n /* A task's box says whether it is done; it is not a control here, the editor is. */\n if (tag === 'li' && props['data-type'] === 'taskItem') {\n const done = props['data-checked'] === 'true';\n return createElement(\n 'li',\n props,\n <input type=\"checkbox\" checked={done} disabled readOnly aria-label={say(done ? 'done' : 'notDone')} />,\n <div>{children(element, connection, key)}</div>,\n );\n }\n if (tag === 'br') return createElement('br', props);\n return createElement(tag, props, ...children(element, connection, key));\n}\n\n/** The stored value, read into an inert document and drawn through the allowlist. */\nexport const RichText = memo(function RichText({\n html,\n connection,\n className,\n}: {\n html: string;\n /** The connection (an App) the value's pictures are read from. */\n connection?: string | null;\n className?: string;\n}) {\n const body = useMemo(() => (html ? new DOMParser().parseFromString(html, 'text/html').body : undefined), [html]);\n if (!body) return null;\n return <div className={`rich-text${className ? ` ${className}` : ''}`}>{children(body, connection, 'r')}</div>;\n});\n","/* Compact cells keep their text preview. Fetch the tree only for a full value. */\nimport { onDemand } from './onDemand.js';\n\nexport const JsonValue = onDemand(() => import('./JsonView.js'), 'JsonView');\n","/**\n * A value drawn from what is said about it, and nothing else: a display\n * rule's dress (`Dressed`), or the grid planner's reading of a plain value\n * (`Said`). Every input is a prop — the column, the value, whether an App is\n * drawing — so this reads no global of the walk's.\n *\n * That is what lets one set of rules draw a value everywhere: `Value` (the\n * record and the page, which find the rule and the column in the App's\n * payload), and the public kit's `Value` (components/sdk), which a custom\n * component draws in the page and in its own tests, where there is no walk.\n */\nimport { memo, useState } from 'react';\nimport type { ColumnMeta } from '@mistriwork/engine/shared/schema.js';\nimport { Icon, type IconName } from './Icon.js';\nimport { vocabularyWord } from '@mistriwork/engine/shared/model.js';\nimport { hueOf, initialsOf, sayValue, type Dress } from './valueModel.js';\nimport { identifierLike } from '../columns.js';\nimport { say } from '../copy/record/components/Dressed.js';\nimport { RichText } from './RichText.js';\nimport { JsonValue } from './JsonValue.js';\nimport { onDemand } from './onDemand.js';\n\n/* The QR encoder is a library of its own: fetched by the first value that is drawn as a code. */\nconst QrPart = onDemand(() => import('./QrCode.js'), 'QrCode', { quiet: true });\n\n/* A ring's circumference at r = 6: the dash that fills it to a percent. */\nconst RING = 2 * Math.PI * 6;\n\n/** A name with its initials disc, or the person's photo where one is found (avatarPhotos.tsx); the disc is\n decoration, the name is the text. A photo that will not load gives way to the initials. */\nexport const AvatarText = memo(function AvatarText({ text, photo }: { text: string; photo?: string }) {\n const [failed, setFailed] = useState<string | undefined>();\n const drawn = photo && photo !== failed ? photo : undefined;\n return (\n <span className=\"avatar-value\">\n {drawn ? (\n <img\n className={`avatar avatar-photo avatar-c${hueOf(text)}`}\n src={drawn}\n alt=\"\"\n loading=\"lazy\"\n decoding=\"async\"\n onError={() => setFailed(drawn)}\n />\n ) : (\n <span className={`avatar avatar-c${hueOf(text)}`} aria-hidden=\"true\">\n {initialsOf(text)}\n </span>\n )}\n <span className=\"avatar-text\">{text}</span>\n </span>\n );\n});\n\n/** A lead icon: the mark in a small square tinted by the row's tone, the accent's where the row says none. Decoration\n beside the value, which stays the text. */\nexport const LeadMark = memo(function LeadMark({ mark, tone }: { mark: string; tone?: string }) {\n return (\n <span className={`lead-icon${tone ? ` tone-${tone}` : ''}`} aria-hidden=\"true\">\n <Icon name={mark as IconName} size={14} />\n </span>\n );\n});\n\n/* A dress is made fresh for every value it dresses (valueModel.ts), so it is\n compared by what it says: a redraw that dressed the same value the same\n way draws nothing. */\nconst sameDress = (a: { dress: Dress; compact?: boolean }, b: { dress: Dress; compact?: boolean }) =>\n a.compact === b.compact &&\n Object.keys(a.dress).length === Object.keys(b.dress).length &&\n (Object.keys(a.dress) as Array<keyof Dress>).every((key) => {\n const x = a.dress[key],\n y = b.dress[key];\n return x === y || (Array.isArray(x) && Array.isArray(y) && x.length === y.length && x.every((item, i) => item === y[i]));\n });\n\nexport const Dressed = memo(function Dressed({ dress, compact = false }: { dress: Dress; compact?: boolean }) {\n switch (dress.kind) {\n /* One item per line: a list where there is room to read it, the items\n joined in one line where there is not (a cell, a card). */\n /* Formatted text where there is room for it; its words in one line where there is not. */\n case 'richText':\n return compact ? <span className=\"rich-text-excerpt\">{dress.text}</span> : <RichText html={dress.html} />;\n case 'items':\n return compact ? (\n <span title={dress.items.join('\\n')}>{dress.text}</span>\n ) : (\n <ul className=\"value-items\">\n {dress.items.map((item, index) => (\n <li key={index}>{item}</li>\n ))}\n </ul>\n );\n /* A mark stands where the tone's dot would, in its colour; the word stays the value, for every reader. */\n case 'tone':\n return dress.icon ? (\n <span className={`tone tone-${dress.tone} tone-marked`} title={dress.label === dress.text ? undefined : dress.text}>\n <Icon name={dress.icon as IconName} size={14} className=\"value-mark-icon\" />\n {dress.label}\n </span>\n ) : (\n <span\n className={`tone tone-${dress.tone}${dress.figure ? ' tone-figure' : ''}`}\n title={dress.label === dress.text ? undefined : dress.text}\n >\n {dress.label}\n </span>\n );\n case 'mark':\n return (\n <span className=\"value-mark\" title={dress.label === dress.text ? undefined : dress.text}>\n <Icon name={dress.icon as IconName} size={14} className=\"value-mark-icon\" />\n {dress.label}\n </span>\n );\n case 'word':\n return <span title={dress.label === dress.text ? undefined : dress.text}>{dress.label}</span>;\n case 'money':\n return (\n <span className=\"num-value\" title={dress.title}>\n {dress.text}\n </span>\n );\n case 'number':\n return (\n <span className=\"num-value\" title={dress.title}>\n {dress.text}\n </span>\n );\n case 'date':\n return (\n <span className=\"date-value\" title={dress.title}>\n {dress.text}\n </span>\n );\n case 'relative':\n return (\n <span className={`date-value relative${dress.overdue ? ' overdue' : ''}`} title={dress.title}>\n {dress.text}\n </span>\n );\n case 'avatar':\n return <AvatarText text={dress.text} photo={dress.photo} />;\n /* The names are the text, for every reader; the discs and the count are what a glance takes in. */\n case 'avatars':\n return (\n <span className=\"avatar-stack\" title={dress.text} role=\"img\" aria-label={dress.text}>\n {dress.names.map((name, index) => (\n <span key={index} className={`avatar avatar-c${hueOf(name)}`} aria-hidden=\"true\">\n {initialsOf(name)}\n </span>\n ))}\n {dress.more ? (\n <span className=\"avatar avatar-more\" aria-hidden=\"true\">\n +{dress.more}\n </span>\n ) : null}\n </span>\n );\n /* No title and no reveal: the placeholder is all that is drawn. */\n case 'masked':\n return <span className=\"value-masked\">{dress.text}</span>;\n case 'meter':\n return (\n <span className={`meter-wrap${dress.tone ? ` meter-${dress.tone}` : ''}`} title={dress.title}>\n <span className=\"pct-bar\">\n <span className=\"pct-fill\" style={{ width: `${dress.fill}%` }} />\n </span>\n <span className=\"num-value\">{dress.text}</span>\n </span>\n );\n /* Stars as one picture, said as words: \"4 of 5 stars\". A tone colors the filled ones. */\n case 'rating':\n return (\n <span className={`rating-value${dress.tone ? ` rating-${dress.tone}` : ''}`} role=\"img\" aria-label={dress.text} title={dress.text}>\n {Array.from({ length: dress.outOf }, (_, index) => (\n <span key={index} className={index < dress.value ? 'rating-star is-on' : 'rating-star'} aria-hidden=\"true\">\n ★\n </span>\n ))}\n </span>\n );\n case 'color':\n return (\n <span className=\"color-value\">\n <span className=\"color-swatch\" style={{ background: dress.hex }} aria-hidden=\"true\" />\n <span className=\"num-value\">{dress.text}</span>\n </span>\n );\n case 'json':\n return compact ? <span className=\"json-preview-text\">{dress.excerpt}</span> : <JsonValue value={JSON.parse(dress.text) as object} />;\n /* In a list the value is its text; a record draws the code to scan, the text under it. */\n case 'qr':\n return compact ? <span className=\"num-value\">{dress.text}</span> : <QrPart text={dress.text} />;\n /* In a list a signature is the word; a record draws the picture, ink on the card's own ground. */\n case 'signature':\n return compact ? (\n <span>{dress.text}</span>\n ) : (\n <img\n className=\"signature-value\"\n src={dress.src}\n alt={dress.text}\n loading=\"lazy\"\n // Ink kept on paper in every look, as a QR code's ground is; inline, so no first sheet carries it.\n style={{ display: 'block', maxWidth: 240, maxHeight: 96, padding: 4, background: '#fff', borderRadius: 'var(--radius)' }}\n />\n );\n case 'percent':\n if (dress.ring !== undefined)\n return (\n <span className=\"pct-ring-wrap\" title={dress.text}>\n <svg className=\"pct-ring\" viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <circle className=\"pct-ring-track\" cx=\"8\" cy=\"8\" r=\"6\" />\n <circle\n className=\"pct-ring-fill\"\n cx=\"8\"\n cy=\"8\"\n r=\"6\"\n strokeDasharray={`${(dress.ring / 100) * RING} ${RING}`}\n transform=\"rotate(-90 8 8)\"\n />\n </svg>\n <span className=\"num-value\">{dress.text}</span>\n </span>\n );\n if (dress.bar === undefined) return <span className=\"num-value\">{dress.text}</span>;\n return (\n <span className=\"pct-wrap\" title={dress.text}>\n <span className=\"pct-bar\">\n <span className=\"pct-fill\" style={{ width: `${dress.bar}%` }} />\n </span>\n <span className=\"num-value\">{dress.text}</span>\n </span>\n );\n }\n}, sameDress);\n\n/** A long unbroken token, said by its start and its length; the whole of it on request, wrapping anywhere. */\nfunction Opaque({ text, head, compact }: { text: string; head: string; compact: boolean }) {\n const [open, setOpen] = useState(false);\n if (compact) return <span className=\"value-opaque\">{head}…</span>;\n if (open) return <div className=\"value-opaque value-opaque-open\">{text}</div>;\n return (\n <span className=\"value-opaque\">\n {head}…{' '}\n <button type=\"button\" className=\"value-opaque-more\" onClick={() => setOpen(true)}>\n {say('showAllCharacters', { textCount: text.length.toLocaleString() })}\n </button>\n </span>\n );\n}\n\n/**\n * A value no rule dresses, as the grid's planner reads it on a row of one: a\n * flag, a figure (every digit of one past 2^53 kept — it arrives as a string\n * and is never run through Number()), a date in the reader's words, prose, a\n * token. In an App a value of the column's own vocabulary is a word, as its\n * chip says it; the Workbench shows the data exactly.\n */\nexport function Said({\n col,\n value,\n compact = false,\n app,\n}: {\n col: ColumnMeta | undefined;\n value: unknown;\n compact?: boolean;\n app: boolean;\n}) {\n const said = sayValue(col, value);\n switch (said.kind) {\n case 'boolean':\n return (\n <span className={`bool-value ${said.on ? 'yes' : 'no'}`} title={said.title}>\n {said.on ? say('yes') : say('no')}\n </span>\n );\n case 'number':\n return (\n <span className=\"num-value\" title={said.title}>\n {said.text}\n </span>\n );\n case 'date':\n return (\n <span className=\"date-value\" title={said.title}>\n {said.text}\n </span>\n );\n case 'long':\n return compact ? <span title={said.text}>{said.text}</span> : <div className=\"long-value prose\">{said.text}</div>;\n case 'opaque':\n return <Opaque text={said.text} head={said.head} compact={compact} />;\n default: {\n const word = app && col?.allowed?.includes(said.text) ? vocabularyWord(said.text) : said.text;\n return (\n /* A key, a code or a serial is a figure to the data face's reach (themeFamilies.css): `id-value` says so. */\n <span\n className={said.prose || (app && !identifierLike(col, col?.name ?? '')) ? 'prose' : app ? 'id-value' : undefined}\n title={said.text}\n >\n {word}\n </span>\n );\n }\n }\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { Ft as shellRoot, Nt as shellQuery } from "./shared-DJZjSi3J.js";
2
- import "./shared-DPAVoWY0.js";
2
+ import "./shared-BoLbc2WD.js";
3
3
  import { Un as refreshViewportScale } from "./shared-CRr4kJXB.js";
4
4
  // packages/kit/src/client/density.js
5
5
  /**
@@ -75,4 +75,4 @@ function setDensity(choice) {
75
75
  }
76
76
  export { setDensity as n, densityChoice as t };
77
77
 
78
- //# sourceMappingURL=shared-D3MAuEA3.js.map
78
+ //# sourceMappingURL=shared-CPjpSFGh.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"shared-D3MAuEA3.js","names":[],"sources":["../../../kit/src/client/density.js"],"sourcesContent":["/**\n * How much room tablewalk takes: comfortable — the default of a look that does not say — spacious, or compact\n * (Lumen, Mono and Sage start an App compact, themeLooks.ts).\n *\n * A display preference like the theme, so it lives where the theme lives:\n * this browser's storage, per person. It applies across both modes,\n * because density is about the reader's eyes, not about which room they\n * are in.\n *\n * One uniform scale rather than a second set of font rules: the px values\n * in the stylesheet were chosen together, and scaling them together is\n * the only change that keeps those choices. The scale lands on the *root*\n * element, not on body: every fixed-position card measures the page with\n * getBoundingClientRect and then places itself, and only with the whole\n * document in one zoomed coordinate space do the measurement and the\n * placement agree — zoom on body put the peek card a room away from the\n * chip it described.\n */\nimport { refreshViewportScale } from './core.js';\nimport { shellQuery, shellRoot } from './shellHost.js';\n\nconst KEY = 'mistri.density';\n/* Steps far enough apart to be steps: a 6% middle read as no change at\n all. The default look sits in the middle as \"comfortable\"; spacious is\n a real jump above it, compact the stylesheet's own tightest cut. */\nconst SCALE = { comfortable: '1.12', spacious: '1.24' };\n/** @typedef {'compact' | 'comfortable' | 'spacious'} Density */\n/** @param {unknown} value @returns {value is Density} */\nconst known = (value) => value === 'compact' || value === 'comfortable' || value === 'spacious';\n/** @type {Density} */\nlet remembered = 'comfortable';\nlet sessionOnly = false;\n/** The worn theme's density (`defineTheme({ density })`), until the reader picks their own. @type {Density | undefined} */\nlet themed;\n/* Until the App's theme arrives, the density the server says its page wears (clientHttp.ts, `mistri-density`).\n Boot zooms before the first paint and the theme lands a round trip later: guessed as comfortable, a compact\n look (Lumen, every App's default) drew its startup outline at 1.12 and then pulled it back to 1, a layout\n shift of 0.12 on a phone before the App had drawn a thing. */\nfunction themedNow() {\n if (themed) return themed;\n const told = shellQuery('meta[name=\"mistri-density\"]')?.getAttribute('content');\n return (themed = known(told) ? told : 'comfortable');\n}\n\n/** The theme's density, for a reader with no choice of their own; applied at once when it changes.\n @param {unknown} choice */\nexport function setDensityDefault(choice) {\n const next = known(choice) ? choice : 'comfortable';\n if (next === themedNow()) return;\n themed = next;\n applyDensity();\n}\n\nexport function densityChoice() {\n // A failed write must not let an older stored choice undo this tab's input.\n if (sessionOnly) return remembered;\n try {\n const stored = localStorage.getItem(KEY);\n remembered = known(stored) ? stored : themedNow();\n } catch {\n /* Keep the last readable or explicitly chosen value. */\n }\n return remembered;\n}\n\nexport function applyDensity() {\n const choice = densityChoice();\n const scale = SCALE[choice];\n /* A list's row is a height per density (--row-h, style.css), drawn through the zoom: set here, with the zoom,\n before the first paint, so a row never changes height once drawn. */\n shellRoot().dataset.density = choice;\n const root = shellRoot().style;\n if (scale) {\n root.setProperty('zoom', scale);\n /* vh units do not shrink with the zoom, so the shell's height token\n must: a 100vh body under zoom overflowed the window by the zoom and\n gave the whole app an outer scrollbar that carried the topbar away. */\n root.setProperty('--shell-vh', `calc(100vh / ${scale})`);\n /* The startup outline painted from the page before this ran, at 1: it divides by this to stay where it was\n drawn (index.html), so the zoom landing is not a layout shift of the whole outline. */\n root.setProperty('--density-zoom', String(scale));\n } else {\n root.removeProperty('zoom');\n root.removeProperty('--shell-vh');\n root.removeProperty('--density-zoom');\n }\n refreshViewportScale();\n}\n\n/** Keep a choice and apply it. Anything unrecognised means comfortable. */\nexport function setDensity(choice) {\n remembered = known(choice) ? choice : 'comfortable';\n try {\n localStorage.setItem(KEY, remembered);\n sessionOnly = false;\n } catch {\n // Nowhere to keep the choice is no reason to refuse it for this tab.\n sessionOnly = true;\n }\n applyDensity();\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAqBA,IAAM,MAAM;AAIZ,IAAM,QAAQ;CAAE,aAAa;CAAQ,UAAU;AAAO;;;AAGtD,IAAM,SAAS,UAAU,UAAU,aAAa,UAAU,iBAAiB,UAAU;;AAErF,IAAI,aAAa;AACjB,IAAI,cAAc;;AAElB,IAAI;AAKJ,SAAS,YAAY;CACnB,IAAI,QAAQ,OAAO;CACnB,MAAM,OAAO,WAAW,+BAA6B,CAAC,EAAE,aAAa,SAAS;CAC9E,OAAQ,SAAS,MAAM,IAAI,IAAI,OAAO;AACxC;AAWA,SAAgB,gBAAgB;CAE9B,IAAI,aAAa,OAAO;CACxB,IAAI;EACF,MAAM,SAAS,aAAa,QAAQ,GAAG;EACvC,aAAa,MAAM,MAAM,IAAI,SAAS,UAAU;CAClD,QAAQ,CAER;CACA,OAAO;AACT;AAEA,SAAgB,eAAe;CAC7B,MAAM,SAAS,cAAc;CAC7B,MAAM,QAAQ,MAAM;CAGpB,UAAU,CAAC,CAAC,QAAQ,UAAU;CAC9B,MAAM,OAAO,UAAU,CAAC,CAAC;CACzB,IAAI,OAAO;EACT,KAAK,YAAY,QAAQ,KAAK;EAI9B,KAAK,YAAY,cAAc,gBAAgB,MAAM,EAAE;EAGvD,KAAK,YAAY,kBAAkB,OAAO,KAAK,CAAC;CAClD,OAAO;EACL,KAAK,eAAe,MAAM;EAC1B,KAAK,eAAe,YAAY;EAChC,KAAK,eAAe,gBAAgB;CACtC;CACA,qBAAqB;AACvB;;AAGA,SAAgB,WAAW,QAAQ;CACjC,aAAa,MAAM,MAAM,IAAI,SAAS;CACtC,IAAI;EACF,aAAa,QAAQ,KAAK,UAAU;EACpC,cAAc;CAChB,QAAQ;EAEN,cAAc;CAChB;CACA,aAAa;AACf"}
1
+ {"version":3,"file":"shared-CPjpSFGh.js","names":[],"sources":["../../../kit/src/client/density.js"],"sourcesContent":["/**\n * How much room tablewalk takes: comfortable — the default of a look that does not say — spacious, or compact\n * (Lumen, Mono and Sage start an App compact, themeLooks.ts).\n *\n * A display preference like the theme, so it lives where the theme lives:\n * this browser's storage, per person. It applies across both modes,\n * because density is about the reader's eyes, not about which room they\n * are in.\n *\n * One uniform scale rather than a second set of font rules: the px values\n * in the stylesheet were chosen together, and scaling them together is\n * the only change that keeps those choices. The scale lands on the *root*\n * element, not on body: every fixed-position card measures the page with\n * getBoundingClientRect and then places itself, and only with the whole\n * document in one zoomed coordinate space do the measurement and the\n * placement agree — zoom on body put the peek card a room away from the\n * chip it described.\n */\nimport { refreshViewportScale } from './core.js';\nimport { shellQuery, shellRoot } from './shellHost.js';\n\nconst KEY = 'mistri.density';\n/* Steps far enough apart to be steps: a 6% middle read as no change at\n all. The default look sits in the middle as \"comfortable\"; spacious is\n a real jump above it, compact the stylesheet's own tightest cut. */\nconst SCALE = { comfortable: '1.12', spacious: '1.24' };\n/** @typedef {'compact' | 'comfortable' | 'spacious'} Density */\n/** @param {unknown} value @returns {value is Density} */\nconst known = (value) => value === 'compact' || value === 'comfortable' || value === 'spacious';\n/** @type {Density} */\nlet remembered = 'comfortable';\nlet sessionOnly = false;\n/** The worn theme's density (`defineTheme({ density })`), until the reader picks their own. @type {Density | undefined} */\nlet themed;\n/* Until the App's theme arrives, the density the server says its page wears (clientHttp.ts, `mistri-density`).\n Boot zooms before the first paint and the theme lands a round trip later: guessed as comfortable, a compact\n look (Lumen, every App's default) drew its startup outline at 1.12 and then pulled it back to 1, a layout\n shift of 0.12 on a phone before the App had drawn a thing. */\nfunction themedNow() {\n if (themed) return themed;\n const told = shellQuery('meta[name=\"mistri-density\"]')?.getAttribute('content');\n return (themed = known(told) ? told : 'comfortable');\n}\n\n/** The theme's density, for a reader with no choice of their own; applied at once when it changes.\n @param {unknown} choice */\nexport function setDensityDefault(choice) {\n const next = known(choice) ? choice : 'comfortable';\n if (next === themedNow()) return;\n themed = next;\n applyDensity();\n}\n\nexport function densityChoice() {\n // A failed write must not let an older stored choice undo this tab's input.\n if (sessionOnly) return remembered;\n try {\n const stored = localStorage.getItem(KEY);\n remembered = known(stored) ? stored : themedNow();\n } catch {\n /* Keep the last readable or explicitly chosen value. */\n }\n return remembered;\n}\n\nexport function applyDensity() {\n const choice = densityChoice();\n const scale = SCALE[choice];\n /* A list's row is a height per density (--row-h, style.css), drawn through the zoom: set here, with the zoom,\n before the first paint, so a row never changes height once drawn. */\n shellRoot().dataset.density = choice;\n const root = shellRoot().style;\n if (scale) {\n root.setProperty('zoom', scale);\n /* vh units do not shrink with the zoom, so the shell's height token\n must: a 100vh body under zoom overflowed the window by the zoom and\n gave the whole app an outer scrollbar that carried the topbar away. */\n root.setProperty('--shell-vh', `calc(100vh / ${scale})`);\n /* The startup outline painted from the page before this ran, at 1: it divides by this to stay where it was\n drawn (index.html), so the zoom landing is not a layout shift of the whole outline. */\n root.setProperty('--density-zoom', String(scale));\n } else {\n root.removeProperty('zoom');\n root.removeProperty('--shell-vh');\n root.removeProperty('--density-zoom');\n }\n refreshViewportScale();\n}\n\n/** Keep a choice and apply it. Anything unrecognised means comfortable. */\nexport function setDensity(choice) {\n remembered = known(choice) ? choice : 'comfortable';\n try {\n localStorage.setItem(KEY, remembered);\n sessionOnly = false;\n } catch {\n // Nowhere to keep the choice is no reason to refuse it for this tab.\n sessionOnly = true;\n }\n applyDensity();\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAqBA,IAAM,MAAM;AAIZ,IAAM,QAAQ;CAAE,aAAa;CAAQ,UAAU;AAAO;;;AAGtD,IAAM,SAAS,UAAU,UAAU,aAAa,UAAU,iBAAiB,UAAU;;AAErF,IAAI,aAAa;AACjB,IAAI,cAAc;;AAElB,IAAI;AAKJ,SAAS,YAAY;CACnB,IAAI,QAAQ,OAAO;CACnB,MAAM,OAAO,WAAW,+BAA6B,CAAC,EAAE,aAAa,SAAS;CAC9E,OAAQ,SAAS,MAAM,IAAI,IAAI,OAAO;AACxC;AAWA,SAAgB,gBAAgB;CAE9B,IAAI,aAAa,OAAO;CACxB,IAAI;EACF,MAAM,SAAS,aAAa,QAAQ,GAAG;EACvC,aAAa,MAAM,MAAM,IAAI,SAAS,UAAU;CAClD,QAAQ,CAER;CACA,OAAO;AACT;AAEA,SAAgB,eAAe;CAC7B,MAAM,SAAS,cAAc;CAC7B,MAAM,QAAQ,MAAM;CAGpB,UAAU,CAAC,CAAC,QAAQ,UAAU;CAC9B,MAAM,OAAO,UAAU,CAAC,CAAC;CACzB,IAAI,OAAO;EACT,KAAK,YAAY,QAAQ,KAAK;EAI9B,KAAK,YAAY,cAAc,gBAAgB,MAAM,EAAE;EAGvD,KAAK,YAAY,kBAAkB,OAAO,KAAK,CAAC;CAClD,OAAO;EACL,KAAK,eAAe,MAAM;EAC1B,KAAK,eAAe,YAAY;EAChC,KAAK,eAAe,gBAAgB;CACtC;CACA,qBAAqB;AACvB;;AAGA,SAAgB,WAAW,QAAQ;CACjC,aAAa,MAAM,MAAM,IAAI,SAAS;CACtC,IAAI;EACF,aAAa,QAAQ,KAAK,UAAU;EACpC,cAAc;CAChB,QAAQ;EAEN,cAAc;CAChB;CACA,aAAa;AACf"}
@@ -1,4 +1,4 @@
1
- import { L as state, R as subscribeWalk, V as walkVersion } from "./shared-DPAVoWY0.js";
1
+ import { L as state, R as subscribeWalk, V as walkVersion } from "./shared-BoLbc2WD.js";
2
2
  import { useSyncExternalStore } from "react";
3
3
  // packages/kit/src/client/components/walk.ts
4
4
  /**
@@ -17,4 +17,4 @@ function useWalk() {
17
17
  }
18
18
  export { useWalk as t };
19
19
 
20
- //# sourceMappingURL=shared-VshXGwXP.js.map
20
+ //# sourceMappingURL=shared-CSPhENq3.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"shared-VshXGwXP.js","names":[],"sources":["../../../kit/src/client/components/walk.ts"],"sourcesContent":["/**\n * The walk, from inside a component.\n *\n * core.js owns the stack and mutates it in place — a crumb's label arrives\n * after the row does, a page learns its root — and ticks a counter on every\n * render and every crumb correction. This subscribes a component to that\n * tick, so it re-reads the stack whenever the vanilla client would have\n * redrawn the trail.\n */\nimport { useSyncExternalStore } from 'react';\nimport { state, subscribeWalk, walkVersion } from '../core.js';\n\nexport interface WalkEntry {\n kind: 'table' | 'breakdown' | 'row' | 'page';\n table?: string;\n query?: string;\n tab?: string;\n key?: Record<string, unknown>;\n label?: string;\n pageId?: string;\n rootBody?: string;\n /** The key of the App view that opened a list, or a row read beside it. */\n view?: string;\n}\n\n/** The stack as it stands; the component re-renders when it changes. */\nexport function useWalk(): WalkEntry[] {\n useSyncExternalStore(subscribeWalk, walkVersion, walkVersion);\n return state.stack as WalkEntry[];\n}\n"],"mappings":";;;;;;;;;;;;;AA0BA,SAAgB,UAAuB;CACrC,qBAAqB,eAAe,aAAa,WAAW;CAC5D,OAAO,MAAM;AACf"}
1
+ {"version":3,"file":"shared-CSPhENq3.js","names":[],"sources":["../../../kit/src/client/components/walk.ts"],"sourcesContent":["/**\n * The walk, from inside a component.\n *\n * core.js owns the stack and mutates it in place — a crumb's label arrives\n * after the row does, a page learns its root — and ticks a counter on every\n * render and every crumb correction. This subscribes a component to that\n * tick, so it re-reads the stack whenever the vanilla client would have\n * redrawn the trail.\n */\nimport { useSyncExternalStore } from 'react';\nimport { state, subscribeWalk, walkVersion } from '../core.js';\n\nexport interface WalkEntry {\n kind: 'table' | 'breakdown' | 'row' | 'page';\n table?: string;\n query?: string;\n tab?: string;\n key?: Record<string, unknown>;\n label?: string;\n pageId?: string;\n rootBody?: string;\n /** The key of the App view that opened a list, or a row read beside it. */\n view?: string;\n}\n\n/** The stack as it stands; the component re-renders when it changes. */\nexport function useWalk(): WalkEntry[] {\n useSyncExternalStore(subscribeWalk, walkVersion, walkVersion);\n return state.stack as WalkEntry[];\n}\n"],"mappings":";;;;;;;;;;;;;AA0BA,SAAgB,UAAuB;CACrC,qBAAqB,eAAe,aAAa,WAAW;CAC5D,OAAO,MAAM;AACf"}
@@ -1,7 +1,7 @@
1
1
  import { I as quoteValue, N as andQuery } from "./shared-poc11xxo.js";
2
2
  import { F as primaryKey, N as labelPath, k as findTable } from "./shared-DJZjSi3J.js";
3
- import { K as tableAtPrefix } from "./shared-DPAVoWY0.js";
4
- import { i as referenceProjection, t as recordView } from "./shared-BHc2Izkj.js";
3
+ import { K as tableAtPrefix } from "./shared-BoLbc2WD.js";
4
+ import { i as referenceProjection, t as recordView } from "./shared-C9DZtSFH.js";
5
5
  // packages/engine/src/shared/appLinks.ts
6
6
  function appTargetFields(target) {
7
7
  const values = [...target.kind === "record" ? Object.values(target.key) : [], ...target.tenant?.kind === "tenant" ? [target.tenant.id] : []];
@@ -192,4 +192,4 @@ function historyBody(base, key, limit) {
192
192
  }
193
193
  export { groupsBody as a, listView as c, whenBody as d, appTargetFields as f, fieldsColumns as i, metricMeasure as l, defaultFieldPaths as n, headerColumns as o, definedThrough as r, historyBody as s, RECORD_COMPOSE_PATH as t, timelineReads as u };
194
194
 
195
- //# sourceMappingURL=shared-DJrJaE73.js.map
195
+ //# sourceMappingURL=shared-CZJE4Bmp.js.map