@stfrigerio/sito-template 0.1.97 → 0.1.99

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.esm.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
2
  import { motion, AnimatePresence, useDragControls, useMotionValue, useTransform, animate, LayoutGroup } from 'framer-motion';
3
- import React, { useRef, useEffect, useCallback, useState, useMemo, createContext, useContext, Fragment as Fragment$1, memo } from 'react';
3
+ import React, { useRef, useEffect, useCallback, useState, useMemo, createContext, useContext, Fragment as Fragment$1, useId, memo } from 'react';
4
4
  import { createPortal } from 'react-dom';
5
5
  import { X, Calendar as Calendar$1, ChevronDown, Search, Check, Edit, Folder, Users, Book, MessageSquare, UserPlus, Sun, Moon, Info, Github, SquareKanban, ChevronRight, Plus, Loader2, AlertTriangle, Play, Brain, FolderSearch, FilePlus, Pencil, FileText, Terminal, Trash2, GripVertical, Download, Menu, BarChart3, CalendarRange, CalendarDays, Divide, Sigma, ScatterChart, ChevronLeft, Maximize, Share2, Pause } from 'lucide-react';
6
6
  import dayjs from 'dayjs';
@@ -3936,22 +3936,27 @@ const Navbar = ({ items, logo, onItemClick, variant = 'sidebar', isMobile = fals
3936
3936
  return (jsx(Fragment, { children: jsx(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 }) }));
3937
3937
  };
3938
3938
 
3939
- 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"};
3939
+ 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"};
3940
3940
 
3941
3941
  const MoodChart = ({ moodData, width = 800, height = 400 }) => {
3942
3942
  const svgRef = useRef(null);
3943
3943
  const containerRef = useRef(null);
3944
3944
  const tooltipRef = useRef(null);
3945
+ const isHoveringTooltipRef = useRef(false);
3946
+ const rawId = useId();
3947
+ const gradientId = useMemo(() => `mood-area-${rawId.replace(/[^a-zA-Z0-9]/g, '_')}`, [rawId]);
3945
3948
  const [selectedMood, setSelectedMood] = useState(null);
3946
3949
  const [tooltipPosition, setTooltipPosition] = useState({ x: 0, y: 0 });
3947
3950
  const [isHoveringTooltip, setIsHoveringTooltip] = useState(false);
3951
+ useEffect(() => {
3952
+ isHoveringTooltipRef.current = isHoveringTooltip;
3953
+ }, [isHoveringTooltip]);
3948
3954
  const margin = useMemo(() => ({ top: 20, right: 20, bottom: 50, left: 40 }), []);
3949
3955
  const chartWidth = width - margin.left - margin.right;
3950
3956
  const chartHeight = height - margin.top - margin.bottom;
3951
3957
  const processedData = useMemo(() => {
3952
3958
  return moodData
3953
3959
  .map(mood => {
3954
- // Parse comma-separated tags
3955
3960
  const tags = mood.tag
3956
3961
  ? mood.tag.split(',').map(t => t.trim()).filter(t => t)
3957
3962
  : [];
@@ -3963,7 +3968,8 @@ const MoodChart = ({ moodData, width = 800, height = 400 }) => {
3963
3968
  };
3964
3969
  })
3965
3970
  .filter(mood => !isNaN(mood.date.getTime()) &&
3966
- isFinite(mood.rating));
3971
+ isFinite(mood.rating))
3972
+ .sort((a, b) => a.date.getTime() - b.date.getTime());
3967
3973
  }, [moodData]);
3968
3974
  const colorScale = useMemo(() => {
3969
3975
  return d3.scaleLinear()
@@ -3976,6 +3982,13 @@ const MoodChart = ({ moodData, width = 800, height = 400 }) => {
3976
3982
  return;
3977
3983
  const svg = d3.select(svgRef.current);
3978
3984
  svg.selectAll('*').remove();
3985
+ const defs = svg.append('defs');
3986
+ const gradient = defs.append('linearGradient')
3987
+ .attr('id', gradientId)
3988
+ .attr('x1', '0%').attr('y1', '0%')
3989
+ .attr('x2', '0%').attr('y2', '100%');
3990
+ gradient.append('stop').attr('offset', '0%').attr('class', styles$9.areaStopTop);
3991
+ gradient.append('stop').attr('offset', '100%').attr('class', styles$9.areaStopBottom);
3979
3992
  const g = svg.append('g')
3980
3993
  .attr('transform', `translate(${margin.left},${margin.top})`);
3981
3994
  const extentDates = d3.extent(processedData, d => d.date);
@@ -3991,6 +4004,12 @@ const MoodChart = ({ moodData, width = 800, height = 400 }) => {
3991
4004
  .x(d => xScale(d.date))
3992
4005
  .y(d => yScale(d.rating))
3993
4006
  .curve(d3.curveMonotoneX);
4007
+ const area = d3.area()
4008
+ .x(d => xScale(d.date))
4009
+ .y0(chartHeight)
4010
+ .y1(d => yScale(d.rating))
4011
+ .curve(d3.curveMonotoneX);
4012
+ // Grid lines (fade in)
3994
4013
  g.selectAll('.grid-line-y')
3995
4014
  .data(yScale.ticks(5))
3996
4015
  .enter().append('line')
@@ -3998,70 +4017,210 @@ const MoodChart = ({ moodData, width = 800, height = 400 }) => {
3998
4017
  .attr('x1', 0)
3999
4018
  .attr('y1', d => yScale(d))
4000
4019
  .attr('x2', chartWidth)
4001
- .attr('y2', d => yScale(d));
4002
- g.append('path')
4003
- .datum(processedData)
4004
- .attr('class', styles$9.line)
4005
- .attr('d', line);
4020
+ .attr('y2', d => yScale(d))
4021
+ .style('opacity', 0)
4022
+ .transition()
4023
+ .duration(500)
4024
+ .ease(d3.easeCubicOut)
4025
+ .style('opacity', 1);
4026
+ // Axes (fade in)
4006
4027
  g.append('g')
4007
4028
  .attr('class', styles$9.xAxis)
4008
4029
  .attr('transform', `translate(0,${chartHeight})`)
4030
+ .style('opacity', 0)
4009
4031
  .call(d3.axisBottom(xScale)
4010
- .tickFormat(d => d3.timeFormat('%m/%d')(d)));
4032
+ .tickFormat(d => d3.timeFormat('%m/%d')(d)))
4033
+ .transition()
4034
+ .duration(600)
4035
+ .delay(100)
4036
+ .style('opacity', 1);
4011
4037
  g.append('g')
4012
4038
  .attr('class', styles$9.yAxis)
4013
- .call(d3.axisLeft(yScale));
4014
- g.selectAll('.mood-circle')
4039
+ .style('opacity', 0)
4040
+ .call(d3.axisLeft(yScale))
4041
+ .transition()
4042
+ .duration(600)
4043
+ .delay(100)
4044
+ .style('opacity', 1);
4045
+ // Area fill (fades in after line draws past it)
4046
+ const areaPath = g.append('path')
4047
+ .datum(processedData)
4048
+ .attr('class', styles$9.area)
4049
+ .attr('fill', `url(#${gradientId})`)
4050
+ .attr('d', area)
4051
+ .style('opacity', 0);
4052
+ // Line (draw-in animation via stroke-dasharray)
4053
+ const linePath = g.append('path')
4054
+ .datum(processedData)
4055
+ .attr('class', styles$9.line)
4056
+ .attr('d', line);
4057
+ const lineNode = linePath.node();
4058
+ const totalLength = lineNode && typeof lineNode.getTotalLength === 'function'
4059
+ ? lineNode.getTotalLength()
4060
+ : 0;
4061
+ const lineDuration = 1200;
4062
+ if (totalLength > 0) {
4063
+ linePath
4064
+ .attr('stroke-dasharray', `${totalLength} ${totalLength}`)
4065
+ .attr('stroke-dashoffset', totalLength)
4066
+ .transition()
4067
+ .duration(lineDuration)
4068
+ .ease(d3.easeCubicOut)
4069
+ .attr('stroke-dashoffset', 0)
4070
+ .on('end', () => {
4071
+ linePath.attr('stroke-dasharray', null);
4072
+ });
4073
+ }
4074
+ areaPath
4075
+ .transition()
4076
+ .delay(lineDuration * 0.4)
4077
+ .duration(800)
4078
+ .ease(d3.easeCubicOut)
4079
+ .style('opacity', 1);
4080
+ // Crosshair (vertical guide on hover)
4081
+ const crosshair = g.append('line')
4082
+ .attr('class', styles$9.crosshair)
4083
+ .attr('y1', 0)
4084
+ .attr('y2', chartHeight)
4085
+ .style('opacity', 0)
4086
+ .style('pointer-events', 'none');
4087
+ // Pulsing halo behind active point
4088
+ const halo = g.append('circle')
4089
+ .attr('class', styles$9.halo)
4090
+ .attr('r', 0)
4091
+ .style('opacity', 0)
4092
+ .style('pointer-events', 'none');
4093
+ // Data points (staggered entrance keyed to line draw)
4094
+ const minX = xScale(extentDates[0]);
4095
+ const maxX = xScale(extentDates[1]);
4096
+ const xRange = Math.max(1, maxX - minX);
4097
+ const pointSel = g.selectAll('.mood-circle')
4015
4098
  .data(processedData)
4016
4099
  .enter().append('circle')
4017
4100
  .attr('class', styles$9.dataPoint)
4018
4101
  .attr('cx', d => xScale(d.date))
4019
4102
  .attr('cy', d => yScale(d.rating))
4020
- .attr('r', 5)
4103
+ .attr('r', 0)
4021
4104
  .attr('fill', d => colorScale(d.rating))
4022
- .style('cursor', 'pointer')
4023
- .on('mouseenter', (event, d) => {
4105
+ .style('opacity', 0)
4106
+ .style('pointer-events', 'none');
4107
+ pointSel.transition()
4108
+ .delay(d => 100 + lineDuration * ((xScale(d.date) - minX) / xRange))
4109
+ .duration(380)
4110
+ .ease(d3.easeBackOut.overshoot(2))
4111
+ .attr('r', 5)
4112
+ .style('opacity', 1);
4113
+ const pointNodes = pointSel.nodes();
4114
+ // Active state lives in mutable refs (closure over redraw)
4115
+ let activeIndex = null;
4116
+ const startHaloPulse = (cx, cy, fill) => {
4117
+ halo
4118
+ .interrupt('halo-pulse')
4119
+ .interrupt('halo-out')
4120
+ .attr('cx', cx)
4121
+ .attr('cy', cy)
4122
+ .attr('fill', fill);
4123
+ const pulseOnce = () => {
4124
+ halo
4125
+ .attr('r', 5)
4126
+ .style('opacity', 0.55)
4127
+ .transition('halo-pulse')
4128
+ .duration(900)
4129
+ .ease(d3.easeCubicOut)
4130
+ .attr('r', 20)
4131
+ .style('opacity', 0)
4132
+ .on('end', pulseOnce);
4133
+ };
4134
+ pulseOnce();
4135
+ };
4136
+ const stopHaloPulse = () => {
4137
+ halo
4138
+ .interrupt('halo-pulse')
4139
+ .transition('halo-out')
4140
+ .duration(180)
4141
+ .style('opacity', 0)
4142
+ .attr('r', 0);
4143
+ };
4144
+ const setActive = (idx, clientX, clientY) => {
4145
+ const d = processedData[idx];
4146
+ if (!d)
4147
+ return;
4148
+ const cx = xScale(d.date);
4149
+ const cy = yScale(d.rating);
4024
4150
  const rect = svgRef.current?.getBoundingClientRect();
4025
- const containerRect = containerRef.current?.getBoundingClientRect();
4026
- if (rect && containerRect) {
4027
- let x = event.clientX - rect.left + 10;
4028
- let y = event.clientY - rect.top - 10;
4029
- // Check if tooltip would overflow on the right
4030
- const estimatedTooltipWidth = 250; // Approximate tooltip width
4031
- const rightEdgeBuffer = 20; // Buffer from the right edge
4032
- if (x + estimatedTooltipWidth > chartWidth + margin.left - rightEdgeBuffer) {
4033
- // Position tooltip to the left of the cursor, but keep it close
4034
- x = event.clientX - rect.left - estimatedTooltipWidth - 10;
4035
- // Ensure it doesn't go off the left edge
4036
- if (x < 0) {
4151
+ if (rect) {
4152
+ let x = clientX - rect.left + 12;
4153
+ let y = clientY - rect.top - 12;
4154
+ const estW = 280;
4155
+ if (x + estW > chartWidth + margin.left - 20) {
4156
+ x = clientX - rect.left - estW - 12;
4157
+ if (x < 0)
4037
4158
  x = 10;
4038
- }
4039
4159
  }
4040
- // Ensure tooltip doesn't go above the container
4041
- if (y < 0) {
4160
+ if (y < 0)
4042
4161
  y = 10;
4043
- }
4044
4162
  setTooltipPosition({ x, y });
4045
4163
  }
4046
4164
  setSelectedMood(d);
4047
- d3.select(event.currentTarget)
4048
- .transition()
4049
- .duration(200)
4050
- .attr('r', 8);
4165
+ crosshair
4166
+ .attr('x1', cx).attr('x2', cx)
4167
+ .interrupt('crosshair-fade')
4168
+ .transition('crosshair-fade')
4169
+ .duration(120)
4170
+ .style('opacity', 1);
4171
+ if (activeIndex !== idx) {
4172
+ if (activeIndex !== null) {
4173
+ d3.select(pointNodes[activeIndex])
4174
+ .transition('point-scale')
4175
+ .duration(180)
4176
+ .ease(d3.easeCubicOut)
4177
+ .attr('r', 5);
4178
+ }
4179
+ d3.select(pointNodes[idx])
4180
+ .transition('point-scale')
4181
+ .duration(180)
4182
+ .ease(d3.easeBackOut.overshoot(2))
4183
+ .attr('r', 8);
4184
+ startHaloPulse(cx, cy, colorScale(d.rating));
4185
+ activeIndex = idx;
4186
+ }
4187
+ };
4188
+ const clearActive = () => {
4189
+ crosshair
4190
+ .interrupt('crosshair-fade')
4191
+ .transition('crosshair-fade')
4192
+ .duration(180)
4193
+ .style('opacity', 0);
4194
+ if (activeIndex !== null) {
4195
+ d3.select(pointNodes[activeIndex])
4196
+ .transition('point-scale')
4197
+ .duration(180)
4198
+ .attr('r', 5);
4199
+ activeIndex = null;
4200
+ }
4201
+ stopHaloPulse();
4202
+ setSelectedMood(null);
4203
+ };
4204
+ // Overlay captures mouse for nearest-point lookup (rendered last so it sits on top)
4205
+ const bisect = d3.bisector(d => d.date).center;
4206
+ g.append('rect')
4207
+ .attr('class', styles$9.overlay)
4208
+ .attr('width', chartWidth)
4209
+ .attr('height', chartHeight)
4210
+ .on('mousemove', function (event) {
4211
+ const [mx] = d3.pointer(event, this);
4212
+ const xDate = xScale.invert(mx);
4213
+ const idx = Math.max(0, Math.min(processedData.length - 1, bisect(processedData, xDate)));
4214
+ setActive(idx, event.clientX, event.clientY);
4051
4215
  })
4052
- .on('mouseleave', (event) => {
4053
- // Add delay to allow mouse to move to tooltip
4054
- setTimeout(() => {
4055
- if (!isHoveringTooltip) {
4056
- setSelectedMood(null);
4216
+ .on('mouseleave', () => {
4217
+ window.setTimeout(() => {
4218
+ if (!isHoveringTooltipRef.current) {
4219
+ clearActive();
4057
4220
  }
4058
- }, 250);
4059
- d3.select(event.currentTarget)
4060
- .transition()
4061
- .duration(200)
4062
- .attr('r', 5);
4221
+ }, 220);
4063
4222
  });
4064
- }, [processedData, chartWidth, chartHeight, colorScale, margin, isHoveringTooltip]);
4223
+ }, [processedData, chartWidth, chartHeight, colorScale, margin, gradientId]);
4065
4224
  // Clean up tooltip on unmount
4066
4225
  useEffect(() => {
4067
4226
  return () => {
@@ -4080,9 +4239,8 @@ const MoodChart = ({ moodData, width = 800, height = 400 }) => {
4080
4239
  }, children: [jsxs("div", { className: styles$9.tooltipHeader, children: [jsx("div", { className: styles$9.tooltipDate, children: selectedMood.date.toLocaleDateString() }), jsxs("div", { className: styles$9.tooltipRating, children: [jsx("span", { className: styles$9.ratingValue, children: selectedMood.rating }), jsx("span", { className: styles$9.ratingMax, children: "/10" })] })] }), selectedMood.tags.length > 0 && (jsx("div", { className: styles$9.tooltipTags, children: selectedMood.tags.map((tag, index) => (jsx("span", { className: styles$9.tag, children: tag }, index))) })), selectedMood.comment && (jsx("div", { className: styles$9.tooltipComment, children: selectedMood.comment }))] }))] }));
4081
4240
  };
4082
4241
 
4083
- 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"};
4242
+ 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"};
4084
4243
 
4085
- // Default colors as fallback
4086
4244
  const DEFAULT_HABIT_COLORS$1 = {
4087
4245
  'Exercise': '#6BCB77',
4088
4246
  'Meditation': '#4D96FF',
@@ -4093,14 +4251,53 @@ const DEFAULT_HABIT_COLORS$1 = {
4093
4251
  'Calories': '#FF9F1C',
4094
4252
  'Study': '#C774E8'
4095
4253
  };
4254
+ // Smoothly interpolate between two SVG path strings by resampling both
4255
+ // at evenly-spaced arc-length positions and tweening corresponding points.
4256
+ const SVG_NS = 'http://www.w3.org/2000/svg';
4257
+ const pathTween = (oldD, newD, samples = 80) => {
4258
+ const safeOld = oldD && oldD.length > 0 ? oldD : 'M0,0';
4259
+ const safeNew = newD && newD.length > 0 ? newD : 'M0,0';
4260
+ const oldNode = document.createElementNS(SVG_NS, 'path');
4261
+ const newNode = document.createElementNS(SVG_NS, 'path');
4262
+ oldNode.setAttribute('d', safeOld);
4263
+ newNode.setAttribute('d', safeNew);
4264
+ const oldLen = typeof oldNode.getTotalLength === 'function' ? oldNode.getTotalLength() : 0;
4265
+ const newLen = typeof newNode.getTotalLength === 'function' ? newNode.getTotalLength() : 0;
4266
+ if (oldLen === 0 || newLen === 0) {
4267
+ return () => safeNew;
4268
+ }
4269
+ const old = [];
4270
+ const next = [];
4271
+ for (let i = 0; i < samples; i++) {
4272
+ const u = samples === 1 ? 0 : i / (samples - 1);
4273
+ const op = oldNode.getPointAtLength(u * oldLen);
4274
+ const np = newNode.getPointAtLength(u * newLen);
4275
+ old.push([op.x, op.y]);
4276
+ next.push([np.x, np.y]);
4277
+ }
4278
+ return (t) => {
4279
+ let s = '';
4280
+ for (let i = 0; i < samples; i++) {
4281
+ const x = old[i][0] + (next[i][0] - old[i][0]) * t;
4282
+ const y = old[i][1] + (next[i][1] - old[i][1]) * t;
4283
+ s += (i === 0 ? 'M' : 'L') + x + ',' + y;
4284
+ }
4285
+ return s;
4286
+ };
4287
+ };
4096
4288
  const QuantifiableHabitsChart = ({ data, width = 800, height = 400, defaultViewType = 'daily', periodType = 'month', habitColors: customHabitColors = {}, habitEmojis: customHabitEmojis = {}, onDataPointClick, hideControls = false, compactLegend = false }) => {
4097
4289
  const svgRef = useRef(null);
4098
4290
  const tooltipRef = useRef(null);
4291
+ const onClickRef = useRef(onDataPointClick);
4292
+ const hasMountedRef = useRef(false);
4099
4293
  const [viewType, setViewType] = useState(defaultViewType);
4100
4294
  const [activeHabits, setActiveHabits] = useState([]);
4101
4295
  const [hoveredHabit, setHoveredHabit] = useState(null);
4102
4296
  const [tooltipData, setTooltipData] = useState(null);
4103
4297
  const [aggregationMode, setAggregationMode] = useState('average');
4298
+ useEffect(() => {
4299
+ onClickRef.current = onDataPointClick;
4300
+ }, [onDataPointClick]);
4104
4301
  const margin = useMemo(() => ({ top: 20, right: 20, bottom: 50, left: 50 }), []);
4105
4302
  const chartWidth = width - margin.left - margin.right;
4106
4303
  const chartHeight = height - margin.top - margin.bottom;
@@ -4108,7 +4305,6 @@ const QuantifiableHabitsChart = ({ data, width = 800, height = 400, defaultViewT
4108
4305
  useEffect(() => {
4109
4306
  setActiveHabits(habits);
4110
4307
  }, [habits]);
4111
- // Hide tooltip on scroll
4112
4308
  useEffect(() => {
4113
4309
  const handleScroll = () => {
4114
4310
  setTooltipData(null);
@@ -4135,39 +4331,32 @@ const QuantifiableHabitsChart = ({ data, width = 800, height = 400, defaultViewT
4135
4331
  }
4136
4332
  }, [periodType]);
4137
4333
  const getColor = useCallback((habit) => {
4138
- // First check custom colors, then defaults, then generate deterministic color
4139
4334
  return customHabitColors[habit] || DEFAULT_HABIT_COLORS$1[habit] || `hsl(${Math.abs(habit.split('').reduce((a, b) => a + b.charCodeAt(0), 0)) % 360}, 70%, 50%)`;
4140
4335
  }, [customHabitColors]);
4141
- // Aggregate data based on view type
4142
4336
  const aggregateData = useMemo(() => {
4143
4337
  if (viewType === 'daily' || !data.dates.length) {
4144
4338
  return data;
4145
4339
  }
4146
4340
  const aggregated = { dates: [] };
4147
4341
  const dateGroups = new Map();
4148
- // Group dates by period
4149
4342
  data.dates.forEach((dateStr, index) => {
4150
4343
  const date = new Date(dateStr);
4151
4344
  let groupKey;
4152
4345
  switch (viewType) {
4153
4346
  case 'weekly': {
4154
- // Get ISO week start (Monday)
4155
4347
  const weekStart = new Date(date);
4156
4348
  const day = weekStart.getDay();
4157
4349
  const diff = weekStart.getDate() - day + (day === 0 ? -6 : 1);
4158
4350
  weekStart.setDate(diff);
4159
- // Use the Monday date as the group key to ensure proper sorting
4160
4351
  groupKey = weekStart.toISOString().split('T')[0];
4161
4352
  break;
4162
4353
  }
4163
4354
  case 'monthly':
4164
- // Use first day of month for consistent sorting
4165
4355
  groupKey = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-01`;
4166
4356
  break;
4167
4357
  case 'quarterly': {
4168
4358
  const quarter = Math.floor(date.getMonth() / 3) + 1;
4169
4359
  const quarterStartMonth = (quarter - 1) * 3;
4170
- // Use first day of quarter for consistent sorting and grouping
4171
4360
  const quarterStart = new Date(date.getFullYear(), quarterStartMonth, 1);
4172
4361
  groupKey = quarterStart.toISOString().split('T')[0];
4173
4362
  break;
@@ -4180,7 +4369,6 @@ const QuantifiableHabitsChart = ({ data, width = 800, height = 400, defaultViewT
4180
4369
  }
4181
4370
  dateGroups.get(groupKey).push(index);
4182
4371
  });
4183
- // Calculate aggregated values - sort dates for proper chronological order
4184
4372
  aggregated.dates = Array.from(dateGroups.keys()).sort();
4185
4373
  habits.forEach(habit => {
4186
4374
  aggregated[habit] = aggregated.dates.map(groupKey => {
@@ -4190,11 +4378,10 @@ const QuantifiableHabitsChart = ({ data, width = 800, height = 400, defaultViewT
4190
4378
  .filter(v => typeof v === 'number' && !isNaN(v));
4191
4379
  if (values.length === 0)
4192
4380
  return 0;
4193
- // Calculate aggregation based on mode
4194
4381
  if (aggregationMode === 'sum') {
4195
4382
  return Math.round(values.reduce((sum, v) => sum + v, 0));
4196
4383
  }
4197
- else { // average
4384
+ else {
4198
4385
  return Math.round(values.reduce((sum, v) => sum + v, 0) / values.length);
4199
4386
  }
4200
4387
  });
@@ -4210,98 +4397,53 @@ const QuantifiableHabitsChart = ({ data, width = 800, height = 400, defaultViewT
4210
4397
  if (!svgRef.current || aggregateData.dates.length === 0)
4211
4398
  return;
4212
4399
  const svg = d3.select(svgRef.current);
4213
- svg.selectAll('*').remove();
4214
- // Add invisible rect to detect mouse leave events
4215
- svg.append('rect')
4216
- .attr('width', width)
4217
- .attr('height', height)
4218
- .attr('fill', 'transparent')
4219
- .style('pointer-events', 'all')
4220
- .on('mouseleave', () => {
4221
- setTooltipData(null);
4222
- });
4223
- const g = svg.append('g')
4224
- .attr('transform', `translate(${margin.left},${margin.top})`);
4400
+ const isFirstRender = !hasMountedRef.current;
4401
+ hasMountedRef.current = true;
4402
+ // Acquire/create persistent root group + sub-groups
4403
+ let root = svg.select('g.qhc-root');
4404
+ if (root.empty()) {
4405
+ root = svg.append('g').attr('class', 'qhc-root');
4406
+ }
4407
+ root.attr('transform', `translate(${margin.left},${margin.top})`);
4408
+ const ensureGroup = (cls) => {
4409
+ let s = root.select(`g.${cls}`);
4410
+ if (s.empty())
4411
+ s = root.append('g').attr('class', cls);
4412
+ return s;
4413
+ };
4414
+ const gridGroup = ensureGroup('qhc-grid');
4415
+ const linesGroup = ensureGroup('qhc-lines');
4416
+ const pointsGroup = ensureGroup('qhc-points');
4417
+ const axesGroup = ensureGroup('qhc-axes');
4418
+ const uiGroup = ensureGroup('qhc-ui');
4225
4419
  const dates = aggregateData.dates.map(d => new Date(d));
4226
4420
  const xScale = d3.scaleTime()
4227
4421
  .domain(d3.extent(dates))
4228
4422
  .range([0, chartWidth]);
4229
- const maxValue = Math.max(...activeHabits.flatMap(habit => aggregateData[habit].filter(v => typeof v === 'number')));
4423
+ const maxValue = Math.max(1, ...activeHabits.flatMap(habit => aggregateData[habit].filter(v => typeof v === 'number')));
4230
4424
  const yScale = d3.scaleLinear()
4231
4425
  .domain([0, maxValue * 1.1])
4232
4426
  .range([chartHeight, 0]);
4233
- g.selectAll('.grid-line-y')
4234
- .data(yScale.ticks(5))
4235
- .enter().append('line')
4236
- .attr('class', styles$8.gridLine)
4237
- .attr('x1', 0)
4238
- .attr('y1', d => yScale(d))
4239
- .attr('x2', chartWidth)
4240
- .attr('y2', d => yScale(d));
4241
- const line = d3.line()
4427
+ const lineGen = d3.line()
4242
4428
  .x(d => xScale(d[0]))
4243
4429
  .y(d => yScale(d[1]))
4244
4430
  .curve(d3.curveMonotoneX);
4245
- activeHabits.forEach(habit => {
4246
- const habitData = dates.map((date, i) => [date, aggregateData[habit][i]]).filter(d => typeof d[1] === 'number');
4247
- g.append('path')
4248
- .datum(habitData)
4249
- .attr('class', styles$8.line)
4250
- .attr('d', line)
4251
- .attr('stroke', getColor(habit))
4252
- .attr('opacity', hoveredHabit && hoveredHabit !== habit ? 0.3 : 1);
4253
- // Add invisible larger circles for better hover detection
4254
- g.selectAll(`.hover-circle-${habit}`)
4255
- .data(habitData)
4256
- .enter().append('circle')
4257
- .attr('cx', d => xScale(d[0]))
4258
- .attr('cy', d => yScale(d[1]))
4259
- .attr('r', 10) // Larger invisible area
4260
- .attr('fill', 'transparent')
4261
- .style('cursor', 'pointer')
4262
- .on('mouseenter', function (_event, d) {
4263
- const [date, value] = d;
4264
- const rect = svgRef.current?.getBoundingClientRect();
4265
- if (rect) {
4266
- setTooltipData({
4267
- habit,
4268
- date: date.toISOString().split('T')[0],
4269
- value,
4270
- x: xScale(date) + margin.left + rect.left,
4271
- y: yScale(value) + margin.top + rect.top
4272
- });
4273
- }
4274
- // Find and enlarge the visible circle
4275
- d3.select(g.node())
4276
- .selectAll(`.circle-${habit}-${dates.indexOf(date)}`)
4277
- .attr('r', 6);
4278
- })
4279
- .on('mouseleave', function (_event, _d) {
4280
- setTooltipData(null);
4281
- // Reset all circles for this habit
4282
- d3.select(g.node())
4283
- .selectAll('[class*="circle-' + habit + '"]')
4284
- .attr('r', 4);
4285
- })
4286
- .on('click', function (_event, d) {
4287
- const [date, value] = d;
4288
- if (onDataPointClick) {
4289
- onDataPointClick(habit, date.toISOString().split('T')[0], value);
4290
- }
4291
- });
4292
- // Add visible circles
4293
- g.selectAll(`.circle-${habit}`)
4294
- .data(habitData)
4295
- .enter().append('circle')
4296
- .attr('class', (_d, i) => `${styles$8.dataPoint} circle-${habit}-${i}`)
4297
- .attr('cx', d => xScale(d[0]))
4298
- .attr('cy', d => yScale(d[1]))
4299
- .attr('r', 4)
4300
- .attr('fill', getColor(habit))
4301
- .attr('opacity', hoveredHabit && hoveredHabit !== habit ? 0.3 : 1)
4302
- .style('pointer-events', 'none'); // Let the invisible circle handle events
4303
- });
4304
- // Helper function to get ISO week number
4431
+ // -------- Grid --------
4432
+ const gridSel = gridGroup.selectAll('line.qhc-grid-line')
4433
+ .data(yScale.ticks(5), d => String(d));
4434
+ gridSel.exit().remove();
4435
+ const gridEnter = gridSel.enter().append('line')
4436
+ .attr('class', `${styles$8.gridLine} qhc-grid-line`)
4437
+ .style('opacity', 0);
4438
+ gridEnter.merge(gridSel)
4439
+ .attr('x1', 0)
4440
+ .attr('x2', chartWidth)
4441
+ .attr('y1', d => yScale(d))
4442
+ .attr('y2', d => yScale(d))
4443
+ .transition()
4444
+ .duration(400)
4445
+ .style('opacity', 1);
4446
+ // -------- Axes --------
4305
4447
  const getISOWeek = (date) => {
4306
4448
  const d = new Date(date);
4307
4449
  d.setHours(0, 0, 0, 0);
@@ -4309,28 +4451,20 @@ const QuantifiableHabitsChart = ({ data, width = 800, height = 400, defaultViewT
4309
4451
  const week1 = new Date(d.getFullYear(), 0, 4);
4310
4452
  return 1 + Math.round(((d.getTime() - week1.getTime()) / 86400000 - 3 + (week1.getDay() + 6) % 7) / 7);
4311
4453
  };
4312
- // Format x-axis based on view type
4313
4454
  const xAxisFormat = (() => {
4314
4455
  switch (viewType) {
4315
4456
  case 'daily':
4316
4457
  return d3.timeFormat('%m-%d');
4317
4458
  case 'weekly':
4318
- return (d) => {
4319
- const weekNum = getISOWeek(d);
4320
- return `W${weekNum.toString().padStart(2, '0')}`;
4321
- };
4459
+ return (d) => `W${getISOWeek(d).toString().padStart(2, '0')}`;
4322
4460
  case 'monthly':
4323
4461
  return d3.timeFormat('%b');
4324
4462
  case 'quarterly':
4325
- return (d) => {
4326
- const quarter = Math.floor(d.getMonth() / 3) + 1;
4327
- return `Q${quarter}`;
4328
- };
4463
+ return (d) => `Q${Math.floor(d.getMonth() / 3) + 1}`;
4329
4464
  default:
4330
4465
  return d3.timeFormat('%m-%d');
4331
4466
  }
4332
4467
  })();
4333
- // Determine number of ticks based on view type and data
4334
4468
  const tickCount = (() => {
4335
4469
  switch (viewType) {
4336
4470
  case 'daily':
@@ -4340,47 +4474,278 @@ const QuantifiableHabitsChart = ({ data, width = 800, height = 400, defaultViewT
4340
4474
  case 'monthly':
4341
4475
  return Math.min(12, aggregateData.dates.length);
4342
4476
  case 'quarterly':
4343
- return aggregateData.dates.length; // Show all quarters
4477
+ return aggregateData.dates.length;
4344
4478
  default:
4345
4479
  return undefined;
4346
4480
  }
4347
4481
  })();
4348
4482
  const xAxisGenerator = d3.axisBottom(xScale)
4349
4483
  .tickFormat(d => xAxisFormat(d));
4350
- // Set tick values for quarterly to avoid duplicates
4351
4484
  if (viewType === 'quarterly') {
4352
4485
  xAxisGenerator.tickValues(dates);
4353
4486
  }
4354
4487
  else if (tickCount) {
4355
4488
  xAxisGenerator.ticks(tickCount);
4356
4489
  }
4357
- const xAxis = g.append('g')
4358
- .attr('class', styles$8.xAxis)
4359
- .attr('transform', `translate(0,${chartHeight})`)
4360
- .call(xAxisGenerator);
4361
- // Rotate labels for better readability if needed
4362
- if (viewType === 'daily' || viewType === 'weekly') {
4363
- xAxis.selectAll('text')
4364
- .style('text-anchor', 'end')
4365
- .attr('dx', '-.8em')
4366
- .attr('dy', '.15em')
4367
- .attr('transform', 'rotate(-45)');
4368
- }
4369
- g.append('g')
4370
- .attr('class', styles$8.yAxis)
4371
- .call(d3.axisLeft(yScale));
4372
- }, [aggregateData, activeHabits, chartWidth, chartHeight, margin, hoveredHabit, onDataPointClick, getColor, height, viewType, width]);
4373
- // Format date for tooltip display
4490
+ let xAxis = axesGroup.select('g.qhc-x-axis');
4491
+ if (xAxis.empty()) {
4492
+ xAxis = axesGroup.append('g').attr('class', `${styles$8.xAxis} qhc-x-axis`);
4493
+ }
4494
+ xAxis.attr('transform', `translate(0,${chartHeight})`).call(xAxisGenerator);
4495
+ xAxis.selectAll('text')
4496
+ .style('text-anchor', viewType === 'daily' || viewType === 'weekly' ? 'end' : 'middle')
4497
+ .attr('dx', viewType === 'daily' || viewType === 'weekly' ? '-.8em' : '0')
4498
+ .attr('dy', viewType === 'daily' || viewType === 'weekly' ? '.15em' : '.71em')
4499
+ .attr('transform', viewType === 'daily' || viewType === 'weekly' ? 'rotate(-45)' : null);
4500
+ let yAxis = axesGroup.select('g.qhc-y-axis');
4501
+ if (yAxis.empty()) {
4502
+ yAxis = axesGroup.append('g').attr('class', `${styles$8.yAxis} qhc-y-axis`);
4503
+ }
4504
+ yAxis.call(d3.axisLeft(yScale));
4505
+ if (isFirstRender) {
4506
+ xAxis.style('opacity', 0).transition().duration(500).delay(80).style('opacity', 1);
4507
+ yAxis.style('opacity', 0).transition().duration(500).delay(80).style('opacity', 1);
4508
+ }
4509
+ // -------- Lines (data join, morph on update) --------
4510
+ const lineData = activeHabits.map(habit => {
4511
+ const points = dates
4512
+ .map((date, i) => [date, aggregateData[habit][i]])
4513
+ .filter(d => typeof d[1] === 'number');
4514
+ return { habit, color: getColor(habit), points };
4515
+ });
4516
+ const lineSel = linesGroup.selectAll('path.qhc-line')
4517
+ .data(lineData, (d) => d.habit);
4518
+ lineSel.exit()
4519
+ .transition('line-exit')
4520
+ .duration(300)
4521
+ .style('opacity', 0)
4522
+ .remove();
4523
+ const lineEnter = lineSel.enter().append('path')
4524
+ .attr('class', `${styles$8.line} qhc-line`)
4525
+ .attr('data-habit', d => d.habit)
4526
+ .attr('fill', 'none')
4527
+ .attr('stroke', d => d.color)
4528
+ .attr('opacity', 0)
4529
+ .attr('d', d => lineGen(d.points) || '')
4530
+ .each(function () {
4531
+ const node = this;
4532
+ const len = typeof node.getTotalLength === 'function' ? node.getTotalLength() : 0;
4533
+ if (len > 0) {
4534
+ d3.select(node)
4535
+ .attr('stroke-dasharray', `${len} ${len}`)
4536
+ .attr('stroke-dashoffset', len);
4537
+ }
4538
+ });
4539
+ lineEnter.transition('line-enter')
4540
+ .duration(900)
4541
+ .ease(d3.easeCubicOut)
4542
+ .attr('opacity', 1)
4543
+ .attr('stroke-dashoffset', 0)
4544
+ .on('end', function () {
4545
+ d3.select(this).attr('stroke-dasharray', null);
4546
+ });
4547
+ lineSel.transition('line-update')
4548
+ .duration(700)
4549
+ .ease(d3.easeCubicInOut)
4550
+ .attr('stroke', d => d.color)
4551
+ .attrTween('d', function (d) {
4552
+ const oldD = d3.select(this).attr('d') || '';
4553
+ const newD = lineGen(d.points) || '';
4554
+ return pathTween(oldD, newD, 90);
4555
+ })
4556
+ .on('end', function (d) {
4557
+ d3.select(this).attr('d', lineGen(d.points) || '');
4558
+ });
4559
+ // -------- Points --------
4560
+ // Clear and re-add (simpler than join when both habit set + count change).
4561
+ // Hide them during line morph, then spring up from baseline.
4562
+ pointsGroup.selectAll('*').remove();
4563
+ const allPoints = [];
4564
+ activeHabits.forEach(habit => {
4565
+ const color = getColor(habit);
4566
+ dates.forEach((date, i) => {
4567
+ const v = aggregateData[habit][i];
4568
+ if (typeof v === 'number' && !isNaN(v)) {
4569
+ allPoints.push({ habit, color, date, value: v });
4570
+ }
4571
+ });
4572
+ });
4573
+ const minX = xScale(dates[0]);
4574
+ const maxX = xScale(dates[dates.length - 1]);
4575
+ const xRange = Math.max(1, maxX - minX);
4576
+ const pointAppearDelay = isFirstRender ? 100 : 350;
4577
+ const pointAppearTotal = isFirstRender ? 1100 : 600;
4578
+ pointsGroup.selectAll('circle.qhc-point')
4579
+ .data(allPoints)
4580
+ .enter().append('circle')
4581
+ .attr('class', `${styles$8.dataPoint} qhc-point`)
4582
+ .attr('data-habit', d => d.habit)
4583
+ .attr('cx', d => xScale(d.date))
4584
+ .attr('cy', chartHeight)
4585
+ .attr('r', 0)
4586
+ .attr('fill', d => d.color)
4587
+ .style('opacity', 0)
4588
+ .transition('point-enter')
4589
+ .delay(d => pointAppearDelay + pointAppearTotal * ((xScale(d.date) - minX) / xRange))
4590
+ .duration(420)
4591
+ .ease(d3.easeBackOut.overshoot(2))
4592
+ .attr('cy', d => yScale(d.value))
4593
+ .attr('r', 4)
4594
+ .style('opacity', 1);
4595
+ // -------- UI layer (crosshair, halo, overlay) --------
4596
+ uiGroup.selectAll('*').remove();
4597
+ const crosshair = uiGroup.append('line')
4598
+ .attr('class', styles$8.crosshair)
4599
+ .attr('y1', 0)
4600
+ .attr('y2', chartHeight)
4601
+ .style('opacity', 0)
4602
+ .style('pointer-events', 'none');
4603
+ const halo = uiGroup.append('circle')
4604
+ .attr('class', styles$8.halo)
4605
+ .attr('r', 0)
4606
+ .style('opacity', 0)
4607
+ .style('pointer-events', 'none');
4608
+ let activeKey = null;
4609
+ const startHaloPulse = (cx, cy, fill) => {
4610
+ halo.interrupt('halo-pulse').interrupt('halo-out')
4611
+ .attr('cx', cx).attr('cy', cy).attr('fill', fill);
4612
+ const pulseOnce = () => {
4613
+ halo.attr('r', 4).style('opacity', 0.55)
4614
+ .transition('halo-pulse').duration(900).ease(d3.easeCubicOut)
4615
+ .attr('r', 18).style('opacity', 0)
4616
+ .on('end', pulseOnce);
4617
+ };
4618
+ pulseOnce();
4619
+ };
4620
+ const stopHaloPulse = () => {
4621
+ halo.interrupt('halo-pulse')
4622
+ .transition('halo-out').duration(180)
4623
+ .style('opacity', 0).attr('r', 0);
4624
+ };
4625
+ const activeAll = allPoints.map(p => ({
4626
+ habit: p.habit,
4627
+ date: p.date,
4628
+ value: p.value,
4629
+ x: xScale(p.date),
4630
+ y: yScale(p.value)
4631
+ }));
4632
+ const setActive = (pt, clientX, clientY) => {
4633
+ const key = `${pt.habit}|${pt.date.toISOString()}`;
4634
+ const color = getColor(pt.habit);
4635
+ crosshair.attr('x1', pt.x).attr('x2', pt.x)
4636
+ .interrupt('crosshair-fade')
4637
+ .transition('crosshair-fade').duration(120).style('opacity', 1);
4638
+ if (activeKey !== key) {
4639
+ pointsGroup.selectAll('circle.qhc-point')
4640
+ .filter(function () { return d3.select(this).attr('data-active') === 'true'; })
4641
+ .attr('data-active', null)
4642
+ .transition('point-scale').duration(150).attr('r', 4);
4643
+ pointsGroup.selectAll('circle.qhc-point')
4644
+ .filter(function () {
4645
+ const cx = +d3.select(this).attr('cx');
4646
+ const cy = +d3.select(this).attr('cy');
4647
+ const habit = d3.select(this).attr('data-habit');
4648
+ return habit === pt.habit && Math.abs(cx - pt.x) < 0.5 && Math.abs(cy - pt.y) < 0.5;
4649
+ })
4650
+ .attr('data-active', 'true')
4651
+ .transition('point-scale').duration(180).ease(d3.easeBackOut.overshoot(2))
4652
+ .attr('r', 7);
4653
+ startHaloPulse(pt.x, pt.y, color);
4654
+ activeKey = key;
4655
+ }
4656
+ setTooltipData({
4657
+ habit: pt.habit,
4658
+ date: pt.date.toISOString().split('T')[0],
4659
+ value: pt.value,
4660
+ x: clientX,
4661
+ y: clientY
4662
+ });
4663
+ };
4664
+ const clearActive = () => {
4665
+ crosshair.interrupt('crosshair-fade')
4666
+ .transition('crosshair-fade').duration(180).style('opacity', 0);
4667
+ pointsGroup.selectAll('circle.qhc-point')
4668
+ .filter(function () { return d3.select(this).attr('data-active') === 'true'; })
4669
+ .attr('data-active', null)
4670
+ .transition('point-scale').duration(180).attr('r', 4);
4671
+ stopHaloPulse();
4672
+ activeKey = null;
4673
+ setTooltipData(null);
4674
+ };
4675
+ uiGroup.append('rect')
4676
+ .attr('class', styles$8.overlay)
4677
+ .attr('width', chartWidth)
4678
+ .attr('height', chartHeight)
4679
+ .on('mousemove', function (event) {
4680
+ if (activeAll.length === 0)
4681
+ return;
4682
+ const [mx, my] = d3.pointer(event, this);
4683
+ let nearest = activeAll[0];
4684
+ let nearestDist = Infinity;
4685
+ for (const p of activeAll) {
4686
+ const dx = p.x - mx;
4687
+ const dy = p.y - my;
4688
+ const dist = dx * dx + dy * dy;
4689
+ if (dist < nearestDist) {
4690
+ nearestDist = dist;
4691
+ nearest = p;
4692
+ }
4693
+ }
4694
+ setActive(nearest, event.clientX, event.clientY);
4695
+ })
4696
+ .on('mouseleave', () => {
4697
+ clearActive();
4698
+ })
4699
+ .on('click', function (event) {
4700
+ if (activeAll.length === 0 || !onClickRef.current)
4701
+ return;
4702
+ const [mx, my] = d3.pointer(event, this);
4703
+ let nearest = activeAll[0];
4704
+ let nearestDist = Infinity;
4705
+ for (const p of activeAll) {
4706
+ const dx = p.x - mx;
4707
+ const dy = p.y - my;
4708
+ const dist = dx * dx + dy * dy;
4709
+ if (dist < nearestDist) {
4710
+ nearestDist = dist;
4711
+ nearest = p;
4712
+ }
4713
+ }
4714
+ onClickRef.current(nearest.habit, nearest.date.toISOString().split('T')[0], nearest.value);
4715
+ });
4716
+ uiGroup.raise();
4717
+ }, [aggregateData, activeHabits, chartWidth, chartHeight, margin, getColor, viewType, width, height]);
4718
+ // Hover dimming: update opacity on existing elements without redrawing.
4719
+ useEffect(() => {
4720
+ if (!svgRef.current)
4721
+ return;
4722
+ const svg = d3.select(svgRef.current);
4723
+ svg.selectAll('path.qhc-line')
4724
+ .each(function () {
4725
+ const habit = this.getAttribute('data-habit');
4726
+ const dim = hoveredHabit && hoveredHabit !== habit;
4727
+ d3.select(this)
4728
+ .transition('hover-dim')
4729
+ .duration(180)
4730
+ .attr('opacity', dim ? 0.25 : 1);
4731
+ });
4732
+ svg.selectAll('circle.qhc-point')
4733
+ .each(function () {
4734
+ const habit = this.getAttribute('data-habit');
4735
+ const dim = hoveredHabit && hoveredHabit !== habit;
4736
+ d3.select(this)
4737
+ .transition('hover-dim')
4738
+ .duration(180)
4739
+ .attr('opacity', dim ? 0.25 : 1);
4740
+ });
4741
+ }, [hoveredHabit]);
4374
4742
  const formatTooltipDate = (dateStr, viewType) => {
4375
4743
  const date = new Date(dateStr);
4376
4744
  switch (viewType) {
4377
4745
  case 'daily':
4378
4746
  return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });
4379
- case 'weekly': {
4380
- const weekEnd = new Date(date);
4381
- weekEnd.setDate(date.getDate() + 6);
4747
+ case 'weekly':
4382
4748
  return `Week of ${date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}`;
4383
- }
4384
4749
  case 'monthly':
4385
4750
  return date.toLocaleDateString('en-US', { month: 'long', year: 'numeric' });
4386
4751
  case 'quarterly': {
@@ -4391,7 +4756,6 @@ const QuantifiableHabitsChart = ({ data, width = 800, height = 400, defaultViewT
4391
4756
  return dateStr;
4392
4757
  }
4393
4758
  };
4394
- // View type icons and labels
4395
4759
  const viewTypeConfig = {
4396
4760
  daily: { Icon: Calendar$1, label: 'Daily' },
4397
4761
  weekly: { Icon: CalendarDays, label: 'Weekly' },