@stfrigerio/sito-template 0.1.97 → 0.1.98

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 (196) hide show
  1. package/dist/components/organisms/charts/MoodChart/MoodChart.d.ts.map +1 -1
  2. package/dist/components/organisms/charts/QuantifiableHabitsChart/QuantifiableHabitsChart.d.ts.map +1 -1
  3. package/dist/index.esm.js +539 -175
  4. package/dist/index.esm.js.map +1 -1
  5. package/dist/index.js +538 -174
  6. package/dist/index.js.map +1 -1
  7. package/dist/styles.css +1 -1
  8. package/dist/styles.css.map +1 -1
  9. package/package.json +1 -1
  10. package/storybook-static/assets/{ASCIIText.stories-Df73neNa.js → ASCIIText.stories-DSI7g-mB.js} +1 -1
  11. package/storybook-static/assets/{AllAtoms.stories-BiI0dRwW.js → AllAtoms.stories-JflUIS5e.js} +1 -1
  12. package/storybook-static/assets/{AnimatedContent.stories-DjkrPhwb.js → AnimatedContent.stories-YR7SgIxb.js} +1 -1
  13. package/storybook-static/assets/{AnimatedList.stories-BfUnGN7d.js → AnimatedList.stories-GR75O93H.js} +1 -1
  14. package/storybook-static/assets/{Antigravity.stories-BTD9Xg7T.js → Antigravity.stories-B2MVCdRl.js} +1 -1
  15. package/storybook-static/assets/{ArrayInput.stories-B9kdIT9a.js → ArrayInput.stories-BI_3D81-.js} +1 -1
  16. package/storybook-static/assets/{Aurora.stories-BKttBo3z.js → Aurora.stories-C_w705rr.js} +1 -1
  17. package/storybook-static/assets/{Beams.stories-BT-94qMG.js → Beams.stories-D1L26zBi.js} +1 -1
  18. package/storybook-static/assets/{BlobCursor.stories-C0fe-xEI.js → BlobCursor.stories-BjywoQ5q.js} +1 -1
  19. package/storybook-static/assets/{BlurText.stories-CASYZKEu.js → BlurText.stories-CSpGTebR.js} +1 -1
  20. package/storybook-static/assets/{BooleansHeatmap.stories-CUTRmSWT.js → BooleansHeatmap.stories-CKYZW8W5.js} +1 -1
  21. package/storybook-static/assets/{BorderGlow.stories-Cbr654fz.js → BorderGlow.stories-BadihHiQ.js} +1 -1
  22. package/storybook-static/assets/{BubbleMenu.stories-D6s9f9iP.js → BubbleMenu.stories-Up_UUIWc.js} +1 -1
  23. package/storybook-static/assets/{Button-BFN9LHxy.js → Button-DtiJJxMy.js} +1 -1
  24. package/storybook-static/assets/{Button.stories--QkKginK.js → Button.stories-BG9uxBwH.js} +1 -1
  25. package/storybook-static/assets/{Calendar.stories-C6fMirS-.js → Calendar.stories-CUZikQRy.js} +1 -1
  26. package/storybook-static/assets/{Card-VJ_YQ2Rs.js → Card-BrvmNtM2.js} +1 -1
  27. package/storybook-static/assets/{Card.stories-BDxNouIx.js → Card.stories-Bf_EtMxA.js} +1 -1
  28. package/storybook-static/assets/{CardNav.stories-BnhrMkGa.js → CardNav.stories-OiwfVEn3.js} +1 -1
  29. package/storybook-static/assets/{Carousel.stories-CifGVvYJ.js → Carousel.stories-Gw1aPaNl.js} +1 -1
  30. package/storybook-static/assets/{Checkbox-BmAUW9fp.js → Checkbox-CJhut6rk.js} +1 -1
  31. package/storybook-static/assets/{Checkbox.stories-C_UvBcxW.js → Checkbox.stories-tIqU6B-y.js} +1 -1
  32. package/storybook-static/assets/{ChromaGrid.stories-BUUY24tG.js → ChromaGrid.stories-DbsrxAuC.js} +1 -1
  33. package/storybook-static/assets/{CircularGallery.stories-BAHtaC5N.js → CircularGallery.stories-0ffqgfyn.js} +1 -1
  34. package/storybook-static/assets/{CircularText.stories-Dyfa9TGc.js → CircularText.stories-o46bAR53.js} +1 -1
  35. package/storybook-static/assets/{ClickSpark.stories-DyY7-W0U.js → ClickSpark.stories-Ci-BtpH_.js} +1 -1
  36. package/storybook-static/assets/{ColorBends.stories-C09fGbbd.js → ColorBends.stories-CAiI7Gmw.js} +1 -1
  37. package/storybook-static/assets/{CountUp.stories-D319IPzj.js → CountUp.stories-CFiYranp.js} +1 -1
  38. package/storybook-static/assets/{Counter.stories-DyCug9AH.js → Counter.stories-BfaVu_y6.js} +1 -1
  39. package/storybook-static/assets/{Crosshair.stories-B0WQ_fE1.js → Crosshair.stories-_Hh1nKQp.js} +1 -1
  40. package/storybook-static/assets/{Cubes.stories-mKx-JaV9.js → Cubes.stories-DXBS_f8J.js} +1 -1
  41. package/storybook-static/assets/{CurvedLoop.stories-CPT1TgIj.js → CurvedLoop.stories-jcgMeMsw.js} +1 -1
  42. package/storybook-static/assets/{DarkVeil.stories-DO4z0Xfp.js → DarkVeil.stories-BwtU9vKO.js} +1 -1
  43. package/storybook-static/assets/{DateInput-CgcMwqZf.js → DateInput-6Jn_FyvO.js} +1 -1
  44. package/storybook-static/assets/{DateInput.stories-9DZA97sK.js → DateInput.stories-C_XBRwB3.js} +1 -1
  45. package/storybook-static/assets/{DecayCard.stories-DGvn_IgJ.js → DecayCard.stories-D6kTH79t.js} +1 -1
  46. package/storybook-static/assets/{DecryptedText.stories-_ycl9X6g.js → DecryptedText.stories-B4xWEvyF.js} +1 -1
  47. package/storybook-static/assets/{Dither.stories-B1UXWjuE.js → Dither.stories-DmAOxBWe.js} +1 -1
  48. package/storybook-static/assets/{Dock.stories--hZxLVBG.js → Dock.stories-AHZywNVf.js} +1 -1
  49. package/storybook-static/assets/{EditFAB.stories-ujZfcFCB.js → EditFAB.stories-BJ5P85ZN.js} +1 -1
  50. package/storybook-static/assets/{EvilEye.stories-DbdhTF7k.js → EvilEye.stories-D0CBPfm1.js} +1 -1
  51. package/storybook-static/assets/{FadeContent.stories-CwCMoiJh.js → FadeContent.stories-D1capsBJ.js} +1 -1
  52. package/storybook-static/assets/{FaultyTerminal.stories-DIhmC0oV.js → FaultyTerminal.stories-BxqqRf0S.js} +1 -1
  53. package/storybook-static/assets/{Fbo-X5yWHBm9.js → Fbo-DvyLCJ1Y.js} +1 -1
  54. package/storybook-static/assets/{FloatingLines.stories-BVLUpCaG.js → FloatingLines.stories-7ze9ddpl.js} +1 -1
  55. package/storybook-static/assets/{FlowingMenu.stories-Bz2Hm0ud.js → FlowingMenu.stories-BX9PD8x2.js} +1 -1
  56. package/storybook-static/assets/{FluidGlass.stories-iKAeEvkd.js → FluidGlass.stories-DynD7GVO.js} +1 -1
  57. package/storybook-static/assets/{Folder.stories-DsIub0M3.js → Folder.stories-DDktLoEO.js} +1 -1
  58. package/storybook-static/assets/{FuzzyText.stories-oIYU7hRG.js → FuzzyText.stories-D9tRARUX.js} +1 -1
  59. package/storybook-static/assets/{Galaxy.stories-CjouLZaF.js → Galaxy.stories-aSApGekp.js} +1 -1
  60. package/storybook-static/assets/{GhostCursor.stories-DCvUCCxa.js → GhostCursor.stories-5l0di532.js} +1 -1
  61. package/storybook-static/assets/{GlareHover.stories-Djk9iCFM.js → GlareHover.stories-Dc69-LbU.js} +1 -1
  62. package/storybook-static/assets/{GlassSurface.stories-VZesotzp.js → GlassSurface.stories-DETLyc0H.js} +1 -1
  63. package/storybook-static/assets/{GlitchText.stories-sn_wSP7G.js → GlitchText.stories-Bzb3ZMSY.js} +1 -1
  64. package/storybook-static/assets/{GooeyNav.stories-BFC9B_L0.js → GooeyNav.stories-rxdxJjAy.js} +1 -1
  65. package/storybook-static/assets/{GradientBlinds.stories-z-3FXHpB.js → GradientBlinds.stories-03LkBbo8.js} +1 -1
  66. package/storybook-static/assets/{GradientText.stories-B9P29Fe5.js → GradientText.stories-CGo9FyNH.js} +1 -1
  67. package/storybook-static/assets/{Grainient.stories-BxQe6t8A.js → Grainient.stories-CzGAEJr-.js} +1 -1
  68. package/storybook-static/assets/{GridMotion.stories-B8Qfotg2.js → GridMotion.stories-BzeBDaK8.js} +1 -1
  69. package/storybook-static/assets/{HabitTimeOfDayChart.stories-DqOwaExY.js → HabitTimeOfDayChart.stories-CbMqUfq0.js} +1 -1
  70. package/storybook-static/assets/{ImageSlideshow.stories-C7AUfiPQ.js → ImageSlideshow.stories-hoGOc1Gf.js} +1 -1
  71. package/storybook-static/assets/{Iridescence.stories-CmJNPKZp.js → Iridescence.stories-CQTjQ1lh.js} +1 -1
  72. package/storybook-static/assets/{LaserFlow.stories-Cj36k-Br.js → LaserFlow.stories-DzkVWskc.js} +1 -1
  73. package/storybook-static/assets/{LetterGlitch.stories-3n0_SpPW.js → LetterGlitch.stories-0wcxCpnJ.js} +1 -1
  74. package/storybook-static/assets/{LightPillar.stories-DLDV89_g.js → LightPillar.stories-C3jRtdg9.js} +1 -1
  75. package/storybook-static/assets/{LightRays.stories-95rx1Jld.js → LightRays.stories-C52kBsnd.js} +1 -1
  76. package/storybook-static/assets/{Lightning.stories-Ban00VPp.js → Lightning.stories-BFVGqmMh.js} +1 -1
  77. package/storybook-static/assets/{LineWaves.stories-tYVITNBI.js → LineWaves.stories-DNdwRrSd.js} +1 -1
  78. package/storybook-static/assets/{LiquidChrome.stories-CRXhS5wG.js → LiquidChrome.stories-DFTBXxI6.js} +1 -1
  79. package/storybook-static/assets/{LiquidEther.stories-DFcjj4WN.js → LiquidEther.stories-BGYmyfDI.js} +1 -1
  80. package/storybook-static/assets/{LoadingSpinner-BCSPbqAf.js → LoadingSpinner-D3Kx-V7J.js} +1 -1
  81. package/storybook-static/assets/{LoadingSpinner.stories-B-3mwj6v.js → LoadingSpinner.stories-CP70BGAb.js} +1 -1
  82. package/storybook-static/assets/{MagicRings.stories-DxX9Y4fZ.js → MagicRings.stories-BA9xv5mB.js} +1 -1
  83. package/storybook-static/assets/{Magnet.stories-BtP078KP.js → Magnet.stories-cqBYCb-D.js} +1 -1
  84. package/storybook-static/assets/{MagnetLines.stories-Boc9ZU8z.js → MagnetLines.stories-QkoPnGKj.js} +1 -1
  85. package/storybook-static/assets/{Masonry.stories-BZUo993q.js → Masonry.stories-CiGXRf3O.js} +1 -1
  86. package/storybook-static/assets/{MetaBalls.stories-DXYO9QHZ.js → MetaBalls.stories-3l0pQiKn.js} +1 -1
  87. package/storybook-static/assets/{MetallicPaint.stories-BSFAAtcE.js → MetallicPaint.stories-DgZJfMr5.js} +1 -1
  88. package/storybook-static/assets/MoodChart-Cu7ntVIE.css +1 -0
  89. package/storybook-static/assets/MoodChart.stories-UXaQU4EG.js +40 -0
  90. package/storybook-static/assets/{MotionConfigContext-cqdgvETc.js → MotionConfigContext-BWFxZgdN.js} +1 -1
  91. package/storybook-static/assets/{Navbar.stories-TgnWvuhq.js → Navbar.stories-C_Zyfhqr.js} +1 -1
  92. package/storybook-static/assets/{Noise.stories-COwmBW-s.js → Noise.stories-Cg7CucgT.js} +1 -1
  93. package/storybook-static/assets/{NumberStepper-BLyqaAZY.js → NumberStepper-DpOu7xmF.js} +1 -1
  94. package/storybook-static/assets/{NumberStepper.stories-BH--ymZD.js → NumberStepper.stories-CvG9oY5Q.js} +1 -1
  95. package/storybook-static/assets/{Orb.stories-BouXCqts.js → Orb.stories-BR92tgyW.js} +1 -1
  96. package/storybook-static/assets/{OrbitImages.stories-DwPbtwmh.js → OrbitImages.stories-D_-2HcAd.js} +1 -1
  97. package/storybook-static/assets/{PieChart.stories-ThEQ6o4T.js → PieChart.stories-CjtEiSJY.js} +1 -1
  98. package/storybook-static/assets/{PixelBlast.stories-CXLoQgLR.js → PixelBlast.stories-B6FXuNf4.js} +1 -1
  99. package/storybook-static/assets/{PixelCard.stories-CwsDhfSZ.js → PixelCard.stories-Dq4CP2Qj.js} +1 -1
  100. package/storybook-static/assets/{PixelSnow.stories-B78--r-5.js → PixelSnow.stories-BoQSOear.js} +1 -1
  101. package/storybook-static/assets/{PixelTransition.stories-CQRCg5Dh.js → PixelTransition.stories-CtQQ070z.js} +1 -1
  102. package/storybook-static/assets/{Plasma.stories-C4nsJ8m0.js → Plasma.stories-D-421jzZ.js} +1 -1
  103. package/storybook-static/assets/{Prism.stories-CYyW2MhJ.js → Prism.stories-BuibpwdU.js} +1 -1
  104. package/storybook-static/assets/{PrismaticBurst.stories-DPAVXNq-.js → PrismaticBurst.stories-CwYzdBlM.js} +1 -1
  105. package/storybook-static/assets/{ProfileCard.stories-GQnHhvBL.js → ProfileCard.stories-Dj4oJCxw.js} +1 -1
  106. package/storybook-static/assets/QuantifiableHabitsChart-DK3Cp5zY.css +1 -0
  107. package/storybook-static/assets/QuantifiableHabitsChart.stories-ZY1-WQ1g.js +125 -0
  108. package/storybook-static/assets/{Radar.stories-BiS3kVBK.js → Radar.stories-DxNmoYV3.js} +1 -1
  109. package/storybook-static/assets/{RecurrencePicker.stories-AkU87_0U.js → RecurrencePicker.stories-BAicSNhQ.js} +1 -1
  110. package/storybook-static/assets/{Ribbons.stories-OMZCYkS-.js → Ribbons.stories-usN1kCyI.js} +1 -1
  111. package/storybook-static/assets/{RippleGrid.stories-f-knJ_dC.js → RippleGrid.stories-nTLGHPV6.js} +1 -1
  112. package/storybook-static/assets/{RotatingText.stories-Cs5g6eNr.js → RotatingText.stories-8CShs_WJ.js} +1 -1
  113. package/storybook-static/assets/{ScrollFloat.stories-BkinOlWM.js → ScrollFloat.stories-Dp9YyvHK.js} +1 -1
  114. package/storybook-static/assets/{ScrollReveal.stories-DAawYSvS.js → ScrollReveal.stories-Dy4JUrqi.js} +1 -1
  115. package/storybook-static/assets/{ScrollVelocity.stories-DDKvgeRt.js → ScrollVelocity.stories-CUf-OHNp.js} +1 -1
  116. package/storybook-static/assets/{SearchBar.stories-DontnpSK.js → SearchBar.stories-BKfuRnlK.js} +1 -1
  117. package/storybook-static/assets/{SearchableDropdown-DOvqXBhT.js → SearchableDropdown-Ctnh_PVq.js} +1 -1
  118. package/storybook-static/assets/{SearchableDropdown.stories-Ct5wfF8Q.js → SearchableDropdown.stories-1d-goy0G.js} +1 -1
  119. package/storybook-static/assets/{SelectInput-DTobf0zh.js → SelectInput-C94OHQIl.js} +1 -1
  120. package/storybook-static/assets/{SelectInput.stories-D65m3xT6.js → SelectInput.stories-DPV5iKcs.js} +1 -1
  121. package/storybook-static/assets/{ShapeBlur.stories-C2QcmUF6.js → ShapeBlur.stories-CdASN24B.js} +1 -1
  122. package/storybook-static/assets/{ShapeGrid.stories-B4UpvWuC.js → ShapeGrid.stories-Duzq6qpW.js} +1 -1
  123. package/storybook-static/assets/{ShinyText.stories-Dx9uB0Ge.js → ShinyText.stories-Dgqps29_.js} +1 -1
  124. package/storybook-static/assets/{Silk.stories-OqHp151A.js → Silk.stories-DWnaBFZp.js} +1 -1
  125. package/storybook-static/assets/{SleepChart.stories-EvXrufhV.js → SleepChart.stories-C1n9aK7B.js} +1 -1
  126. package/storybook-static/assets/{Slider-B49_dS8L.js → Slider-C69QbwVa.js} +1 -1
  127. package/storybook-static/assets/{Slider.stories-C-WUPilU.js → Slider.stories-DDhTLU2g.js} +1 -1
  128. package/storybook-static/assets/{SoftAurora.stories-D3FuYkw4.js → SoftAurora.stories-C5OSOqjj.js} +1 -1
  129. package/storybook-static/assets/{SoundDemo.stories-BgQu6ftq.js → SoundDemo.stories-sb4V9P8H.js} +1 -1
  130. package/storybook-static/assets/{SplashCursor.stories-DWJpmVM0.js → SplashCursor.stories-PeC0-y78.js} +1 -1
  131. package/storybook-static/assets/{SpotlightCard.stories-B59YbgvD.js → SpotlightCard.stories-BCCdQhIJ.js} +1 -1
  132. package/storybook-static/assets/{Stack.stories-C0txqVGC.js → Stack.stories-DJekNsdu.js} +1 -1
  133. package/storybook-static/assets/{StaggeredMenu.stories-B-EDB5Rd.js → StaggeredMenu.stories-BU-AxZRv.js} +1 -1
  134. package/storybook-static/assets/{StarBorder.stories-WozhQkt_.js → StarBorder.stories-Dw9LDvMk.js} +1 -1
  135. package/storybook-static/assets/{SunburstChart.stories-B-FtFWzz.js → SunburstChart.stories-CE4d4r8-.js} +1 -1
  136. package/storybook-static/assets/{Table.stories-CnuV2Phn.js → Table.stories-IhtnLV5J.js} +1 -1
  137. package/storybook-static/assets/{Tabs.stories-C6Ixt85v.js → Tabs.stories-F_Q4-xiR.js} +1 -1
  138. package/storybook-static/assets/{TargetCursor.stories-D05-aNwu.js → TargetCursor.stories-B-Tl1DdA.js} +1 -1
  139. package/storybook-static/assets/{TextArea-DtQ-6kae.js → TextArea-Bb148SaD.js} +1 -1
  140. package/storybook-static/assets/{TextArea.stories-DQa3wP_Z.js → TextArea.stories-5-dHoUPL.js} +1 -1
  141. package/storybook-static/assets/{TextCursor.stories-BJTUllxj.js → TextCursor.stories-O-EIx7Nu.js} +1 -1
  142. package/storybook-static/assets/{TextInput-ohzWFFuq.js → TextInput-BQ78htqq.js} +1 -1
  143. package/storybook-static/assets/{TextInput.stories-CIFhZSxb.js → TextInput.stories-Bjjfu_5O.js} +1 -1
  144. package/storybook-static/assets/{TextPressure.stories-BDbHdoj0.js → TextPressure.stories-BvXWcayn.js} +1 -1
  145. package/storybook-static/assets/{TextType.stories-Dpp0yM1F.js → TextType.stories-DL92625c.js} +1 -1
  146. package/storybook-static/assets/{ThemeSwitcher.stories-Ch3eX-Q4.js → ThemeSwitcher.stories-BUUyb12v.js} +1 -1
  147. package/storybook-static/assets/{Threads.stories-BYlFBArL.js → Threads.stories-C_LDNe0R.js} +1 -1
  148. package/storybook-static/assets/{TimeInput.stories-ChJb0EcK.js → TimeInput.stories-Tj2LrCtN.js} +1 -1
  149. package/storybook-static/assets/{Toggle-Er5JazC4.js → Toggle-BgFXbOVy.js} +1 -1
  150. package/storybook-static/assets/{Toggle.stories-ClF63HwM.js → Toggle.stories-voNeGmVh.js} +1 -1
  151. package/storybook-static/assets/{ToggleButton-BgyTdkGs.js → ToggleButton-CQLM9369.js} +1 -1
  152. package/storybook-static/assets/{ToggleButton.stories-D2YQjBPU.js → ToggleButton.stories-CLdG94qe.js} +1 -1
  153. package/storybook-static/assets/{TrueFocus.stories-B4Qoh1Ek.js → TrueFocus.stories-CEC_mKz7.js} +1 -1
  154. package/storybook-static/assets/{VariableProximity.stories-DLzbqQ-q.js → VariableProximity.stories-CoB68xuF.js} +1 -1
  155. package/storybook-static/assets/{Waves.stories-OX3VExu5.js → Waves.stories-Cpn9tv6C.js} +1 -1
  156. package/storybook-static/assets/{band-BYy0bT_S.js → band-Cq25-Mh7.js} +1 -1
  157. package/storybook-static/assets/{calendar-3_ekvfk7.js → calendar-B90N4a5g.js} +1 -1
  158. package/storybook-static/assets/{chart-column-B99l8ykF.js → chart-column-Qn3KVlVm.js} +1 -1
  159. package/storybook-static/assets/{check-MGuZ-vQU.js → check-BdgefYk0.js} +1 -1
  160. package/storybook-static/assets/{chevron-down-dMiwJ2Fa.js → chevron-down-rAxqUK0f.js} +1 -1
  161. package/storybook-static/assets/{chevron-right-BGiouhAQ.js → chevron-right-BQYLOSGD.js} +1 -1
  162. package/storybook-static/assets/client-Chg03P_H.js +1 -0
  163. package/storybook-static/assets/{createLucideIcon-He700CuR.js → createLucideIcon-CanksmPJ.js} +1 -1
  164. package/storybook-static/assets/{download-BKSOfxpe.js → download-BoPCl2gy.js} +1 -1
  165. package/storybook-static/assets/{folder-LestSoCO.js → folder-B0zTnOfo.js} +1 -1
  166. package/storybook-static/assets/{iconBase-zJDHXTd9.js → iconBase-jWAd7fUM.js} +1 -1
  167. package/storybook-static/assets/{iframe-D8qqeeGJ.js → iframe-BTbLpgFM.js} +3 -3
  168. package/storybook-static/assets/{index-L49vE-ah.js → index-8orVvKs3.js} +1 -1
  169. package/storybook-static/assets/{index-C-VnSuS_.js → index-D9A3yXPP.js} +1 -1
  170. package/storybook-static/assets/{index-CJyQ6SwC.js → index-Dnnp7mc9.js} +1 -1
  171. package/storybook-static/assets/{linear-DhrdWH9x.js → linear-9syG7RFK.js} +1 -1
  172. package/storybook-static/assets/monotone-B6BFTqpP.js +1 -0
  173. package/storybook-static/assets/{proxy-1W9qMPm5.js → proxy-DHiOkbBq.js} +1 -1
  174. package/storybook-static/assets/{react-18-BVZJZnf4.js → react-18-RyhzFaVZ.js} +1 -1
  175. package/storybook-static/assets/{react-three-fiber.esm-Ccm-0uhF.js → react-three-fiber.esm-DyDueq1t.js} +1 -1
  176. package/storybook-static/assets/{search-BgqlFsxE.js → search-C2F8ucQI.js} +1 -1
  177. package/storybook-static/assets/{settings-BXbuThqT.js → settings-B4F4kfld.js} +1 -1
  178. package/storybook-static/assets/{sun-DzhjLvFL.js → sun-CbGl2Vwt.js} +1 -1
  179. package/storybook-static/assets/{transform-QOf3tDlt.js → transform-v7fcW145.js} +1 -1
  180. package/storybook-static/assets/{trash-2-SM79_8re.js → trash-2-CNCXZ0wH.js} +1 -1
  181. package/storybook-static/assets/{use-animation-frame-sEnyIjfp.js → use-animation-frame-DY1VsI4g.js} +1 -1
  182. package/storybook-static/assets/{use-in-view-Z5TSuHio.js → use-in-view-Cawxv_UZ.js} +1 -1
  183. package/storybook-static/assets/{use-motion-value-DQT5SPdA.js → use-motion-value-BKT0PPfP.js} +1 -1
  184. package/storybook-static/assets/{use-spring-DwAy_p1Y.js → use-spring-CDH8BIpQ.js} +1 -1
  185. package/storybook-static/assets/{use-transform-C2Oyk60n.js → use-transform-Bj0aHFrd.js} +1 -1
  186. package/storybook-static/assets/{useSound-CUVgLyES.js → useSound-OlKqgJtL.js} +1 -1
  187. package/storybook-static/assets/{users-CeDtcuCx.js → users-Oy8C2tFC.js} +1 -1
  188. package/storybook-static/assets/{x-BoXEIqKt.js → x-CR0CkM0G.js} +1 -1
  189. package/storybook-static/iframe.html +1 -1
  190. package/storybook-static/project.json +1 -1
  191. package/storybook-static/assets/MoodChart-ba3aY_qF.css +0 -1
  192. package/storybook-static/assets/MoodChart.stories-CnSQKAhp.js +0 -40
  193. package/storybook-static/assets/QuantifiableHabitsChart-JSu1fVKW.css +0 -1
  194. package/storybook-static/assets/QuantifiableHabitsChart.stories-DQybQV3G.js +0 -125
  195. package/storybook-static/assets/client-AUYJ3-v0.js +0 -1
  196. package/storybook-static/assets/monotone-DouxdRGd.js +0 -1
package/dist/index.js CHANGED
@@ -3957,22 +3957,27 @@ const Navbar = ({ items, logo, onItemClick, variant = 'sidebar', isMobile = fals
3957
3957
  return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsx(framerMotion.motion.nav, { className: `${styles.navbar} ${styles[`navbar${variant.charAt(0).toUpperCase() + variant.slice(1)}`]} ${className}`, "data-colored-icons": coloredIconsAttr, initial: variant === 'sidebar' ? { x: -300 } : { opacity: 0 }, animate: variant === 'sidebar' ? { x: 0 } : { opacity: 1 }, transition: { type: 'spring', stiffness: 300, damping: 30 }, children: navContent }) }));
3958
3958
  };
3959
3959
 
3960
- var styles$9 = {"container":"MoodChart-module_container__MB1Vr","chart":"MoodChart-module_chart__4-spu","gridLine":"MoodChart-module_gridLine__YJpZ8","line":"MoodChart-module_line__LfeUX","xAxis":"MoodChart-module_xAxis__SeIWG","yAxis":"MoodChart-module_yAxis__sRjjE","dataPoint":"MoodChart-module_dataPoint__112P1","tooltip":"MoodChart-module_tooltip__vW59y","tooltipHeader":"MoodChart-module_tooltipHeader__U7yvN","tooltipDate":"MoodChart-module_tooltipDate__6Jjeu","tooltipRating":"MoodChart-module_tooltipRating__5A2Yx","ratingValue":"MoodChart-module_ratingValue__7Gpfx","ratingMax":"MoodChart-module_ratingMax__10WcJ","tooltipTags":"MoodChart-module_tooltipTags__FUQrU","tag":"MoodChart-module_tag__QhCh5","tooltipComment":"MoodChart-module_tooltipComment__6driJ"};
3960
+ var styles$9 = {"container":"MoodChart-module_container__MB1Vr","chart":"MoodChart-module_chart__4-spu","gridLine":"MoodChart-module_gridLine__YJpZ8","line":"MoodChart-module_line__LfeUX","area":"MoodChart-module_area__a4BFM","areaStopTop":"MoodChart-module_areaStopTop__KEp49","areaStopBottom":"MoodChart-module_areaStopBottom__cp7Gn","crosshair":"MoodChart-module_crosshair__PHLfW","halo":"MoodChart-module_halo__YQB-7","overlay":"MoodChart-module_overlay__ZwuHi","xAxis":"MoodChart-module_xAxis__SeIWG","yAxis":"MoodChart-module_yAxis__sRjjE","dataPoint":"MoodChart-module_dataPoint__112P1","tooltip":"MoodChart-module_tooltip__vW59y","tooltipHeader":"MoodChart-module_tooltipHeader__U7yvN","tooltipDate":"MoodChart-module_tooltipDate__6Jjeu","tooltipRating":"MoodChart-module_tooltipRating__5A2Yx","ratingValue":"MoodChart-module_ratingValue__7Gpfx","ratingMax":"MoodChart-module_ratingMax__10WcJ","tooltipTags":"MoodChart-module_tooltipTags__FUQrU","tag":"MoodChart-module_tag__QhCh5","tooltipComment":"MoodChart-module_tooltipComment__6driJ"};
3961
3961
 
3962
3962
  const MoodChart = ({ moodData, width = 800, height = 400 }) => {
3963
3963
  const svgRef = React.useRef(null);
3964
3964
  const containerRef = React.useRef(null);
3965
3965
  const tooltipRef = React.useRef(null);
3966
+ const isHoveringTooltipRef = React.useRef(false);
3967
+ const rawId = React.useId();
3968
+ const gradientId = React.useMemo(() => `mood-area-${rawId.replace(/[^a-zA-Z0-9]/g, '_')}`, [rawId]);
3966
3969
  const [selectedMood, setSelectedMood] = React.useState(null);
3967
3970
  const [tooltipPosition, setTooltipPosition] = React.useState({ x: 0, y: 0 });
3968
3971
  const [isHoveringTooltip, setIsHoveringTooltip] = React.useState(false);
3972
+ React.useEffect(() => {
3973
+ isHoveringTooltipRef.current = isHoveringTooltip;
3974
+ }, [isHoveringTooltip]);
3969
3975
  const margin = React.useMemo(() => ({ top: 20, right: 20, bottom: 50, left: 40 }), []);
3970
3976
  const chartWidth = width - margin.left - margin.right;
3971
3977
  const chartHeight = height - margin.top - margin.bottom;
3972
3978
  const processedData = React.useMemo(() => {
3973
3979
  return moodData
3974
3980
  .map(mood => {
3975
- // Parse comma-separated tags
3976
3981
  const tags = mood.tag
3977
3982
  ? mood.tag.split(',').map(t => t.trim()).filter(t => t)
3978
3983
  : [];
@@ -3984,7 +3989,8 @@ const MoodChart = ({ moodData, width = 800, height = 400 }) => {
3984
3989
  };
3985
3990
  })
3986
3991
  .filter(mood => !isNaN(mood.date.getTime()) &&
3987
- isFinite(mood.rating));
3992
+ isFinite(mood.rating))
3993
+ .sort((a, b) => a.date.getTime() - b.date.getTime());
3988
3994
  }, [moodData]);
3989
3995
  const colorScale = React.useMemo(() => {
3990
3996
  return d3__namespace.scaleLinear()
@@ -3997,6 +4003,13 @@ const MoodChart = ({ moodData, width = 800, height = 400 }) => {
3997
4003
  return;
3998
4004
  const svg = d3__namespace.select(svgRef.current);
3999
4005
  svg.selectAll('*').remove();
4006
+ const defs = svg.append('defs');
4007
+ const gradient = defs.append('linearGradient')
4008
+ .attr('id', gradientId)
4009
+ .attr('x1', '0%').attr('y1', '0%')
4010
+ .attr('x2', '0%').attr('y2', '100%');
4011
+ gradient.append('stop').attr('offset', '0%').attr('class', styles$9.areaStopTop);
4012
+ gradient.append('stop').attr('offset', '100%').attr('class', styles$9.areaStopBottom);
4000
4013
  const g = svg.append('g')
4001
4014
  .attr('transform', `translate(${margin.left},${margin.top})`);
4002
4015
  const extentDates = d3__namespace.extent(processedData, d => d.date);
@@ -4012,6 +4025,12 @@ const MoodChart = ({ moodData, width = 800, height = 400 }) => {
4012
4025
  .x(d => xScale(d.date))
4013
4026
  .y(d => yScale(d.rating))
4014
4027
  .curve(d3__namespace.curveMonotoneX);
4028
+ const area = d3__namespace.area()
4029
+ .x(d => xScale(d.date))
4030
+ .y0(chartHeight)
4031
+ .y1(d => yScale(d.rating))
4032
+ .curve(d3__namespace.curveMonotoneX);
4033
+ // Grid lines (fade in)
4015
4034
  g.selectAll('.grid-line-y')
4016
4035
  .data(yScale.ticks(5))
4017
4036
  .enter().append('line')
@@ -4019,70 +4038,210 @@ const MoodChart = ({ moodData, width = 800, height = 400 }) => {
4019
4038
  .attr('x1', 0)
4020
4039
  .attr('y1', d => yScale(d))
4021
4040
  .attr('x2', chartWidth)
4022
- .attr('y2', d => yScale(d));
4023
- g.append('path')
4024
- .datum(processedData)
4025
- .attr('class', styles$9.line)
4026
- .attr('d', line);
4041
+ .attr('y2', d => yScale(d))
4042
+ .style('opacity', 0)
4043
+ .transition()
4044
+ .duration(500)
4045
+ .ease(d3__namespace.easeCubicOut)
4046
+ .style('opacity', 1);
4047
+ // Axes (fade in)
4027
4048
  g.append('g')
4028
4049
  .attr('class', styles$9.xAxis)
4029
4050
  .attr('transform', `translate(0,${chartHeight})`)
4051
+ .style('opacity', 0)
4030
4052
  .call(d3__namespace.axisBottom(xScale)
4031
- .tickFormat(d => d3__namespace.timeFormat('%m/%d')(d)));
4053
+ .tickFormat(d => d3__namespace.timeFormat('%m/%d')(d)))
4054
+ .transition()
4055
+ .duration(600)
4056
+ .delay(100)
4057
+ .style('opacity', 1);
4032
4058
  g.append('g')
4033
4059
  .attr('class', styles$9.yAxis)
4034
- .call(d3__namespace.axisLeft(yScale));
4035
- g.selectAll('.mood-circle')
4060
+ .style('opacity', 0)
4061
+ .call(d3__namespace.axisLeft(yScale))
4062
+ .transition()
4063
+ .duration(600)
4064
+ .delay(100)
4065
+ .style('opacity', 1);
4066
+ // Area fill (fades in after line draws past it)
4067
+ const areaPath = g.append('path')
4068
+ .datum(processedData)
4069
+ .attr('class', styles$9.area)
4070
+ .attr('fill', `url(#${gradientId})`)
4071
+ .attr('d', area)
4072
+ .style('opacity', 0);
4073
+ // Line (draw-in animation via stroke-dasharray)
4074
+ const linePath = g.append('path')
4075
+ .datum(processedData)
4076
+ .attr('class', styles$9.line)
4077
+ .attr('d', line);
4078
+ const lineNode = linePath.node();
4079
+ const totalLength = lineNode && typeof lineNode.getTotalLength === 'function'
4080
+ ? lineNode.getTotalLength()
4081
+ : 0;
4082
+ const lineDuration = 1200;
4083
+ if (totalLength > 0) {
4084
+ linePath
4085
+ .attr('stroke-dasharray', `${totalLength} ${totalLength}`)
4086
+ .attr('stroke-dashoffset', totalLength)
4087
+ .transition()
4088
+ .duration(lineDuration)
4089
+ .ease(d3__namespace.easeCubicOut)
4090
+ .attr('stroke-dashoffset', 0)
4091
+ .on('end', () => {
4092
+ linePath.attr('stroke-dasharray', null);
4093
+ });
4094
+ }
4095
+ areaPath
4096
+ .transition()
4097
+ .delay(lineDuration * 0.4)
4098
+ .duration(800)
4099
+ .ease(d3__namespace.easeCubicOut)
4100
+ .style('opacity', 1);
4101
+ // Crosshair (vertical guide on hover)
4102
+ const crosshair = g.append('line')
4103
+ .attr('class', styles$9.crosshair)
4104
+ .attr('y1', 0)
4105
+ .attr('y2', chartHeight)
4106
+ .style('opacity', 0)
4107
+ .style('pointer-events', 'none');
4108
+ // Pulsing halo behind active point
4109
+ const halo = g.append('circle')
4110
+ .attr('class', styles$9.halo)
4111
+ .attr('r', 0)
4112
+ .style('opacity', 0)
4113
+ .style('pointer-events', 'none');
4114
+ // Data points (staggered entrance keyed to line draw)
4115
+ const minX = xScale(extentDates[0]);
4116
+ const maxX = xScale(extentDates[1]);
4117
+ const xRange = Math.max(1, maxX - minX);
4118
+ const pointSel = g.selectAll('.mood-circle')
4036
4119
  .data(processedData)
4037
4120
  .enter().append('circle')
4038
4121
  .attr('class', styles$9.dataPoint)
4039
4122
  .attr('cx', d => xScale(d.date))
4040
4123
  .attr('cy', d => yScale(d.rating))
4041
- .attr('r', 5)
4124
+ .attr('r', 0)
4042
4125
  .attr('fill', d => colorScale(d.rating))
4043
- .style('cursor', 'pointer')
4044
- .on('mouseenter', (event, d) => {
4126
+ .style('opacity', 0)
4127
+ .style('pointer-events', 'none');
4128
+ pointSel.transition()
4129
+ .delay(d => 100 + lineDuration * ((xScale(d.date) - minX) / xRange))
4130
+ .duration(380)
4131
+ .ease(d3__namespace.easeBackOut.overshoot(2))
4132
+ .attr('r', 5)
4133
+ .style('opacity', 1);
4134
+ const pointNodes = pointSel.nodes();
4135
+ // Active state lives in mutable refs (closure over redraw)
4136
+ let activeIndex = null;
4137
+ const startHaloPulse = (cx, cy, fill) => {
4138
+ halo
4139
+ .interrupt('halo-pulse')
4140
+ .interrupt('halo-out')
4141
+ .attr('cx', cx)
4142
+ .attr('cy', cy)
4143
+ .attr('fill', fill);
4144
+ const pulseOnce = () => {
4145
+ halo
4146
+ .attr('r', 5)
4147
+ .style('opacity', 0.55)
4148
+ .transition('halo-pulse')
4149
+ .duration(900)
4150
+ .ease(d3__namespace.easeCubicOut)
4151
+ .attr('r', 20)
4152
+ .style('opacity', 0)
4153
+ .on('end', pulseOnce);
4154
+ };
4155
+ pulseOnce();
4156
+ };
4157
+ const stopHaloPulse = () => {
4158
+ halo
4159
+ .interrupt('halo-pulse')
4160
+ .transition('halo-out')
4161
+ .duration(180)
4162
+ .style('opacity', 0)
4163
+ .attr('r', 0);
4164
+ };
4165
+ const setActive = (idx, clientX, clientY) => {
4166
+ const d = processedData[idx];
4167
+ if (!d)
4168
+ return;
4169
+ const cx = xScale(d.date);
4170
+ const cy = yScale(d.rating);
4045
4171
  const rect = svgRef.current?.getBoundingClientRect();
4046
- const containerRect = containerRef.current?.getBoundingClientRect();
4047
- if (rect && containerRect) {
4048
- let x = event.clientX - rect.left + 10;
4049
- let y = event.clientY - rect.top - 10;
4050
- // Check if tooltip would overflow on the right
4051
- const estimatedTooltipWidth = 250; // Approximate tooltip width
4052
- const rightEdgeBuffer = 20; // Buffer from the right edge
4053
- if (x + estimatedTooltipWidth > chartWidth + margin.left - rightEdgeBuffer) {
4054
- // Position tooltip to the left of the cursor, but keep it close
4055
- x = event.clientX - rect.left - estimatedTooltipWidth - 10;
4056
- // Ensure it doesn't go off the left edge
4057
- if (x < 0) {
4172
+ if (rect) {
4173
+ let x = clientX - rect.left + 12;
4174
+ let y = clientY - rect.top - 12;
4175
+ const estW = 280;
4176
+ if (x + estW > chartWidth + margin.left - 20) {
4177
+ x = clientX - rect.left - estW - 12;
4178
+ if (x < 0)
4058
4179
  x = 10;
4059
- }
4060
4180
  }
4061
- // Ensure tooltip doesn't go above the container
4062
- if (y < 0) {
4181
+ if (y < 0)
4063
4182
  y = 10;
4064
- }
4065
4183
  setTooltipPosition({ x, y });
4066
4184
  }
4067
4185
  setSelectedMood(d);
4068
- d3__namespace.select(event.currentTarget)
4069
- .transition()
4070
- .duration(200)
4071
- .attr('r', 8);
4186
+ crosshair
4187
+ .attr('x1', cx).attr('x2', cx)
4188
+ .interrupt('crosshair-fade')
4189
+ .transition('crosshair-fade')
4190
+ .duration(120)
4191
+ .style('opacity', 1);
4192
+ if (activeIndex !== idx) {
4193
+ if (activeIndex !== null) {
4194
+ d3__namespace.select(pointNodes[activeIndex])
4195
+ .transition('point-scale')
4196
+ .duration(180)
4197
+ .ease(d3__namespace.easeCubicOut)
4198
+ .attr('r', 5);
4199
+ }
4200
+ d3__namespace.select(pointNodes[idx])
4201
+ .transition('point-scale')
4202
+ .duration(180)
4203
+ .ease(d3__namespace.easeBackOut.overshoot(2))
4204
+ .attr('r', 8);
4205
+ startHaloPulse(cx, cy, colorScale(d.rating));
4206
+ activeIndex = idx;
4207
+ }
4208
+ };
4209
+ const clearActive = () => {
4210
+ crosshair
4211
+ .interrupt('crosshair-fade')
4212
+ .transition('crosshair-fade')
4213
+ .duration(180)
4214
+ .style('opacity', 0);
4215
+ if (activeIndex !== null) {
4216
+ d3__namespace.select(pointNodes[activeIndex])
4217
+ .transition('point-scale')
4218
+ .duration(180)
4219
+ .attr('r', 5);
4220
+ activeIndex = null;
4221
+ }
4222
+ stopHaloPulse();
4223
+ setSelectedMood(null);
4224
+ };
4225
+ // Overlay captures mouse for nearest-point lookup (rendered last so it sits on top)
4226
+ const bisect = d3__namespace.bisector(d => d.date).center;
4227
+ g.append('rect')
4228
+ .attr('class', styles$9.overlay)
4229
+ .attr('width', chartWidth)
4230
+ .attr('height', chartHeight)
4231
+ .on('mousemove', function (event) {
4232
+ const [mx] = d3__namespace.pointer(event, this);
4233
+ const xDate = xScale.invert(mx);
4234
+ const idx = Math.max(0, Math.min(processedData.length - 1, bisect(processedData, xDate)));
4235
+ setActive(idx, event.clientX, event.clientY);
4072
4236
  })
4073
- .on('mouseleave', (event) => {
4074
- // Add delay to allow mouse to move to tooltip
4075
- setTimeout(() => {
4076
- if (!isHoveringTooltip) {
4077
- setSelectedMood(null);
4237
+ .on('mouseleave', () => {
4238
+ window.setTimeout(() => {
4239
+ if (!isHoveringTooltipRef.current) {
4240
+ clearActive();
4078
4241
  }
4079
- }, 250);
4080
- d3__namespace.select(event.currentTarget)
4081
- .transition()
4082
- .duration(200)
4083
- .attr('r', 5);
4242
+ }, 220);
4084
4243
  });
4085
- }, [processedData, chartWidth, chartHeight, colorScale, margin, isHoveringTooltip]);
4244
+ }, [processedData, chartWidth, chartHeight, colorScale, margin, gradientId]);
4086
4245
  // Clean up tooltip on unmount
4087
4246
  React.useEffect(() => {
4088
4247
  return () => {
@@ -4101,9 +4260,8 @@ const MoodChart = ({ moodData, width = 800, height = 400 }) => {
4101
4260
  }, children: [jsxRuntime.jsxs("div", { className: styles$9.tooltipHeader, children: [jsxRuntime.jsx("div", { className: styles$9.tooltipDate, children: selectedMood.date.toLocaleDateString() }), jsxRuntime.jsxs("div", { className: styles$9.tooltipRating, children: [jsxRuntime.jsx("span", { className: styles$9.ratingValue, children: selectedMood.rating }), jsxRuntime.jsx("span", { className: styles$9.ratingMax, children: "/10" })] })] }), selectedMood.tags.length > 0 && (jsxRuntime.jsx("div", { className: styles$9.tooltipTags, children: selectedMood.tags.map((tag, index) => (jsxRuntime.jsx("span", { className: styles$9.tag, children: tag }, index))) })), selectedMood.comment && (jsxRuntime.jsx("div", { className: styles$9.tooltipComment, children: selectedMood.comment }))] }))] }));
4102
4261
  };
4103
4262
 
4104
- var styles$8 = {"container":"QuantifiableHabitsChart-module_container__X5SBp","controls":"QuantifiableHabitsChart-module_controls__O-ObQ","viewToggle":"QuantifiableHabitsChart-module_viewToggle__24hKA","viewButton":"QuantifiableHabitsChart-module_viewButton__WFU6j","active":"QuantifiableHabitsChart-module_active__Pjqy9","viewIcon":"QuantifiableHabitsChart-module_viewIcon__b2mfk","viewLabel":"QuantifiableHabitsChart-module_viewLabel__9MjCU","aggregationToggle":"QuantifiableHabitsChart-module_aggregationToggle__WnxwB","aggregationButton":"QuantifiableHabitsChart-module_aggregationButton__sGCxX","aggregationIcon":"QuantifiableHabitsChart-module_aggregationIcon__HIaEf","aggregationLabel":"QuantifiableHabitsChart-module_aggregationLabel__Yc-S-","legend":"QuantifiableHabitsChart-module_legend__3Ki7c","compactLegend":"QuantifiableHabitsChart-module_compactLegend__jMpLB","legendItem":"QuantifiableHabitsChart-module_legendItem__Zl7fz","legendEmoji":"QuantifiableHabitsChart-module_legendEmoji__HG9CZ","legendLabel":"QuantifiableHabitsChart-module_legendLabel__H3oFL","inactive":"QuantifiableHabitsChart-module_inactive__TzZC-","legendColor":"QuantifiableHabitsChart-module_legendColor__zbPoV","chart":"QuantifiableHabitsChart-module_chart__FMeA-","gridLine":"QuantifiableHabitsChart-module_gridLine__CTNIq","line":"QuantifiableHabitsChart-module_line__CpYip","xAxis":"QuantifiableHabitsChart-module_xAxis__lbgBG","yAxis":"QuantifiableHabitsChart-module_yAxis__Y6WeV","dataPoint":"QuantifiableHabitsChart-module_dataPoint__s8UMX","tooltip":"QuantifiableHabitsChart-module_tooltip__Fay8N","visible":"QuantifiableHabitsChart-module_visible__-KSJq","tooltipHeader":"QuantifiableHabitsChart-module_tooltipHeader__7Q2up","tooltipEmoji":"QuantifiableHabitsChart-module_tooltipEmoji__atV3T","tooltipDot":"QuantifiableHabitsChart-module_tooltipDot__YbdFh","tooltipInfo":"QuantifiableHabitsChart-module_tooltipInfo__XC7WF","tooltipDate":"QuantifiableHabitsChart-module_tooltipDate__6V6Xi","tooltipValue":"QuantifiableHabitsChart-module_tooltipValue__ldASB"};
4263
+ var styles$8 = {"container":"QuantifiableHabitsChart-module_container__X5SBp","controls":"QuantifiableHabitsChart-module_controls__O-ObQ","viewToggle":"QuantifiableHabitsChart-module_viewToggle__24hKA","viewButton":"QuantifiableHabitsChart-module_viewButton__WFU6j","active":"QuantifiableHabitsChart-module_active__Pjqy9","viewIcon":"QuantifiableHabitsChart-module_viewIcon__b2mfk","viewLabel":"QuantifiableHabitsChart-module_viewLabel__9MjCU","aggregationToggle":"QuantifiableHabitsChart-module_aggregationToggle__WnxwB","aggregationButton":"QuantifiableHabitsChart-module_aggregationButton__sGCxX","aggregationIcon":"QuantifiableHabitsChart-module_aggregationIcon__HIaEf","aggregationLabel":"QuantifiableHabitsChart-module_aggregationLabel__Yc-S-","legend":"QuantifiableHabitsChart-module_legend__3Ki7c","compactLegend":"QuantifiableHabitsChart-module_compactLegend__jMpLB","legendItem":"QuantifiableHabitsChart-module_legendItem__Zl7fz","legendEmoji":"QuantifiableHabitsChart-module_legendEmoji__HG9CZ","legendLabel":"QuantifiableHabitsChart-module_legendLabel__H3oFL","inactive":"QuantifiableHabitsChart-module_inactive__TzZC-","legendColor":"QuantifiableHabitsChart-module_legendColor__zbPoV","chart":"QuantifiableHabitsChart-module_chart__FMeA-","gridLine":"QuantifiableHabitsChart-module_gridLine__CTNIq","line":"QuantifiableHabitsChart-module_line__CpYip","crosshair":"QuantifiableHabitsChart-module_crosshair__7hoFL","halo":"QuantifiableHabitsChart-module_halo__YlkOF","overlay":"QuantifiableHabitsChart-module_overlay__ffeNz","xAxis":"QuantifiableHabitsChart-module_xAxis__lbgBG","yAxis":"QuantifiableHabitsChart-module_yAxis__Y6WeV","dataPoint":"QuantifiableHabitsChart-module_dataPoint__s8UMX","tooltip":"QuantifiableHabitsChart-module_tooltip__Fay8N","visible":"QuantifiableHabitsChart-module_visible__-KSJq","tooltipHeader":"QuantifiableHabitsChart-module_tooltipHeader__7Q2up","tooltipEmoji":"QuantifiableHabitsChart-module_tooltipEmoji__atV3T","tooltipDot":"QuantifiableHabitsChart-module_tooltipDot__YbdFh","tooltipInfo":"QuantifiableHabitsChart-module_tooltipInfo__XC7WF","tooltipDate":"QuantifiableHabitsChart-module_tooltipDate__6V6Xi","tooltipValue":"QuantifiableHabitsChart-module_tooltipValue__ldASB"};
4105
4264
 
4106
- // Default colors as fallback
4107
4265
  const DEFAULT_HABIT_COLORS$1 = {
4108
4266
  'Exercise': '#6BCB77',
4109
4267
  'Meditation': '#4D96FF',
@@ -4114,14 +4272,53 @@ const DEFAULT_HABIT_COLORS$1 = {
4114
4272
  'Calories': '#FF9F1C',
4115
4273
  'Study': '#C774E8'
4116
4274
  };
4275
+ // Smoothly interpolate between two SVG path strings by resampling both
4276
+ // at evenly-spaced arc-length positions and tweening corresponding points.
4277
+ const SVG_NS = 'http://www.w3.org/2000/svg';
4278
+ const pathTween = (oldD, newD, samples = 80) => {
4279
+ const safeOld = oldD && oldD.length > 0 ? oldD : 'M0,0';
4280
+ const safeNew = newD && newD.length > 0 ? newD : 'M0,0';
4281
+ const oldNode = document.createElementNS(SVG_NS, 'path');
4282
+ const newNode = document.createElementNS(SVG_NS, 'path');
4283
+ oldNode.setAttribute('d', safeOld);
4284
+ newNode.setAttribute('d', safeNew);
4285
+ const oldLen = typeof oldNode.getTotalLength === 'function' ? oldNode.getTotalLength() : 0;
4286
+ const newLen = typeof newNode.getTotalLength === 'function' ? newNode.getTotalLength() : 0;
4287
+ if (oldLen === 0 || newLen === 0) {
4288
+ return () => safeNew;
4289
+ }
4290
+ const old = [];
4291
+ const next = [];
4292
+ for (let i = 0; i < samples; i++) {
4293
+ const u = samples === 1 ? 0 : i / (samples - 1);
4294
+ const op = oldNode.getPointAtLength(u * oldLen);
4295
+ const np = newNode.getPointAtLength(u * newLen);
4296
+ old.push([op.x, op.y]);
4297
+ next.push([np.x, np.y]);
4298
+ }
4299
+ return (t) => {
4300
+ let s = '';
4301
+ for (let i = 0; i < samples; i++) {
4302
+ const x = old[i][0] + (next[i][0] - old[i][0]) * t;
4303
+ const y = old[i][1] + (next[i][1] - old[i][1]) * t;
4304
+ s += (i === 0 ? 'M' : 'L') + x + ',' + y;
4305
+ }
4306
+ return s;
4307
+ };
4308
+ };
4117
4309
  const QuantifiableHabitsChart = ({ data, width = 800, height = 400, defaultViewType = 'daily', periodType = 'month', habitColors: customHabitColors = {}, habitEmojis: customHabitEmojis = {}, onDataPointClick, hideControls = false, compactLegend = false }) => {
4118
4310
  const svgRef = React.useRef(null);
4119
4311
  const tooltipRef = React.useRef(null);
4312
+ const onClickRef = React.useRef(onDataPointClick);
4313
+ const hasMountedRef = React.useRef(false);
4120
4314
  const [viewType, setViewType] = React.useState(defaultViewType);
4121
4315
  const [activeHabits, setActiveHabits] = React.useState([]);
4122
4316
  const [hoveredHabit, setHoveredHabit] = React.useState(null);
4123
4317
  const [tooltipData, setTooltipData] = React.useState(null);
4124
4318
  const [aggregationMode, setAggregationMode] = React.useState('average');
4319
+ React.useEffect(() => {
4320
+ onClickRef.current = onDataPointClick;
4321
+ }, [onDataPointClick]);
4125
4322
  const margin = React.useMemo(() => ({ top: 20, right: 20, bottom: 50, left: 50 }), []);
4126
4323
  const chartWidth = width - margin.left - margin.right;
4127
4324
  const chartHeight = height - margin.top - margin.bottom;
@@ -4129,7 +4326,6 @@ const QuantifiableHabitsChart = ({ data, width = 800, height = 400, defaultViewT
4129
4326
  React.useEffect(() => {
4130
4327
  setActiveHabits(habits);
4131
4328
  }, [habits]);
4132
- // Hide tooltip on scroll
4133
4329
  React.useEffect(() => {
4134
4330
  const handleScroll = () => {
4135
4331
  setTooltipData(null);
@@ -4156,39 +4352,32 @@ const QuantifiableHabitsChart = ({ data, width = 800, height = 400, defaultViewT
4156
4352
  }
4157
4353
  }, [periodType]);
4158
4354
  const getColor = React.useCallback((habit) => {
4159
- // First check custom colors, then defaults, then generate deterministic color
4160
4355
  return customHabitColors[habit] || DEFAULT_HABIT_COLORS$1[habit] || `hsl(${Math.abs(habit.split('').reduce((a, b) => a + b.charCodeAt(0), 0)) % 360}, 70%, 50%)`;
4161
4356
  }, [customHabitColors]);
4162
- // Aggregate data based on view type
4163
4357
  const aggregateData = React.useMemo(() => {
4164
4358
  if (viewType === 'daily' || !data.dates.length) {
4165
4359
  return data;
4166
4360
  }
4167
4361
  const aggregated = { dates: [] };
4168
4362
  const dateGroups = new Map();
4169
- // Group dates by period
4170
4363
  data.dates.forEach((dateStr, index) => {
4171
4364
  const date = new Date(dateStr);
4172
4365
  let groupKey;
4173
4366
  switch (viewType) {
4174
4367
  case 'weekly': {
4175
- // Get ISO week start (Monday)
4176
4368
  const weekStart = new Date(date);
4177
4369
  const day = weekStart.getDay();
4178
4370
  const diff = weekStart.getDate() - day + (day === 0 ? -6 : 1);
4179
4371
  weekStart.setDate(diff);
4180
- // Use the Monday date as the group key to ensure proper sorting
4181
4372
  groupKey = weekStart.toISOString().split('T')[0];
4182
4373
  break;
4183
4374
  }
4184
4375
  case 'monthly':
4185
- // Use first day of month for consistent sorting
4186
4376
  groupKey = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-01`;
4187
4377
  break;
4188
4378
  case 'quarterly': {
4189
4379
  const quarter = Math.floor(date.getMonth() / 3) + 1;
4190
4380
  const quarterStartMonth = (quarter - 1) * 3;
4191
- // Use first day of quarter for consistent sorting and grouping
4192
4381
  const quarterStart = new Date(date.getFullYear(), quarterStartMonth, 1);
4193
4382
  groupKey = quarterStart.toISOString().split('T')[0];
4194
4383
  break;
@@ -4201,7 +4390,6 @@ const QuantifiableHabitsChart = ({ data, width = 800, height = 400, defaultViewT
4201
4390
  }
4202
4391
  dateGroups.get(groupKey).push(index);
4203
4392
  });
4204
- // Calculate aggregated values - sort dates for proper chronological order
4205
4393
  aggregated.dates = Array.from(dateGroups.keys()).sort();
4206
4394
  habits.forEach(habit => {
4207
4395
  aggregated[habit] = aggregated.dates.map(groupKey => {
@@ -4211,11 +4399,10 @@ const QuantifiableHabitsChart = ({ data, width = 800, height = 400, defaultViewT
4211
4399
  .filter(v => typeof v === 'number' && !isNaN(v));
4212
4400
  if (values.length === 0)
4213
4401
  return 0;
4214
- // Calculate aggregation based on mode
4215
4402
  if (aggregationMode === 'sum') {
4216
4403
  return Math.round(values.reduce((sum, v) => sum + v, 0));
4217
4404
  }
4218
- else { // average
4405
+ else {
4219
4406
  return Math.round(values.reduce((sum, v) => sum + v, 0) / values.length);
4220
4407
  }
4221
4408
  });
@@ -4231,98 +4418,53 @@ const QuantifiableHabitsChart = ({ data, width = 800, height = 400, defaultViewT
4231
4418
  if (!svgRef.current || aggregateData.dates.length === 0)
4232
4419
  return;
4233
4420
  const svg = d3__namespace.select(svgRef.current);
4234
- svg.selectAll('*').remove();
4235
- // Add invisible rect to detect mouse leave events
4236
- svg.append('rect')
4237
- .attr('width', width)
4238
- .attr('height', height)
4239
- .attr('fill', 'transparent')
4240
- .style('pointer-events', 'all')
4241
- .on('mouseleave', () => {
4242
- setTooltipData(null);
4243
- });
4244
- const g = svg.append('g')
4245
- .attr('transform', `translate(${margin.left},${margin.top})`);
4421
+ const isFirstRender = !hasMountedRef.current;
4422
+ hasMountedRef.current = true;
4423
+ // Acquire/create persistent root group + sub-groups
4424
+ let root = svg.select('g.qhc-root');
4425
+ if (root.empty()) {
4426
+ root = svg.append('g').attr('class', 'qhc-root');
4427
+ }
4428
+ root.attr('transform', `translate(${margin.left},${margin.top})`);
4429
+ const ensureGroup = (cls) => {
4430
+ let s = root.select(`g.${cls}`);
4431
+ if (s.empty())
4432
+ s = root.append('g').attr('class', cls);
4433
+ return s;
4434
+ };
4435
+ const gridGroup = ensureGroup('qhc-grid');
4436
+ const linesGroup = ensureGroup('qhc-lines');
4437
+ const pointsGroup = ensureGroup('qhc-points');
4438
+ const axesGroup = ensureGroup('qhc-axes');
4439
+ const uiGroup = ensureGroup('qhc-ui');
4246
4440
  const dates = aggregateData.dates.map(d => new Date(d));
4247
4441
  const xScale = d3__namespace.scaleTime()
4248
4442
  .domain(d3__namespace.extent(dates))
4249
4443
  .range([0, chartWidth]);
4250
- const maxValue = Math.max(...activeHabits.flatMap(habit => aggregateData[habit].filter(v => typeof v === 'number')));
4444
+ const maxValue = Math.max(1, ...activeHabits.flatMap(habit => aggregateData[habit].filter(v => typeof v === 'number')));
4251
4445
  const yScale = d3__namespace.scaleLinear()
4252
4446
  .domain([0, maxValue * 1.1])
4253
4447
  .range([chartHeight, 0]);
4254
- g.selectAll('.grid-line-y')
4255
- .data(yScale.ticks(5))
4256
- .enter().append('line')
4257
- .attr('class', styles$8.gridLine)
4258
- .attr('x1', 0)
4259
- .attr('y1', d => yScale(d))
4260
- .attr('x2', chartWidth)
4261
- .attr('y2', d => yScale(d));
4262
- const line = d3__namespace.line()
4448
+ const lineGen = d3__namespace.line()
4263
4449
  .x(d => xScale(d[0]))
4264
4450
  .y(d => yScale(d[1]))
4265
4451
  .curve(d3__namespace.curveMonotoneX);
4266
- activeHabits.forEach(habit => {
4267
- const habitData = dates.map((date, i) => [date, aggregateData[habit][i]]).filter(d => typeof d[1] === 'number');
4268
- g.append('path')
4269
- .datum(habitData)
4270
- .attr('class', styles$8.line)
4271
- .attr('d', line)
4272
- .attr('stroke', getColor(habit))
4273
- .attr('opacity', hoveredHabit && hoveredHabit !== habit ? 0.3 : 1);
4274
- // Add invisible larger circles for better hover detection
4275
- g.selectAll(`.hover-circle-${habit}`)
4276
- .data(habitData)
4277
- .enter().append('circle')
4278
- .attr('cx', d => xScale(d[0]))
4279
- .attr('cy', d => yScale(d[1]))
4280
- .attr('r', 10) // Larger invisible area
4281
- .attr('fill', 'transparent')
4282
- .style('cursor', 'pointer')
4283
- .on('mouseenter', function (_event, d) {
4284
- const [date, value] = d;
4285
- const rect = svgRef.current?.getBoundingClientRect();
4286
- if (rect) {
4287
- setTooltipData({
4288
- habit,
4289
- date: date.toISOString().split('T')[0],
4290
- value,
4291
- x: xScale(date) + margin.left + rect.left,
4292
- y: yScale(value) + margin.top + rect.top
4293
- });
4294
- }
4295
- // Find and enlarge the visible circle
4296
- d3__namespace.select(g.node())
4297
- .selectAll(`.circle-${habit}-${dates.indexOf(date)}`)
4298
- .attr('r', 6);
4299
- })
4300
- .on('mouseleave', function (_event, _d) {
4301
- setTooltipData(null);
4302
- // Reset all circles for this habit
4303
- d3__namespace.select(g.node())
4304
- .selectAll('[class*="circle-' + habit + '"]')
4305
- .attr('r', 4);
4306
- })
4307
- .on('click', function (_event, d) {
4308
- const [date, value] = d;
4309
- if (onDataPointClick) {
4310
- onDataPointClick(habit, date.toISOString().split('T')[0], value);
4311
- }
4312
- });
4313
- // Add visible circles
4314
- g.selectAll(`.circle-${habit}`)
4315
- .data(habitData)
4316
- .enter().append('circle')
4317
- .attr('class', (_d, i) => `${styles$8.dataPoint} circle-${habit}-${i}`)
4318
- .attr('cx', d => xScale(d[0]))
4319
- .attr('cy', d => yScale(d[1]))
4320
- .attr('r', 4)
4321
- .attr('fill', getColor(habit))
4322
- .attr('opacity', hoveredHabit && hoveredHabit !== habit ? 0.3 : 1)
4323
- .style('pointer-events', 'none'); // Let the invisible circle handle events
4324
- });
4325
- // Helper function to get ISO week number
4452
+ // -------- Grid --------
4453
+ const gridSel = gridGroup.selectAll('line.qhc-grid-line')
4454
+ .data(yScale.ticks(5), d => String(d));
4455
+ gridSel.exit().remove();
4456
+ const gridEnter = gridSel.enter().append('line')
4457
+ .attr('class', `${styles$8.gridLine} qhc-grid-line`)
4458
+ .style('opacity', 0);
4459
+ gridEnter.merge(gridSel)
4460
+ .attr('x1', 0)
4461
+ .attr('x2', chartWidth)
4462
+ .attr('y1', d => yScale(d))
4463
+ .attr('y2', d => yScale(d))
4464
+ .transition()
4465
+ .duration(400)
4466
+ .style('opacity', 1);
4467
+ // -------- Axes --------
4326
4468
  const getISOWeek = (date) => {
4327
4469
  const d = new Date(date);
4328
4470
  d.setHours(0, 0, 0, 0);
@@ -4330,28 +4472,20 @@ const QuantifiableHabitsChart = ({ data, width = 800, height = 400, defaultViewT
4330
4472
  const week1 = new Date(d.getFullYear(), 0, 4);
4331
4473
  return 1 + Math.round(((d.getTime() - week1.getTime()) / 86400000 - 3 + (week1.getDay() + 6) % 7) / 7);
4332
4474
  };
4333
- // Format x-axis based on view type
4334
4475
  const xAxisFormat = (() => {
4335
4476
  switch (viewType) {
4336
4477
  case 'daily':
4337
4478
  return d3__namespace.timeFormat('%m-%d');
4338
4479
  case 'weekly':
4339
- return (d) => {
4340
- const weekNum = getISOWeek(d);
4341
- return `W${weekNum.toString().padStart(2, '0')}`;
4342
- };
4480
+ return (d) => `W${getISOWeek(d).toString().padStart(2, '0')}`;
4343
4481
  case 'monthly':
4344
4482
  return d3__namespace.timeFormat('%b');
4345
4483
  case 'quarterly':
4346
- return (d) => {
4347
- const quarter = Math.floor(d.getMonth() / 3) + 1;
4348
- return `Q${quarter}`;
4349
- };
4484
+ return (d) => `Q${Math.floor(d.getMonth() / 3) + 1}`;
4350
4485
  default:
4351
4486
  return d3__namespace.timeFormat('%m-%d');
4352
4487
  }
4353
4488
  })();
4354
- // Determine number of ticks based on view type and data
4355
4489
  const tickCount = (() => {
4356
4490
  switch (viewType) {
4357
4491
  case 'daily':
@@ -4361,47 +4495,278 @@ const QuantifiableHabitsChart = ({ data, width = 800, height = 400, defaultViewT
4361
4495
  case 'monthly':
4362
4496
  return Math.min(12, aggregateData.dates.length);
4363
4497
  case 'quarterly':
4364
- return aggregateData.dates.length; // Show all quarters
4498
+ return aggregateData.dates.length;
4365
4499
  default:
4366
4500
  return undefined;
4367
4501
  }
4368
4502
  })();
4369
4503
  const xAxisGenerator = d3__namespace.axisBottom(xScale)
4370
4504
  .tickFormat(d => xAxisFormat(d));
4371
- // Set tick values for quarterly to avoid duplicates
4372
4505
  if (viewType === 'quarterly') {
4373
4506
  xAxisGenerator.tickValues(dates);
4374
4507
  }
4375
4508
  else if (tickCount) {
4376
4509
  xAxisGenerator.ticks(tickCount);
4377
4510
  }
4378
- const xAxis = g.append('g')
4379
- .attr('class', styles$8.xAxis)
4380
- .attr('transform', `translate(0,${chartHeight})`)
4381
- .call(xAxisGenerator);
4382
- // Rotate labels for better readability if needed
4383
- if (viewType === 'daily' || viewType === 'weekly') {
4384
- xAxis.selectAll('text')
4385
- .style('text-anchor', 'end')
4386
- .attr('dx', '-.8em')
4387
- .attr('dy', '.15em')
4388
- .attr('transform', 'rotate(-45)');
4389
- }
4390
- g.append('g')
4391
- .attr('class', styles$8.yAxis)
4392
- .call(d3__namespace.axisLeft(yScale));
4393
- }, [aggregateData, activeHabits, chartWidth, chartHeight, margin, hoveredHabit, onDataPointClick, getColor, height, viewType, width]);
4394
- // Format date for tooltip display
4511
+ let xAxis = axesGroup.select('g.qhc-x-axis');
4512
+ if (xAxis.empty()) {
4513
+ xAxis = axesGroup.append('g').attr('class', `${styles$8.xAxis} qhc-x-axis`);
4514
+ }
4515
+ xAxis.attr('transform', `translate(0,${chartHeight})`).call(xAxisGenerator);
4516
+ xAxis.selectAll('text')
4517
+ .style('text-anchor', viewType === 'daily' || viewType === 'weekly' ? 'end' : 'middle')
4518
+ .attr('dx', viewType === 'daily' || viewType === 'weekly' ? '-.8em' : '0')
4519
+ .attr('dy', viewType === 'daily' || viewType === 'weekly' ? '.15em' : '.71em')
4520
+ .attr('transform', viewType === 'daily' || viewType === 'weekly' ? 'rotate(-45)' : null);
4521
+ let yAxis = axesGroup.select('g.qhc-y-axis');
4522
+ if (yAxis.empty()) {
4523
+ yAxis = axesGroup.append('g').attr('class', `${styles$8.yAxis} qhc-y-axis`);
4524
+ }
4525
+ yAxis.call(d3__namespace.axisLeft(yScale));
4526
+ if (isFirstRender) {
4527
+ xAxis.style('opacity', 0).transition().duration(500).delay(80).style('opacity', 1);
4528
+ yAxis.style('opacity', 0).transition().duration(500).delay(80).style('opacity', 1);
4529
+ }
4530
+ // -------- Lines (data join, morph on update) --------
4531
+ const lineData = activeHabits.map(habit => {
4532
+ const points = dates
4533
+ .map((date, i) => [date, aggregateData[habit][i]])
4534
+ .filter(d => typeof d[1] === 'number');
4535
+ return { habit, color: getColor(habit), points };
4536
+ });
4537
+ const lineSel = linesGroup.selectAll('path.qhc-line')
4538
+ .data(lineData, (d) => d.habit);
4539
+ lineSel.exit()
4540
+ .transition('line-exit')
4541
+ .duration(300)
4542
+ .style('opacity', 0)
4543
+ .remove();
4544
+ const lineEnter = lineSel.enter().append('path')
4545
+ .attr('class', `${styles$8.line} qhc-line`)
4546
+ .attr('data-habit', d => d.habit)
4547
+ .attr('fill', 'none')
4548
+ .attr('stroke', d => d.color)
4549
+ .attr('opacity', 0)
4550
+ .attr('d', d => lineGen(d.points) || '')
4551
+ .each(function () {
4552
+ const node = this;
4553
+ const len = typeof node.getTotalLength === 'function' ? node.getTotalLength() : 0;
4554
+ if (len > 0) {
4555
+ d3__namespace.select(node)
4556
+ .attr('stroke-dasharray', `${len} ${len}`)
4557
+ .attr('stroke-dashoffset', len);
4558
+ }
4559
+ });
4560
+ lineEnter.transition('line-enter')
4561
+ .duration(900)
4562
+ .ease(d3__namespace.easeCubicOut)
4563
+ .attr('opacity', 1)
4564
+ .attr('stroke-dashoffset', 0)
4565
+ .on('end', function () {
4566
+ d3__namespace.select(this).attr('stroke-dasharray', null);
4567
+ });
4568
+ lineSel.transition('line-update')
4569
+ .duration(700)
4570
+ .ease(d3__namespace.easeCubicInOut)
4571
+ .attr('stroke', d => d.color)
4572
+ .attrTween('d', function (d) {
4573
+ const oldD = d3__namespace.select(this).attr('d') || '';
4574
+ const newD = lineGen(d.points) || '';
4575
+ return pathTween(oldD, newD, 90);
4576
+ })
4577
+ .on('end', function (d) {
4578
+ d3__namespace.select(this).attr('d', lineGen(d.points) || '');
4579
+ });
4580
+ // -------- Points --------
4581
+ // Clear and re-add (simpler than join when both habit set + count change).
4582
+ // Hide them during line morph, then spring up from baseline.
4583
+ pointsGroup.selectAll('*').remove();
4584
+ const allPoints = [];
4585
+ activeHabits.forEach(habit => {
4586
+ const color = getColor(habit);
4587
+ dates.forEach((date, i) => {
4588
+ const v = aggregateData[habit][i];
4589
+ if (typeof v === 'number' && !isNaN(v)) {
4590
+ allPoints.push({ habit, color, date, value: v });
4591
+ }
4592
+ });
4593
+ });
4594
+ const minX = xScale(dates[0]);
4595
+ const maxX = xScale(dates[dates.length - 1]);
4596
+ const xRange = Math.max(1, maxX - minX);
4597
+ const pointAppearDelay = isFirstRender ? 100 : 350;
4598
+ const pointAppearTotal = isFirstRender ? 1100 : 600;
4599
+ pointsGroup.selectAll('circle.qhc-point')
4600
+ .data(allPoints)
4601
+ .enter().append('circle')
4602
+ .attr('class', `${styles$8.dataPoint} qhc-point`)
4603
+ .attr('data-habit', d => d.habit)
4604
+ .attr('cx', d => xScale(d.date))
4605
+ .attr('cy', chartHeight)
4606
+ .attr('r', 0)
4607
+ .attr('fill', d => d.color)
4608
+ .style('opacity', 0)
4609
+ .transition('point-enter')
4610
+ .delay(d => pointAppearDelay + pointAppearTotal * ((xScale(d.date) - minX) / xRange))
4611
+ .duration(420)
4612
+ .ease(d3__namespace.easeBackOut.overshoot(2))
4613
+ .attr('cy', d => yScale(d.value))
4614
+ .attr('r', 4)
4615
+ .style('opacity', 1);
4616
+ // -------- UI layer (crosshair, halo, overlay) --------
4617
+ uiGroup.selectAll('*').remove();
4618
+ const crosshair = uiGroup.append('line')
4619
+ .attr('class', styles$8.crosshair)
4620
+ .attr('y1', 0)
4621
+ .attr('y2', chartHeight)
4622
+ .style('opacity', 0)
4623
+ .style('pointer-events', 'none');
4624
+ const halo = uiGroup.append('circle')
4625
+ .attr('class', styles$8.halo)
4626
+ .attr('r', 0)
4627
+ .style('opacity', 0)
4628
+ .style('pointer-events', 'none');
4629
+ let activeKey = null;
4630
+ const startHaloPulse = (cx, cy, fill) => {
4631
+ halo.interrupt('halo-pulse').interrupt('halo-out')
4632
+ .attr('cx', cx).attr('cy', cy).attr('fill', fill);
4633
+ const pulseOnce = () => {
4634
+ halo.attr('r', 4).style('opacity', 0.55)
4635
+ .transition('halo-pulse').duration(900).ease(d3__namespace.easeCubicOut)
4636
+ .attr('r', 18).style('opacity', 0)
4637
+ .on('end', pulseOnce);
4638
+ };
4639
+ pulseOnce();
4640
+ };
4641
+ const stopHaloPulse = () => {
4642
+ halo.interrupt('halo-pulse')
4643
+ .transition('halo-out').duration(180)
4644
+ .style('opacity', 0).attr('r', 0);
4645
+ };
4646
+ const activeAll = allPoints.map(p => ({
4647
+ habit: p.habit,
4648
+ date: p.date,
4649
+ value: p.value,
4650
+ x: xScale(p.date),
4651
+ y: yScale(p.value)
4652
+ }));
4653
+ const setActive = (pt, clientX, clientY) => {
4654
+ const key = `${pt.habit}|${pt.date.toISOString()}`;
4655
+ const color = getColor(pt.habit);
4656
+ crosshair.attr('x1', pt.x).attr('x2', pt.x)
4657
+ .interrupt('crosshair-fade')
4658
+ .transition('crosshair-fade').duration(120).style('opacity', 1);
4659
+ if (activeKey !== key) {
4660
+ pointsGroup.selectAll('circle.qhc-point')
4661
+ .filter(function () { return d3__namespace.select(this).attr('data-active') === 'true'; })
4662
+ .attr('data-active', null)
4663
+ .transition('point-scale').duration(150).attr('r', 4);
4664
+ pointsGroup.selectAll('circle.qhc-point')
4665
+ .filter(function () {
4666
+ const cx = +d3__namespace.select(this).attr('cx');
4667
+ const cy = +d3__namespace.select(this).attr('cy');
4668
+ const habit = d3__namespace.select(this).attr('data-habit');
4669
+ return habit === pt.habit && Math.abs(cx - pt.x) < 0.5 && Math.abs(cy - pt.y) < 0.5;
4670
+ })
4671
+ .attr('data-active', 'true')
4672
+ .transition('point-scale').duration(180).ease(d3__namespace.easeBackOut.overshoot(2))
4673
+ .attr('r', 7);
4674
+ startHaloPulse(pt.x, pt.y, color);
4675
+ activeKey = key;
4676
+ }
4677
+ setTooltipData({
4678
+ habit: pt.habit,
4679
+ date: pt.date.toISOString().split('T')[0],
4680
+ value: pt.value,
4681
+ x: clientX,
4682
+ y: clientY
4683
+ });
4684
+ };
4685
+ const clearActive = () => {
4686
+ crosshair.interrupt('crosshair-fade')
4687
+ .transition('crosshair-fade').duration(180).style('opacity', 0);
4688
+ pointsGroup.selectAll('circle.qhc-point')
4689
+ .filter(function () { return d3__namespace.select(this).attr('data-active') === 'true'; })
4690
+ .attr('data-active', null)
4691
+ .transition('point-scale').duration(180).attr('r', 4);
4692
+ stopHaloPulse();
4693
+ activeKey = null;
4694
+ setTooltipData(null);
4695
+ };
4696
+ uiGroup.append('rect')
4697
+ .attr('class', styles$8.overlay)
4698
+ .attr('width', chartWidth)
4699
+ .attr('height', chartHeight)
4700
+ .on('mousemove', function (event) {
4701
+ if (activeAll.length === 0)
4702
+ return;
4703
+ const [mx, my] = d3__namespace.pointer(event, this);
4704
+ let nearest = activeAll[0];
4705
+ let nearestDist = Infinity;
4706
+ for (const p of activeAll) {
4707
+ const dx = p.x - mx;
4708
+ const dy = p.y - my;
4709
+ const dist = dx * dx + dy * dy;
4710
+ if (dist < nearestDist) {
4711
+ nearestDist = dist;
4712
+ nearest = p;
4713
+ }
4714
+ }
4715
+ setActive(nearest, event.clientX, event.clientY);
4716
+ })
4717
+ .on('mouseleave', () => {
4718
+ clearActive();
4719
+ })
4720
+ .on('click', function (event) {
4721
+ if (activeAll.length === 0 || !onClickRef.current)
4722
+ return;
4723
+ const [mx, my] = d3__namespace.pointer(event, this);
4724
+ let nearest = activeAll[0];
4725
+ let nearestDist = Infinity;
4726
+ for (const p of activeAll) {
4727
+ const dx = p.x - mx;
4728
+ const dy = p.y - my;
4729
+ const dist = dx * dx + dy * dy;
4730
+ if (dist < nearestDist) {
4731
+ nearestDist = dist;
4732
+ nearest = p;
4733
+ }
4734
+ }
4735
+ onClickRef.current(nearest.habit, nearest.date.toISOString().split('T')[0], nearest.value);
4736
+ });
4737
+ uiGroup.raise();
4738
+ }, [aggregateData, activeHabits, chartWidth, chartHeight, margin, getColor, viewType, width, height]);
4739
+ // Hover dimming: update opacity on existing elements without redrawing.
4740
+ React.useEffect(() => {
4741
+ if (!svgRef.current)
4742
+ return;
4743
+ const svg = d3__namespace.select(svgRef.current);
4744
+ svg.selectAll('path.qhc-line')
4745
+ .each(function () {
4746
+ const habit = this.getAttribute('data-habit');
4747
+ const dim = hoveredHabit && hoveredHabit !== habit;
4748
+ d3__namespace.select(this)
4749
+ .transition('hover-dim')
4750
+ .duration(180)
4751
+ .attr('opacity', dim ? 0.25 : 1);
4752
+ });
4753
+ svg.selectAll('circle.qhc-point')
4754
+ .each(function () {
4755
+ const habit = this.getAttribute('data-habit');
4756
+ const dim = hoveredHabit && hoveredHabit !== habit;
4757
+ d3__namespace.select(this)
4758
+ .transition('hover-dim')
4759
+ .duration(180)
4760
+ .attr('opacity', dim ? 0.25 : 1);
4761
+ });
4762
+ }, [hoveredHabit]);
4395
4763
  const formatTooltipDate = (dateStr, viewType) => {
4396
4764
  const date = new Date(dateStr);
4397
4765
  switch (viewType) {
4398
4766
  case 'daily':
4399
4767
  return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });
4400
- case 'weekly': {
4401
- const weekEnd = new Date(date);
4402
- weekEnd.setDate(date.getDate() + 6);
4768
+ case 'weekly':
4403
4769
  return `Week of ${date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}`;
4404
- }
4405
4770
  case 'monthly':
4406
4771
  return date.toLocaleDateString('en-US', { month: 'long', year: 'numeric' });
4407
4772
  case 'quarterly': {
@@ -4412,7 +4777,6 @@ const QuantifiableHabitsChart = ({ data, width = 800, height = 400, defaultViewT
4412
4777
  return dateStr;
4413
4778
  }
4414
4779
  };
4415
- // View type icons and labels
4416
4780
  const viewTypeConfig = {
4417
4781
  daily: { Icon: lucideReact.Calendar, label: 'Daily' },
4418
4782
  weekly: { Icon: lucideReact.CalendarDays, label: 'Weekly' },