@g4rcez/components 5.0.2 → 5.0.3

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 (273) hide show
  1. package/dist/AnimatePresence-j36AYeOQ.js +181 -0
  2. package/dist/AnimatePresence-j36AYeOQ.js.map +1 -0
  3. package/dist/Calendar.es-xICmgvjq.js +23 -0
  4. package/dist/Calendar.es-xICmgvjq.js.map +1 -0
  5. package/dist/Funnel.es-DjKVl8Nj.js +23 -0
  6. package/dist/Funnel.es-DjKVl8Nj.js.map +1 -0
  7. package/dist/{MotionConfig-DKKYqBH2.js → MotionConfig-CXHoPGbK.js} +2 -2
  8. package/dist/{MotionConfig-DKKYqBH2.js.map → MotionConfig-CXHoPGbK.js.map} +1 -1
  9. package/dist/Plus.es-DbyRkEE2.js +23 -0
  10. package/dist/Plus.es-DbyRkEE2.js.map +1 -0
  11. package/dist/Trash.es-BFAc8PMf.js +23 -0
  12. package/dist/Trash.es-BFAc8PMf.js.map +1 -0
  13. package/dist/{calendar-PCCZDUIL.js → calendar-DEPkz8sw.js} +364 -502
  14. package/dist/calendar-DEPkz8sw.js.map +1 -0
  15. package/dist/calendar-header-Dfr-CwkY.js +174 -0
  16. package/dist/calendar-header-Dfr-CwkY.js.map +1 -0
  17. package/dist/chunk-jwUa06l-.js +23 -0
  18. package/dist/components/core/button.js +1 -1
  19. package/dist/components/core/heading.js +11 -0
  20. package/dist/components/core/heading.js.map +1 -0
  21. package/dist/{polymorph-BLXhrn9n.js → components/core/polymorph.js} +2 -2
  22. package/dist/components/core/polymorph.js.map +1 -0
  23. package/dist/components/core/render-on-view.js +29 -0
  24. package/dist/components/core/render-on-view.js.map +1 -0
  25. package/dist/components/core/resizable.d.ts +7 -1
  26. package/dist/components/core/resizable.d.ts.map +1 -1
  27. package/dist/components/core/resizable.js +60 -0
  28. package/dist/components/core/resizable.js.map +1 -0
  29. package/dist/components/core/resizable.jsx +46 -40
  30. package/dist/{slot-pC8kH9De.js → components/core/slot.js} +2 -2
  31. package/dist/components/core/slot.js.map +1 -0
  32. package/dist/components/core/tag.js +1 -1
  33. package/dist/components/core/typography.js +40 -0
  34. package/dist/components/core/typography.js.map +1 -0
  35. package/dist/components/display/alert.d.ts.map +1 -1
  36. package/dist/components/display/alert.js +83 -102
  37. package/dist/components/display/alert.js.map +1 -1
  38. package/dist/components/display/alert.jsx +26 -29
  39. package/dist/components/display/calendar.d.ts.map +1 -1
  40. package/dist/components/display/calendar.js +1 -1
  41. package/dist/components/display/calendar.jsx +15 -10
  42. package/dist/components/display/card.js +2 -2
  43. package/dist/components/display/empty.d.ts.map +1 -1
  44. package/dist/components/display/empty.js +25 -0
  45. package/dist/components/display/empty.js.map +1 -0
  46. package/dist/components/display/empty.jsx +3 -1
  47. package/dist/components/display/list.d.ts.map +1 -1
  48. package/dist/components/display/list.js +132 -122
  49. package/dist/components/display/list.js.map +1 -1
  50. package/dist/components/display/list.jsx +30 -25
  51. package/dist/components/display/notifications.d.ts.map +1 -1
  52. package/dist/components/display/notifications.js +1 -1
  53. package/dist/components/display/notifications.jsx +8 -6
  54. package/dist/components/display/progress.d.ts.map +1 -1
  55. package/dist/components/display/progress.js +3 -0
  56. package/dist/components/display/progress.jsx +6 -8
  57. package/dist/components/display/shortcut.js +2 -0
  58. package/dist/components/display/skeleton.js +41 -0
  59. package/dist/components/display/skeleton.js.map +1 -0
  60. package/dist/components/display/spinner.js +17 -0
  61. package/dist/components/display/spinner.js.map +1 -0
  62. package/dist/components/display/step.d.ts.map +1 -1
  63. package/dist/components/display/step.js +3 -0
  64. package/dist/components/display/step.jsx +5 -5
  65. package/dist/components/display/tabs.js +1 -1
  66. package/dist/components/display/timeline.js +1 -1
  67. package/dist/components/floating/command-palette.d.ts.map +1 -1
  68. package/dist/components/floating/command-palette.js +255 -0
  69. package/dist/components/floating/command-palette.js.map +1 -0
  70. package/dist/components/floating/command-palette.jsx +34 -25
  71. package/dist/components/floating/dropdown.js +1 -1
  72. package/dist/components/floating/dropdown.js.map +1 -1
  73. package/dist/components/floating/dropdown.jsx +1 -1
  74. package/dist/components/floating/expand.js +15 -14
  75. package/dist/components/floating/expand.js.map +1 -1
  76. package/dist/components/floating/menu.js +1 -1
  77. package/dist/components/floating/modal.d.ts +14 -11
  78. package/dist/components/floating/modal.d.ts.map +1 -1
  79. package/dist/components/floating/modal.js +1 -1
  80. package/dist/components/floating/modal.jsx +56 -17
  81. package/dist/components/floating/toolbar.d.ts +3 -3
  82. package/dist/components/floating/toolbar.d.ts.map +1 -1
  83. package/dist/components/floating/toolbar.js +20 -0
  84. package/dist/components/floating/toolbar.js.map +1 -0
  85. package/dist/components/floating/toolbar.jsx +7 -3
  86. package/dist/components/floating/tooltip.js +2 -2
  87. package/dist/components/floating/tooltip.js.map +1 -1
  88. package/dist/components/floating/tooltip.jsx +1 -1
  89. package/dist/components/floating/wizard.js +3 -0
  90. package/dist/components/form/autocomplete.d.ts.map +1 -1
  91. package/dist/components/form/autocomplete.js +344 -2
  92. package/dist/components/form/autocomplete.js.map +1 -0
  93. package/dist/components/form/autocomplete.jsx +27 -18
  94. package/dist/components/form/checkbox.d.ts.map +1 -1
  95. package/dist/components/form/checkbox.js +29 -27
  96. package/dist/components/form/checkbox.js.map +1 -1
  97. package/dist/components/form/checkbox.jsx +21 -6
  98. package/dist/components/form/date-picker.js +1 -1
  99. package/dist/components/form/date-picker.jsx +1 -1
  100. package/dist/components/form/file-upload.d.ts +6 -1
  101. package/dist/components/form/file-upload.d.ts.map +1 -1
  102. package/dist/components/form/file-upload.js +1 -1
  103. package/dist/components/form/file-upload.jsx +34 -12
  104. package/dist/components/form/formReset.js +10 -0
  105. package/dist/components/form/formReset.js.map +1 -0
  106. package/dist/components/form/free-text.js +70 -0
  107. package/dist/components/form/free-text.js.map +1 -0
  108. package/dist/components/form/free-text.jsx +1 -1
  109. package/dist/components/form/input-field.d.ts.map +1 -1
  110. package/dist/components/form/input-field.js +3 -0
  111. package/dist/components/form/input-field.jsx +14 -8
  112. package/dist/components/form/input.js +1 -1
  113. package/dist/components/form/multi-select.d.ts.map +1 -1
  114. package/dist/components/form/multi-select.js +420 -0
  115. package/dist/components/form/multi-select.js.map +1 -0
  116. package/dist/components/form/multi-select.jsx +41 -33
  117. package/dist/components/form/select.d.ts.map +1 -1
  118. package/dist/components/form/select.js +55 -51
  119. package/dist/components/form/select.js.map +1 -1
  120. package/dist/components/form/select.jsx +8 -5
  121. package/dist/components/form/slider.js +3 -0
  122. package/dist/components/form/switch.d.ts +2 -1
  123. package/dist/components/form/switch.d.ts.map +1 -1
  124. package/dist/components/form/switch.js +32 -26
  125. package/dist/components/form/switch.js.map +1 -1
  126. package/dist/components/form/switch.jsx +26 -13
  127. package/dist/components/form/textarea.js +19 -0
  128. package/dist/components/form/textarea.js.map +1 -0
  129. package/dist/components/page-calendar/calendar-header.d.ts.map +1 -1
  130. package/dist/components/page-calendar/calendar-header.js +2 -0
  131. package/dist/components/page-calendar/calendar-header.jsx +6 -4
  132. package/dist/components/page-calendar/day-view.js +124 -0
  133. package/dist/components/page-calendar/day-view.js.map +1 -0
  134. package/dist/components/page-calendar/event-pill.js +44 -0
  135. package/dist/components/page-calendar/event-pill.js.map +1 -0
  136. package/dist/components/page-calendar/month-view.d.ts.map +1 -1
  137. package/dist/components/page-calendar/month-view.js +109 -0
  138. package/dist/components/page-calendar/month-view.js.map +1 -0
  139. package/dist/components/page-calendar/month-view.jsx +78 -31
  140. package/dist/components/page-calendar/page-calendar.d.ts.map +1 -1
  141. package/dist/components/page-calendar/page-calendar.js +75 -0
  142. package/dist/components/page-calendar/page-calendar.js.map +1 -0
  143. package/dist/components/page-calendar/page-calendar.jsx +2 -2
  144. package/dist/components/page-calendar/week-view.js +88 -0
  145. package/dist/components/page-calendar/week-view.js.map +1 -0
  146. package/dist/components/table/filter.d.ts.map +1 -1
  147. package/dist/components/table/filter.js +239 -0
  148. package/dist/components/table/filter.js.map +1 -0
  149. package/dist/components/table/filter.jsx +9 -4
  150. package/dist/components/table/group.d.ts.map +1 -1
  151. package/dist/components/table/group.js +3 -0
  152. package/dist/components/table/group.jsx +5 -3
  153. package/dist/components/table/index.js +102 -0
  154. package/dist/components/table/index.js.map +1 -0
  155. package/dist/components/table/inner-table.js +2 -0
  156. package/dist/components/table/inner-table.jsx +1 -1
  157. package/dist/components/table/metadata.js +73 -0
  158. package/dist/components/table/metadata.js.map +1 -0
  159. package/dist/components/table/metadata.jsx +1 -1
  160. package/dist/components/table/pagination.js +70 -0
  161. package/dist/components/table/pagination.js.map +1 -0
  162. package/dist/components/table/row.js +58 -0
  163. package/dist/components/table/row.js.map +1 -0
  164. package/dist/components/table/sort.d.ts.map +1 -1
  165. package/dist/components/table/sort.js +3 -0
  166. package/dist/components/table/sort.jsx +3 -1
  167. package/dist/components/table/thead.js +3 -0
  168. package/dist/config/default-translations.d.ts +18 -0
  169. package/dist/config/default-translations.d.ts.map +1 -1
  170. package/dist/config/default-translations.jsx +18 -0
  171. package/dist/{use-translations-DTLfPE3_.js → context-CsnUsfeP.js} +55 -40
  172. package/dist/context-CsnUsfeP.js.map +1 -0
  173. package/dist/{date-picker-BhKEFZew.js → date-picker-DNzupG8R.js} +301 -317
  174. package/dist/date-picker-DNzupG8R.js.map +1 -0
  175. package/dist/dict-CisoYSMO.js +28 -0
  176. package/dist/dict-CisoYSMO.js.map +1 -0
  177. package/dist/dist-ChfJ5LO9.js +498 -0
  178. package/dist/dist-ChfJ5LO9.js.map +1 -0
  179. package/dist/{dist-BrGpYRaj.js → dist-DIjUECx9.js} +56 -56
  180. package/dist/{dist-BrGpYRaj.js.map → dist-DIjUECx9.js.map} +1 -1
  181. package/dist/dom-Bn4wY_Zx.js.map +1 -1
  182. package/dist/{file-upload-DWbZfeG5.js → file-upload-C2zNnv9n.js} +501 -481
  183. package/dist/{file-upload-DWbZfeG5.js.map → file-upload-C2zNnv9n.js.map} +1 -1
  184. package/dist/fzf-CPGDDCoU.js +64 -0
  185. package/dist/fzf-CPGDDCoU.js.map +1 -0
  186. package/dist/getISOWeek-EcB4Ebqp.js +72 -0
  187. package/dist/getISOWeek-EcB4Ebqp.js.map +1 -0
  188. package/dist/group-Dl14TJXO.js +222 -0
  189. package/dist/group-Dl14TJXO.js.map +1 -0
  190. package/dist/hooks/use-translations.d.ts +18 -0
  191. package/dist/hooks/use-translations.d.ts.map +1 -1
  192. package/dist/index.css +1 -1
  193. package/dist/index.js.map +1 -1
  194. package/dist/inner-table-CeDX60cL.js +151 -0
  195. package/dist/inner-table-CeDX60cL.js.map +1 -0
  196. package/dist/input-Cmyuea4Y.js +412 -0
  197. package/dist/input-Cmyuea4Y.js.map +1 -0
  198. package/dist/{input-field-B_whI66Q.js → input-field-ffx1MbHo.js} +29 -16
  199. package/dist/input-field-ffx1MbHo.js.map +1 -0
  200. package/dist/isSameMonth-C3lsSwcg.js +10 -0
  201. package/dist/isSameMonth-C3lsSwcg.js.map +1 -0
  202. package/dist/isToday-COXfxFui.js +32 -0
  203. package/dist/isToday-COXfxFui.js.map +1 -0
  204. package/dist/lib/dom.d.ts.map +1 -1
  205. package/dist/modal-Df8-6i-o.js +408 -0
  206. package/dist/modal-Df8-6i-o.js.map +1 -0
  207. package/dist/notifications-NhCESJUV.js +1697 -0
  208. package/dist/notifications-NhCESJUV.js.map +1 -0
  209. package/dist/page-calendar.utils-Bd0PHktL.js +102 -0
  210. package/dist/page-calendar.utils-Bd0PHktL.js.map +1 -0
  211. package/dist/preset/preset.tailwind.d.ts.map +1 -1
  212. package/dist/preset/preset.tailwind.js +6 -7
  213. package/dist/preset/src/styles/dark.js +1 -1
  214. package/dist/progress-8LO5gWLp.js +104 -0
  215. package/dist/progress-8LO5gWLp.js.map +1 -0
  216. package/dist/{proxy-BcJ_5Dwq.js → proxy-fP2NxmhM.js} +658 -844
  217. package/dist/proxy-fP2NxmhM.js.map +1 -0
  218. package/dist/shim-Czv-YhKR.js +93 -0
  219. package/dist/shim-Czv-YhKR.js.map +1 -0
  220. package/dist/shortcut-CQCmgmlU.js +100 -0
  221. package/dist/shortcut-CQCmgmlU.js.map +1 -0
  222. package/dist/slider-TX9hiHO-.js +1196 -0
  223. package/dist/slider-TX9hiHO-.js.map +1 -0
  224. package/dist/sort-DGmiselV.js +195 -0
  225. package/dist/sort-DGmiselV.js.map +1 -0
  226. package/dist/step-DFpJ7zCG.js +185 -0
  227. package/dist/step-DFpJ7zCG.js.map +1 -0
  228. package/dist/styles/dark.js +1 -1
  229. package/dist/subMonths-QcCnE3Yh.js +43 -0
  230. package/dist/subMonths-QcCnE3Yh.js.map +1 -0
  231. package/dist/table-lib-1bkYSklk.js +174 -0
  232. package/dist/table-lib-1bkYSklk.js.map +1 -0
  233. package/dist/{tabs-Ciy0l9OF.js → tabs-Brc963EW.js} +2 -2
  234. package/dist/{tabs-Ciy0l9OF.js.map → tabs-Brc963EW.js.map} +1 -1
  235. package/dist/thead-B6WELJZ-.js +211 -0
  236. package/dist/thead-B6WELJZ-.js.map +1 -0
  237. package/dist/use-locale-DPM_sg4s.js +12 -0
  238. package/dist/use-locale-DPM_sg4s.js.map +1 -0
  239. package/dist/use-remove-scroll-pAgC09Sq.js +38 -0
  240. package/dist/use-remove-scroll-pAgC09Sq.js.map +1 -0
  241. package/dist/use-translations-BE4PuhLm.js +11 -0
  242. package/dist/use-translations-BE4PuhLm.js.map +1 -0
  243. package/dist/useAnimationFrame-DnKbaXfi.js +223 -0
  244. package/dist/useAnimationFrame-DnKbaXfi.js.map +1 -0
  245. package/dist/valueToPercent-DZc_m1tm.js +43 -0
  246. package/dist/valueToPercent-DZc_m1tm.js.map +1 -0
  247. package/dist/visuallyHidden-B7wI86yi.js +303 -0
  248. package/dist/visuallyHidden-B7wI86yi.js.map +1 -0
  249. package/dist/with-selector-BFW5n-pb.js +102 -0
  250. package/dist/with-selector-BFW5n-pb.js.map +1 -0
  251. package/dist/wizard-7u_qZ-78.js +218 -0
  252. package/dist/wizard-7u_qZ-78.js.map +1 -0
  253. package/package.json +19 -11
  254. package/dist/autocomplete-D3VOTihi.js +0 -415
  255. package/dist/autocomplete-D3VOTihi.js.map +0 -1
  256. package/dist/calendar-PCCZDUIL.js.map +0 -1
  257. package/dist/components/table/table.js +0 -3
  258. package/dist/date-picker-BhKEFZew.js.map +0 -1
  259. package/dist/input-B7jqwPG4.js +0 -473
  260. package/dist/input-B7jqwPG4.js.map +0 -1
  261. package/dist/input-field-B_whI66Q.js.map +0 -1
  262. package/dist/modal-Bz-61ays.js +0 -373
  263. package/dist/modal-Bz-61ays.js.map +0 -1
  264. package/dist/notifications-MT4XkLov.js +0 -2203
  265. package/dist/notifications-MT4XkLov.js.map +0 -1
  266. package/dist/polymorph-BLXhrn9n.js.map +0 -1
  267. package/dist/proxy-BcJ_5Dwq.js.map +0 -1
  268. package/dist/skeleton-CBYEq3lM.js +0 -26
  269. package/dist/skeleton-CBYEq3lM.js.map +0 -1
  270. package/dist/slot-pC8kH9De.js.map +0 -1
  271. package/dist/table-CUFbAI2k.js +0 -1914
  272. package/dist/table-CUFbAI2k.js.map +0 -1
  273. package/dist/use-translations-DTLfPE3_.js.map +0 -1
@@ -2,8 +2,11 @@
2
2
  import React, { forwardRef, useEffect, useId, useImperativeHandle, useRef, useState } from "react";
3
3
  import { useStableRef } from "../../hooks/use-stable-ref";
4
4
  import { css } from "../../lib/dom";
5
- export const Switch = forwardRef(({ children, loading, container, error, ...props }, ref) => {
5
+ export const Switch = forwardRef(({ children, loading, container, error, onKeyDown, onCheck: onCheckProp, ...props }, ref) => {
6
6
  const id = useId();
7
+ const errorId = error ? `${props.id || id}-error` : undefined;
8
+ const describedBy = [props["aria-describedby"], errorId].filter(Boolean).join(" ") || undefined;
9
+ const ariaInvalid = error ? true : props["aria-invalid"];
7
10
  const [innerChecked, setInnerChecked] = useState(props.checked ?? false);
8
11
  const checked = innerChecked;
9
12
  const innerRef = useRef(null);
@@ -25,22 +28,32 @@ export const Switch = forwardRef(({ children, loading, container, error, ...prop
25
28
  const onCheck = () => {
26
29
  const checked = !innerRef.current?.checked;
27
30
  setInnerChecked(checked);
28
- props?.onCheck?.(checked);
31
+ onCheckProp?.(checked);
29
32
  if (innerRef.current !== null) {
30
33
  innerRef.current.checked = checked;
31
34
  innerRef.current.dispatchEvent(new Event("change", { bubbles: true }));
32
35
  }
33
36
  };
34
37
  return (<fieldset className={css("flex flex-col flex-wrap justify-center", container)} data-component="switch" disabled={props.disabled || loading}>
35
- <span className="flex flex-row flex-wrap items-center">
36
- <input {...props} hidden ref={innerRef} type="checkbox" checked={checked} id={props.id || id} data-trigger="change" data-checked={checked} disabled={props.disabled || loading} onChange={(e) => setInnerChecked(e.target.checked)}/>
37
- <button role="switch" type="button" onClick={onCheck} aria-checked={checked} data-checked={checked} aria-labelledby={`${id}-label`} disabled={props.disabled || loading} className="relative inline-flex h-switch-track-h w-switch-track-w flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-300 ease-in-out focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2 data-[checked=false]:bg-input-switch-bg data-[checked=true]:bg-primary">
38
- <span aria-hidden="true" data-checked={checked} className="inline-block aspect-square size-switch-thumb-size transform rounded-full shadow ring-0 transition duration-300 ease-in-out data-[checked=false]:translate-x-0 data-[checked=true]:translate-x-5 data-[checked=false]:bg-disabled data-[checked=true]:bg-input-switch"/>
39
- </button>
40
- <label htmlFor={props.id || id} className="ml-switch-gap inline-block text-switch-label-text" id={`${id}-label`}>
41
- <span className="font-medium text-foreground">{children}</span>
42
- </label>
43
- </span>
44
- <span className="mt-switch-hint-mt flex-1 whitespace-nowrap text-switch-hint-text text-danger empty:mt-0 empty:hidden">{error}</span>
45
- </fieldset>);
38
+ <span className="flex flex-row flex-wrap items-center">
39
+ <input {...props} hidden ref={innerRef} type="checkbox" checked={checked} id={props.id || id} data-trigger="change" data-checked={checked} disabled={props.disabled || loading} onChange={(e) => setInnerChecked(e.target.checked)}/>
40
+ <button role="switch" type="button" onClick={onCheck} onKeyDown={(event) => {
41
+ onKeyDown?.(event);
42
+ if (event.defaultPrevented)
43
+ return;
44
+ if (event.key === " " || event.key === "Space" || event.code === "Space" || event.key === "Enter") {
45
+ event.preventDefault();
46
+ onCheck();
47
+ }
48
+ }} aria-checked={checked} aria-invalid={ariaInvalid} aria-describedby={describedBy} data-checked={checked} aria-labelledby={`${id}-label`} disabled={props.disabled || loading} className="relative inline-flex h-switch-track-h w-switch-track-w flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-300 ease-in-out focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2 data-[checked=false]:bg-input-switch-bg data-[checked=true]:bg-primary">
49
+ <span aria-hidden="true" data-checked={checked} className="inline-block aspect-square size-switch-thumb-size transform rounded-full shadow ring-0 transition duration-300 ease-in-out data-[checked=false]:translate-x-0 data-[checked=true]:translate-x-5 data-[checked=false]:bg-disabled data-[checked=true]:bg-input-switch"/>
50
+ </button>
51
+ <label htmlFor={props.id || id} className="ml-switch-gap inline-block text-switch-label-text" id={`${id}-label`}>
52
+ <span className="font-medium text-foreground">{children}</span>
53
+ </label>
54
+ </span>
55
+ <span id={errorId} className="mt-switch-hint-mt flex-1 whitespace-nowrap text-switch-hint-text text-danger empty:mt-0 empty:hidden">
56
+ {error}
57
+ </span>
58
+ </fieldset>);
46
59
  });
@@ -0,0 +1,19 @@
1
+ "use client";
2
+ import { createFreeText as e } from "./free-text.js";
3
+ //#region src/components/form/textarea.tsx
4
+ var t = e("textarea", "textarea", { container: "w-full" }, (e) => {
5
+ let t = e.hasAttribute("rows"), n = (() => {
6
+ if (!t) return e.offsetHeight;
7
+ let n = window.getComputedStyle(e);
8
+ return e.rows * parseFloat(n.lineHeight) + parseFloat(n.paddingTop) + parseFloat(n.paddingBottom) + parseFloat(n.borderTopWidth) + parseFloat(n.borderBottomWidth);
9
+ })(), r = () => {
10
+ e.style.height = "0px", e.style.height = `${Math.max(e.scrollHeight, n)}px`;
11
+ };
12
+ return r(), e.addEventListener("input", r), () => {
13
+ e.removeEventListener("input", r), e.style.height = "";
14
+ };
15
+ });
16
+ //#endregion
17
+ export { t as Textarea };
18
+
19
+ //# sourceMappingURL=textarea.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"textarea.js","names":[],"sources":["../../../src/components/form/textarea.tsx"],"sourcesContent":["\"use client\";\nimport React from \"react\";\nimport { Any } from \"../../types\";\nimport { createFreeText, FreeTextProps } from \"./free-text\";\n\nexport type TextareaProps = FreeTextProps<\"textarea\", React.ComponentProps<\"textarea\">>;\n\nexport const Textarea: React.FC<TextareaProps> = createFreeText<\"textarea\", HTMLTextAreaElement, Any>(\n \"textarea\",\n \"textarea\",\n { container: \"w-full\" },\n (textarea: HTMLTextAreaElement) => {\n const hasRows = textarea.hasAttribute(\"rows\");\n const computeMinHeight = (): number => {\n if (!hasRows) return textarea.offsetHeight;\n const s = window.getComputedStyle(textarea);\n return (\n textarea.rows * parseFloat(s.lineHeight) +\n parseFloat(s.paddingTop) +\n parseFloat(s.paddingBottom) +\n parseFloat(s.borderTopWidth) +\n parseFloat(s.borderBottomWidth)\n );\n };\n const minHeight = computeMinHeight();\n const adjustHeight = () => {\n textarea.style.height = \"0px\";\n textarea.style.height = `${Math.max(textarea.scrollHeight, minHeight)}px`;\n };\n adjustHeight();\n textarea.addEventListener(\"input\", adjustHeight);\n return () => {\n textarea.removeEventListener(\"input\", adjustHeight);\n textarea.style.height = \"\";\n };\n }\n);\n"],"mappings":";;;AAOA,IAAa,IAAoC,EAC7C,YACA,YACA,EAAE,WAAW,SAAS,IACrB,MAAkC;CAC/B,IAAM,IAAU,EAAS,aAAa,MAAM,GAYtC,WAXiC;EACnC,IAAI,CAAC,GAAS,OAAO,EAAS;EAC9B,IAAM,IAAI,OAAO,iBAAiB,CAAQ;EAC1C,OACI,EAAS,OAAO,WAAW,EAAE,UAAU,IACvC,WAAW,EAAE,UAAU,IACvB,WAAW,EAAE,aAAa,IAC1B,WAAW,EAAE,cAAc,IAC3B,WAAW,EAAE,iBAAiB;CAEtC,GACmC,GAC7B,UAAqB;EAEvB,AADA,EAAS,MAAM,SAAS,OACxB,EAAS,MAAM,SAAS,GAAG,KAAK,IAAI,EAAS,cAAc,CAAS,EAAE;CAC1E;CAGA,OAFA,EAAa,GACb,EAAS,iBAAiB,SAAS,CAAY,SAClC;EAET,AADA,EAAS,oBAAoB,SAAS,CAAY,GAClD,EAAS,MAAM,SAAS;CAC5B;AACJ,CACJ"}
@@ -1 +1 @@
1
- {"version":3,"file":"calendar-header.d.ts","sourceRoot":"","sources":["../../../src/components/page-calendar/calendar-header.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEtE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAW,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAEhD,KAAK,mBAAmB,GAAG;IACvB,WAAW,EAAE,IAAI,CAAC;IAClB,WAAW,EAAE,QAAQ,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB,cAAc,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC/B,cAAc,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACnC,cAAc,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CACxC,CAAC;AAEF,wBAAgB,cAAc,CAAC,EAC3B,WAAW,EACX,WAAW,EACX,OAAO,EACP,UAAU,EACV,cAAc,EACd,cAAc,EACd,cAAc,EACd,UAAU,GACb,EAAE,mBAAmB,+BAuHrB"}
1
+ {"version":3,"file":"calendar-header.d.ts","sourceRoot":"","sources":["../../../src/components/page-calendar/calendar-header.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEtE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAW,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAEhD,KAAK,mBAAmB,GAAG;IACvB,WAAW,EAAE,IAAI,CAAC;IAClB,WAAW,EAAE,QAAQ,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB,cAAc,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC/B,cAAc,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACnC,cAAc,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CACxC,CAAC;AAEF,wBAAgB,cAAc,CAAC,EAC3B,WAAW,EACX,WAAW,EACX,OAAO,EACP,UAAU,EACV,cAAc,EACd,cAAc,EACd,cAAc,EACd,UAAU,GACb,EAAE,mBAAmB,+BA0HrB"}
@@ -0,0 +1,2 @@
1
+ import { t as e } from "../../calendar-header-Dfr-CwkY.js";
2
+ export { e as CalendarHeader };
@@ -37,7 +37,7 @@ export function CalendarHeader({ currentDate, currentView, filters, filterArea,
37
37
  return (<header className="flex flex-col gap-page-calendar-header-gap">
38
38
  <div className="flex items-center justify-between gap-page-calendar-header-gap">
39
39
  <div className="flex items-center gap-page-calendar-date-gap">
40
- <div aria-hidden="true" className={`rounded-page-calendar-badge-radius flex size-page-calendar-badge-size flex-col items-center justify-center overflow-hidden text-page-calendar-week-label-text ${isDateToday ? "bg-primary text-primary-foreground" : "bg-card text-foreground"}`}>
40
+ <div aria-hidden="true" className={`flex size-page-calendar-badge-size flex-col items-center justify-center overflow-hidden rounded-page-calendar-badge-radius text-page-calendar-week-label-text ${isDateToday ? "bg-primary text-primary-foreground" : "bg-card text-foreground"}`}>
41
41
  <span className="font-light uppercase leading-none">{formatMonthShort(currentDate, locale)}</span>
42
42
  <span className="text-page-calendar-title-text font-medium leading-none">{formatDay(currentDate, locale)}</span>
43
43
  </div>
@@ -60,8 +60,8 @@ export function CalendarHeader({ currentDate, currentView, filters, filterArea,
60
60
  <CaretRightIcon size={16}/>
61
61
  </Button>
62
62
  </div>
63
- <div className="rounded-page-calendar-view-switch-radius flex">
64
- {VIEWS.map((v) => (<Button size="small" key={v.value} onClick={() => setCurrentView(v.value)} theme={currentView === v.value ? "primary" : "muted"} aria-pressed={currentView === v.value} className="first:rounded-l-button last:rounded-r-button rounded-button-radius-squared">
63
+ <div className="flex rounded-page-calendar-view-switch-radius">
64
+ {VIEWS.map((v) => (<Button size="small" key={v.value} rounded="squared" onClick={() => setCurrentView(v.value)} theme={currentView === v.value ? "primary" : "muted"} aria-pressed={currentView === v.value} className="first:rounded-l-button-radius last:rounded-r-button-radius">
65
65
  {v.label}
66
66
  </Button>))}
67
67
  </div>
@@ -73,7 +73,9 @@ export function CalendarHeader({ currentDate, currentView, filters, filterArea,
73
73
  </div>
74
74
  {filterArea ??
75
75
  (filters.length > 0 && (<div role="group" aria-label={t.pageCalendarFilter} className="flex flex-wrap items-center gap-page-calendar-filter-gap">
76
- <CalendarIcon size={14} className="text-muted-foreground" aria-hidden="true"/>
76
+ <span className="text-muted-foreground">
77
+ <CalendarIcon size={14} aria-hidden="true"/>
78
+ </span>
77
79
  <span className="mr-page-calendar-nav-mr text-page-calendar-filter-text text-muted-foreground">{t.pageCalendarFilter}</span>
78
80
  {filters.map((filter) => (<Tag as="button" size="small" type="button" key={filter.id} theme={filter.theme} indicator={filter.enabled ? filter.theme : undefined} aria-pressed={filter.enabled} aria-label={`${filter.label}, ${filter.enabled ? t.pageCalendarFilterEnabled : t.pageCalendarFilterDisabled}`} onClick={() => onToggleFilter(filter.id)}>
79
81
  {filter.label}
@@ -0,0 +1,124 @@
1
+ import { Tag as e } from "../core/tag.js";
2
+ import { t } from "../../use-locale-DPM_sg4s.js";
3
+ import { t as n } from "../../calendar-DEPkz8sw.js";
4
+ import { t as r } from "../../isToday-COXfxFui.js";
5
+ import { _ as i, a, c as o, f as s, i as c, n as l, s as u, t as d, u as f } from "../../page-calendar.utils-Bd0PHktL.js";
6
+ import { EventPill as p } from "./event-pill.js";
7
+ import { useEffect as m, useRef as h, useState as g } from "react";
8
+ import { Fragment as _, jsx as v, jsxs as y } from "react/jsx-runtime";
9
+ //#region src/components/page-calendar/day-view.tsx
10
+ var b = 48;
11
+ function x(e) {
12
+ let t = e.date.getHours(), n = e.date.getMinutes();
13
+ return t * b + n / 60 * b;
14
+ }
15
+ function S({ currentDate: S, onSlotClick: C, renderEvent: w, eventsByDate: T, onDateChange: E, onEventClick: D }) {
16
+ let O = t(), k = h(null), A = h(null), j = s(), [M, N] = g(null);
17
+ m(() => {
18
+ if (A.current && k.current) {
19
+ let e = k.current.offsetTop;
20
+ A.current.scrollTop = e - A.current.clientHeight / 2;
21
+ }
22
+ }, []);
23
+ let P = i(S), F = T.get(P) || [], I = ({ date: e }) => {
24
+ let t = i(e), n = (T.get(t) || []).length > 0, r = i(e) === i(S);
25
+ return !n || r ? null : /* @__PURE__ */ v("span", { className: "absolute bottom-page-calendar-dot-bottom left-1/2 size-page-calendar-dot-size -translate-x-1/2 rounded-full bg-primary" });
26
+ }, L = (e) => {
27
+ N(e), D(e);
28
+ };
29
+ return /* @__PURE__ */ y("div", {
30
+ className: "flex min-w-full flex-1",
31
+ children: [/* @__PURE__ */ y("div", {
32
+ className: "flex w-full flex-1 flex-col",
33
+ children: [/* @__PURE__ */ y("div", {
34
+ "aria-label": c(S, O),
35
+ className: "flex flex-shrink-0 items-center gap-page-calendar-day-header-gap border-b border-border px-page-calendar-day-header-px py-page-calendar-day-header-py",
36
+ children: [/* @__PURE__ */ v("span", {
37
+ className: `inline-flex size-page-calendar-day-badge-size items-center justify-center rounded-full font-bold ${r(S) ? "bg-primary text-primary-foreground" : "text-foreground"}`,
38
+ children: l(S, O)
39
+ }), /* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("div", {
40
+ className: "font-semibold",
41
+ children: f(S, O)
42
+ }), /* @__PURE__ */ v("div", {
43
+ className: "text-typography-xs text-muted-foreground",
44
+ children: u(S, O)
45
+ })] })]
46
+ }), /* @__PURE__ */ y("div", {
47
+ ref: A,
48
+ className: "flex flex-1 items-start overflow-y-auto",
49
+ children: [/* @__PURE__ */ v("div", {
50
+ className: "w-page-calendar-gutter-w flex-shrink-0",
51
+ children: j.map((e) => /* @__PURE__ */ y("div", {
52
+ className: "relative",
53
+ style: { height: b },
54
+ children: [/* @__PURE__ */ v("span", {
55
+ className: "absolute -top-2.5 right-2 text-page-calendar-hour-text text-muted-foreground",
56
+ children: e === 0 ? "" : a(e, O)
57
+ }), e === (/* @__PURE__ */ new Date()).getHours() && /* @__PURE__ */ v("div", { ref: k })]
58
+ }, e))
59
+ }), /* @__PURE__ */ y("div", {
60
+ className: "relative flex-1 border-l border-card-border",
61
+ children: [j.map((e) => {
62
+ let t = new Date(S);
63
+ return t.setHours(e, 0, 0, 0), /* @__PURE__ */ v("button", {
64
+ type: "button",
65
+ "aria-label": a(e, O),
66
+ className: "w-full cursor-pointer border-b border-border/50 hover:bg-muted/20",
67
+ style: { height: b },
68
+ onClick: () => C?.(t)
69
+ }, e);
70
+ }), d(F).map(({ event: e, columnIndex: t, columnCount: n }) => /* @__PURE__ */ v("div", {
71
+ role: "presentation",
72
+ className: "absolute",
73
+ style: {
74
+ top: x(e),
75
+ height: b,
76
+ left: `calc(${t / n * 100}% + 2px)`,
77
+ width: `calc(${100 / n}% - 4px)`
78
+ },
79
+ onClick: (e) => e.stopPropagation(),
80
+ onKeyDown: (e) => e.stopPropagation(),
81
+ children: /* @__PURE__ */ v(p, {
82
+ event: e,
83
+ onClick: () => L(e)
84
+ })
85
+ }, e.id))]
86
+ })]
87
+ })]
88
+ }), /* @__PURE__ */ y("div", {
89
+ className: "flex flex-col overflow-y-auto border-l border-card-border px-page-calendar-side-px",
90
+ children: [/* @__PURE__ */ v(n, {
91
+ date: S,
92
+ markToday: !0,
93
+ changeOnlyOnClick: !0,
94
+ RenderOnDay: I,
95
+ onChange: (e) => e && E(e)
96
+ }), M && /* @__PURE__ */ v("div", {
97
+ className: "flex flex-col gap-page-calendar-detail-gap border-t p-page-calendar-detail-p",
98
+ children: w ? w(M) : /* @__PURE__ */ y(_, { children: [
99
+ /* @__PURE__ */ v("div", {
100
+ className: "text-typography-sm truncate font-semibold",
101
+ children: M.title
102
+ }),
103
+ /* @__PURE__ */ v("div", {
104
+ className: "text-typography-xs text-muted-foreground",
105
+ children: c(M.date, O)
106
+ }),
107
+ /* @__PURE__ */ v("div", {
108
+ className: "text-typography-xs text-muted-foreground",
109
+ children: o(M.date, O)
110
+ }),
111
+ /* @__PURE__ */ v(e, {
112
+ theme: M.className ? "custom" : "primary",
113
+ size: "small",
114
+ className: `self-start${M.className ? ` ${M.className}` : ""}`
115
+ })
116
+ ] })
117
+ })]
118
+ })]
119
+ });
120
+ }
121
+ //#endregion
122
+ export { S as DayView };
123
+
124
+ //# sourceMappingURL=day-view.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"day-view.js","names":[],"sources":["../../../src/components/page-calendar/day-view.tsx"],"sourcesContent":["import { isToday } from \"date-fns\";\nimport { useEffect, useRef, useState } from \"react\";\nimport { Tag } from \"../core/tag\";\nimport { useLocale } from \"../../hooks/use-locale\";\nimport type { CalendarEvent, CalendarEventBase } from \"./page-calendar.types\";\nimport { EventPill } from \"./event-pill\";\nimport { Calendar } from \"../display/calendar\";\nimport {\n getHourSlots,\n toDateKey,\n formatDay,\n formatWeekdayLong,\n formatMonthYear,\n formatHourLabel,\n formatFullDate,\n formatTime,\n computeEventColumns,\n} from \"./page-calendar.utils\";\n\nconst HOUR_HEIGHT = 48;\n\nfunction getTopOffset(event: CalendarEvent): number {\n const hour = event.date.getHours();\n const minutes = event.date.getMinutes();\n return hour * HOUR_HEIGHT + (minutes / 60) * HOUR_HEIGHT;\n}\n\ntype DayViewProps<T extends CalendarEventBase> = {\n currentDate: Date;\n onDateChange: (date: Date) => void;\n onSlotClick?: (date: Date) => void;\n eventsByDate: Map<string, CalendarEvent<T>[]>;\n onEventClick: (event: CalendarEvent<T>) => void;\n renderEvent?: (event: CalendarEvent<T>) => React.ReactNode;\n};\n\nexport function DayView<T extends CalendarEventBase>({\n currentDate,\n onSlotClick,\n renderEvent,\n eventsByDate,\n onDateChange,\n onEventClick,\n}: DayViewProps<T>) {\n const locale = useLocale();\n const currentHourRef = useRef<HTMLDivElement>(null);\n const scrollBodyRef = useRef<HTMLDivElement>(null);\n const hours = getHourSlots();\n const [selectedEvent, setSelectedEvent] = useState<CalendarEvent<T> | null>(null);\n\n useEffect(() => {\n if (scrollBodyRef.current && currentHourRef.current) {\n const top = currentHourRef.current.offsetTop;\n scrollBodyRef.current.scrollTop = top - scrollBodyRef.current.clientHeight / 2;\n }\n }, []);\n\n const dayKey = toDateKey(currentDate);\n const events = eventsByDate.get(dayKey) || [];\n\n const RenderOnDay = ({ date }: { date: Date }) => {\n const key = toDateKey(date);\n const hasEvents = (eventsByDate.get(key) || []).length > 0;\n const isSelected = toDateKey(date) === toDateKey(currentDate);\n if (!hasEvents || isSelected) return null;\n return (\n <span className=\"absolute bottom-page-calendar-dot-bottom left-1/2 size-page-calendar-dot-size -translate-x-1/2 rounded-full bg-primary\" />\n );\n };\n\n const handleEventClick = (event: CalendarEvent<T>) => {\n setSelectedEvent(event);\n onEventClick(event);\n };\n\n return (\n <div className=\"flex min-w-full flex-1\">\n <div className=\"flex w-full flex-1 flex-col\">\n <div\n aria-label={formatFullDate(currentDate, locale)}\n className=\"flex flex-shrink-0 items-center gap-page-calendar-day-header-gap border-b border-border px-page-calendar-day-header-px py-page-calendar-day-header-py\"\n >\n <span\n className={`inline-flex size-page-calendar-day-badge-size items-center justify-center rounded-full font-bold ${isToday(currentDate) ? \"bg-primary text-primary-foreground\" : \"text-foreground\"}`}\n >\n {formatDay(currentDate, locale)}\n </span>\n <div>\n <div className=\"font-semibold\">{formatWeekdayLong(currentDate, locale)}</div>\n <div className=\"text-typography-xs text-muted-foreground\">{formatMonthYear(currentDate, locale)}</div>\n </div>\n </div>\n <div ref={scrollBodyRef} className=\"flex flex-1 items-start overflow-y-auto\">\n <div className=\"w-page-calendar-gutter-w flex-shrink-0\">\n {hours.map((hour) => (\n <div key={hour} className=\"relative\" style={{ height: HOUR_HEIGHT }}>\n <span className=\"absolute -top-2.5 right-2 text-page-calendar-hour-text text-muted-foreground\">\n {hour === 0 ? \"\" : formatHourLabel(hour, locale)}\n </span>\n {hour === new Date().getHours() && <div ref={currentHourRef} />}\n </div>\n ))}\n </div>\n <div className=\"relative flex-1 border-l border-card-border\">\n {hours.map((hour) => {\n const slotDate = new Date(currentDate);\n slotDate.setHours(hour, 0, 0, 0);\n return (\n <button\n key={hour}\n type=\"button\"\n aria-label={formatHourLabel(hour, locale)}\n className=\"w-full cursor-pointer border-b border-border/50 hover:bg-muted/20\"\n style={{ height: HOUR_HEIGHT }}\n onClick={() => onSlotClick?.(slotDate)}\n />\n );\n })}\n {computeEventColumns(events).map(({ event, columnIndex, columnCount }) => (\n <div\n key={event.id}\n role=\"presentation\"\n className=\"absolute\"\n style={{\n top: getTopOffset(event),\n height: HOUR_HEIGHT,\n left: `calc(${(columnIndex / columnCount) * 100}% + 2px)`,\n width: `calc(${100 / columnCount}% - 4px)`,\n }}\n onClick={(e) => e.stopPropagation()}\n onKeyDown={(e) => e.stopPropagation()}\n >\n <EventPill event={event} onClick={() => handleEventClick(event)} />\n </div>\n ))}\n </div>\n </div>\n </div>\n <div className=\"flex flex-col overflow-y-auto border-l border-card-border px-page-calendar-side-px\">\n <Calendar\n date={currentDate}\n markToday\n changeOnlyOnClick\n RenderOnDay={RenderOnDay}\n onChange={(d: Date | undefined) => d && onDateChange(d)}\n />\n {selectedEvent && (\n <div className=\"flex flex-col gap-page-calendar-detail-gap border-t p-page-calendar-detail-p\">\n {renderEvent ? (\n renderEvent(selectedEvent)\n ) : (\n <>\n <div className=\"text-typography-sm truncate font-semibold\">{selectedEvent.title}</div>\n <div className=\"text-typography-xs text-muted-foreground\">{formatFullDate(selectedEvent.date, locale)}</div>\n <div className=\"text-typography-xs text-muted-foreground\">{formatTime(selectedEvent.date, locale)}</div>\n <Tag\n theme={selectedEvent.className ? \"custom\" : \"primary\"}\n size=\"small\"\n className={`self-start${selectedEvent.className ? ` ${selectedEvent.className}` : \"\"}`}\n />\n </>\n )}\n </div>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ import { t as e } from "../../dom-Bn4wY_Zx.js";
2
+ import { t } from "../../use-translations-BE4PuhLm.js";
3
+ import { Button as n } from "../core/button.js";
4
+ import { r } from "../../page-calendar.utils-Bd0PHktL.js";
5
+ import { jsx as i, jsxs as a } from "react/jsx-runtime";
6
+ //#region src/components/page-calendar/event-pill.tsx
7
+ function o({ event: o, onClick: s, compact: c = !1 }) {
8
+ let l = t(), u = {
9
+ style: {
10
+ border: "0",
11
+ padding: "0 0.5rem",
12
+ height: "1.25rem",
13
+ borderRadius: "0.25rem"
14
+ },
15
+ className: e("w-full border-0 justify-start rounded-page-calendar-pill-radius text-page-calendar-pill-text truncate text-ellipsis overflow-hidden border leading-tight", o.className)
16
+ };
17
+ return c ? /* @__PURE__ */ i(n, {
18
+ ...u,
19
+ size: "small",
20
+ onClick: s,
21
+ title: o.title,
22
+ "aria-label": l.pageCalendarEventAt(o.title, r(o.date)),
23
+ theme: o.className ? "raw" : "primary",
24
+ children: o.title
25
+ }) : /* @__PURE__ */ a(n, {
26
+ ...u,
27
+ size: "small",
28
+ onClick: s,
29
+ title: o.title,
30
+ "aria-label": l.pageCalendarEventAt(o.title, r(o.date)),
31
+ theme: o.className ? "raw" : "primary",
32
+ children: [/* @__PURE__ */ i("div", {
33
+ className: "truncate font-medium",
34
+ children: o.title
35
+ }), /* @__PURE__ */ i("div", {
36
+ className: "text-page-calendar-pill-text opacity-60",
37
+ children: r(o.date)
38
+ })]
39
+ });
40
+ }
41
+ //#endregion
42
+ export { o as EventPill };
43
+
44
+ //# sourceMappingURL=event-pill.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-pill.js","names":[],"sources":["../../../src/components/page-calendar/event-pill.tsx"],"sourcesContent":["import { Button } from \"../core/button\";\nimport { css } from \"../../lib/dom\";\nimport { useTranslations } from \"../../hooks/use-translations\";\nimport type { CalendarEvent } from \"./page-calendar.types\";\nimport { formatEventTime } from \"./page-calendar.utils\";\nimport type { CSSProperties } from \"react\";\n\ntype EventPillProps = {\n compact?: boolean;\n onClick: () => void;\n event: CalendarEvent;\n};\n\nexport function EventPill({ event, onClick, compact = false }: EventPillProps) {\n const t = useTranslations();\n const props = {\n style: {\n border: \"0\",\n padding: \"0 0.5rem\",\n height: \"1.25rem\",\n borderRadius: \"0.25rem\",\n } as CSSProperties,\n className: css(\n \"w-full border-0 justify-start rounded-page-calendar-pill-radius text-page-calendar-pill-text truncate text-ellipsis overflow-hidden border leading-tight\",\n event.className\n ),\n };\n if (compact) {\n return (\n <Button\n {...props}\n size=\"small\"\n onClick={onClick}\n title={event.title}\n aria-label={t.pageCalendarEventAt(event.title, formatEventTime(event.date))}\n theme={event.className ? \"raw\" : \"primary\"}\n >\n {event.title}\n </Button>\n );\n }\n\n return (\n <Button\n {...props}\n size=\"small\"\n onClick={onClick}\n title={event.title}\n aria-label={t.pageCalendarEventAt(event.title, formatEventTime(event.date))}\n theme={event.className ? \"raw\" : \"primary\"}\n >\n <div className=\"truncate font-medium\">{event.title}</div>\n <div className=\"text-page-calendar-pill-text opacity-60\">{formatEventTime(event.date)}</div>\n </Button>\n );\n}\n"],"mappings":";;;;;;AAaA,SAAgB,EAAU,EAAE,UAAO,YAAS,aAAU,MAAyB;CAC3E,IAAM,IAAI,EAAgB,GACpB,IAAQ;EACV,OAAO;GACH,QAAQ;GACR,SAAS;GACT,QAAQ;GACR,cAAc;EAClB;EACA,WAAW,EACP,4JACA,EAAM,SACV;CACJ;CAgBA,OAfI,IAEI,kBAAC,GAAD;EACI,GAAI;EACJ,MAAK;EACI;EACT,OAAO,EAAM;EACb,cAAY,EAAE,oBAAoB,EAAM,OAAO,EAAgB,EAAM,IAAI,CAAC;EAC1E,OAAO,EAAM,YAAY,QAAQ;YAEhC,EAAM;CACH,CAAA,IAKZ,kBAAC,GAAD;EACI,GAAI;EACJ,MAAK;EACI;EACT,OAAO,EAAM;EACb,cAAY,EAAE,oBAAoB,EAAM,OAAO,EAAgB,EAAM,IAAI,CAAC;EAC1E,OAAO,EAAM,YAAY,QAAQ;YANrC,CAQI,kBAAC,OAAD;GAAK,WAAU;aAAwB,EAAM;EAAW,CAAA,GACxD,kBAAC,OAAD;GAAK,WAAU;aAA2C,EAAgB,EAAM,IAAI;EAAO,CAAA,CACvF;;AAEhB"}
@@ -1 +1 @@
1
- {"version":3,"file":"month-view.d.ts","sourceRoot":"","sources":["../../../src/components/page-calendar/month-view.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAK3D,KAAK,cAAc,GAAG;IAClB,IAAI,EAAE,IAAI,EAAE,CAAC;IACb,WAAW,EAAE,IAAI,CAAC;IAClB,UAAU,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IACjC,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC;IAC3C,YAAY,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;CAChD,CAAC;AAEF,wBAAgB,SAAS,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,EAAE,cAAc,+BAkEtG"}
1
+ {"version":3,"file":"month-view.d.ts","sourceRoot":"","sources":["../../../src/components/page-calendar/month-view.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAO3D,KAAK,cAAc,GAAG;IAClB,IAAI,EAAE,IAAI,EAAE,CAAC;IACb,WAAW,EAAE,IAAI,CAAC;IAClB,UAAU,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IACjC,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC;IAC3C,YAAY,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;CAChD,CAAC;AAEF,wBAAgB,SAAS,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,EAAE,cAAc,+BAiItG"}
@@ -0,0 +1,109 @@
1
+ import { t as e } from "../../dom-Bn4wY_Zx.js";
2
+ import { t } from "../../use-translations-BE4PuhLm.js";
3
+ import { t as n } from "../../use-locale-DPM_sg4s.js";
4
+ import { t as r } from "../../isToday-COXfxFui.js";
5
+ import { t as i } from "../../isSameMonth-C3lsSwcg.js";
6
+ import { _ as a, i as o, l as s, m as c, n as l } from "../../page-calendar.utils-Bd0PHktL.js";
7
+ import { EventPill as u } from "./event-pill.js";
8
+ import { useEffect as d, useMemo as f, useRef as p, useState as m } from "react";
9
+ import { jsx as h, jsxs as g } from "react/jsx-runtime";
10
+ //#region src/components/page-calendar/month-view.tsx
11
+ var _ = 7;
12
+ function v({ days: v, eventsByDate: y, currentDate: b, onEventClick: x, onDayClick: S }) {
13
+ let C = n(), w = t(), T = f(() => c(/* @__PURE__ */ new Date()), []), E = a(b), D = f(() => {
14
+ let e = v.findIndex((e) => a(e) === E);
15
+ return e >= 0 ? e : 0;
16
+ }, [v, E]), [O, k] = m(D), A = p([]), j = f(() => {
17
+ let e = [];
18
+ for (let t = 0; t < v.length; t += _) e.push(v.slice(t, t + _));
19
+ return e;
20
+ }, [v]);
21
+ d(() => {
22
+ k(D);
23
+ }, [D]);
24
+ let M = (e) => {
25
+ let t = Math.min(Math.max(e, 0), v.length - 1);
26
+ k(t), A.current[t]?.focus();
27
+ }, N = (e, t) => {
28
+ let n = Math.floor(t / _) * _, r = Math.min(n + _ - 1, v.length - 1), i = {
29
+ ArrowRight: t + 1,
30
+ ArrowLeft: t - 1,
31
+ ArrowDown: t + _,
32
+ ArrowUp: t - _,
33
+ Home: n,
34
+ End: r
35
+ }[e.key];
36
+ i !== void 0 && (e.preventDefault(), M(i));
37
+ };
38
+ return /* @__PURE__ */ h("div", {
39
+ className: "flex h-full flex-1 flex-col",
40
+ children: /* @__PURE__ */ g("div", {
41
+ role: "grid",
42
+ "aria-label": w.pageCalendarMonthGrid,
43
+ className: "flex flex-1 flex-col",
44
+ children: [/* @__PURE__ */ h("div", {
45
+ role: "row",
46
+ className: "grid grid-cols-7 border-b border-border",
47
+ children: T.map((e) => {
48
+ let t = s(e, C);
49
+ return /* @__PURE__ */ h("div", {
50
+ role: "columnheader",
51
+ className: "py-page-calendar-weekday-py text-center text-page-calendar-weekday-text font-medium text-muted-foreground",
52
+ children: t
53
+ }, t);
54
+ })
55
+ }), j.map((t, n) => /* @__PURE__ */ h("div", {
56
+ role: "row",
57
+ className: "grid flex-1 grid-cols-7",
58
+ children: t.map((t, s) => {
59
+ let c = n * _ + s, d = a(t), f = y.get(d) || [], p = i(t, b), m = r(t);
60
+ return /* @__PURE__ */ g("div", {
61
+ role: "gridcell",
62
+ "aria-selected": d === E ? !0 : void 0,
63
+ className: e("group flex min-h-page-calendar-cell-min-h flex-col gap-page-calendar-cell-gap border-b border-r border-border p-page-calendar-cell-p transition-colors hover:bg-muted hover:bg-opacity-20", !p && "opacity-50"),
64
+ children: [/* @__PURE__ */ g("button", {
65
+ type: "button",
66
+ ref: (e) => {
67
+ A.current[c] = e;
68
+ },
69
+ tabIndex: O === c ? 0 : -1,
70
+ onFocus: () => k(c),
71
+ onKeyDown: (e) => N(e, c),
72
+ onClick: () => S(t),
73
+ "aria-current": m ? "date" : void 0,
74
+ "aria-label": `${o(t, C)}${f.length > 0 ? `, ${w.pageCalendarEventCount(f.length)}` : ""}`,
75
+ className: "flex w-full cursor-pointer items-center justify-between text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary",
76
+ children: [/* @__PURE__ */ h("span", {
77
+ className: `flex size-page-calendar-month-badge-size items-center justify-center rounded-full text-page-calendar-month-badge-text font-medium ${m ? "bg-primary text-primary-foreground" : "text-foreground"}`,
78
+ children: l(t, C)
79
+ }), /* @__PURE__ */ h("span", {
80
+ "aria-hidden": "true",
81
+ className: "text-page-calendar-overflow-text leading-none text-muted-foreground opacity-0 transition-opacity group-hover:opacity-40",
82
+ children: "+"
83
+ })]
84
+ }), /* @__PURE__ */ h("div", {
85
+ className: "min-h-0 flex-1 overflow-y-auto",
86
+ children: /* @__PURE__ */ h("div", {
87
+ className: "flex flex-col gap-page-calendar-cell-gap-tight",
88
+ children: f.map((e) => /* @__PURE__ */ h("div", {
89
+ role: "presentation",
90
+ onClick: (e) => e.stopPropagation(),
91
+ onKeyDown: (e) => e.stopPropagation(),
92
+ children: /* @__PURE__ */ h(u, {
93
+ compact: !0,
94
+ event: e,
95
+ onClick: () => x(e)
96
+ })
97
+ }, e.id))
98
+ })
99
+ })]
100
+ }, d);
101
+ })
102
+ }, a(t[0])))]
103
+ })
104
+ });
105
+ }
106
+ //#endregion
107
+ export { v as MonthView };
108
+
109
+ //# sourceMappingURL=month-view.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"month-view.js","names":[],"sources":["../../../src/components/page-calendar/month-view.tsx"],"sourcesContent":["import { isSameMonth, isToday } from \"date-fns\";\nimport { useLocale } from \"../../hooks/use-locale\";\nimport { useTranslations } from \"../../hooks/use-translations\";\nimport { css } from \"../../lib/dom\";\nimport type { CalendarEvent } from \"./page-calendar.types\";\nimport { EventPill } from \"./event-pill\";\nimport { toDateKey, formatDay, getWeekDays, formatWeekDay, formatFullDate } from \"./page-calendar.utils\";\nimport { useEffect, useMemo, useRef, useState, type KeyboardEvent } from \"react\";\n\nconst daysInWeek = 7;\n\ntype MonthViewProps = {\n days: Date[];\n currentDate: Date;\n onDayClick: (date: Date) => void;\n eventsByDate: Map<string, CalendarEvent[]>;\n onEventClick: (event: CalendarEvent) => void;\n};\n\nexport function MonthView({ days, eventsByDate, currentDate, onEventClick, onDayClick }: MonthViewProps) {\n const locale = useLocale();\n const t = useTranslations();\n const WEEKDAY_LABELS = useMemo(() => getWeekDays(new Date()), []);\n const selectedDateKey = toDateKey(currentDate);\n const selectedDayIndex = useMemo(() => {\n const index = days.findIndex((day) => toDateKey(day) === selectedDateKey);\n return index >= 0 ? index : 0;\n }, [days, selectedDateKey]);\n const [focusedDayIndex, setFocusedDayIndex] = useState(selectedDayIndex);\n const dayButtonRefs = useRef<Array<HTMLButtonElement | null>>([]);\n const weeks = useMemo(() => {\n const rows: Date[][] = [];\n for (let rowStart = 0; rowStart < days.length; rowStart += daysInWeek) {\n rows.push(days.slice(rowStart, rowStart + daysInWeek));\n }\n return rows;\n }, [days]);\n\n useEffect(() => {\n setFocusedDayIndex(selectedDayIndex);\n }, [selectedDayIndex]);\n\n const moveFocus = (nextIndex: number) => {\n const boundedIndex = Math.min(Math.max(nextIndex, 0), days.length - 1);\n setFocusedDayIndex(boundedIndex);\n dayButtonRefs.current[boundedIndex]?.focus();\n };\n\n const handleDayKeyDown = (event: KeyboardEvent<HTMLButtonElement>, dayIndex: number) => {\n const weekStart = Math.floor(dayIndex / daysInWeek) * daysInWeek;\n const weekEnd = Math.min(weekStart + daysInWeek - 1, days.length - 1);\n const keyMoves: Partial<Record<string, number>> = {\n ArrowRight: dayIndex + 1,\n ArrowLeft: dayIndex - 1,\n ArrowDown: dayIndex + daysInWeek,\n ArrowUp: dayIndex - daysInWeek,\n Home: weekStart,\n End: weekEnd,\n };\n const nextIndex = keyMoves[event.key];\n if (nextIndex === undefined) return;\n event.preventDefault();\n moveFocus(nextIndex);\n };\n\n return (\n <div className=\"flex h-full flex-1 flex-col\">\n <div role=\"grid\" aria-label={t.pageCalendarMonthGrid} className=\"flex flex-1 flex-col\">\n <div role=\"row\" className=\"grid grid-cols-7 border-b border-border\">\n {WEEKDAY_LABELS.map((date) => {\n const day = formatWeekDay(date, locale);\n return (\n <div\n role=\"columnheader\"\n key={day}\n className=\"py-page-calendar-weekday-py text-center text-page-calendar-weekday-text font-medium text-muted-foreground\"\n >\n {day}\n </div>\n );\n })}\n </div>\n {weeks.map((week, weekIndex) => (\n <div role=\"row\" key={toDateKey(week[0])} className=\"grid flex-1 grid-cols-7\">\n {week.map((day, dayIndexInWeek) => {\n const dayIndex = weekIndex * daysInWeek + dayIndexInWeek;\n const key = toDateKey(day);\n const events = eventsByDate.get(key) || [];\n const isCurrentMonth = isSameMonth(day, currentDate);\n const isCurrentDay = isToday(day);\n const isSelected = key === selectedDateKey;\n return (\n <div\n key={key}\n role=\"gridcell\"\n aria-selected={isSelected ? true : undefined}\n className={css(\n \"group flex min-h-page-calendar-cell-min-h flex-col gap-page-calendar-cell-gap border-b border-r border-border p-page-calendar-cell-p transition-colors hover:bg-muted hover:bg-opacity-20\",\n !isCurrentMonth && \"opacity-50\"\n )}\n >\n <button\n type=\"button\"\n ref={(node) => {\n dayButtonRefs.current[dayIndex] = node;\n }}\n tabIndex={focusedDayIndex === dayIndex ? 0 : -1}\n onFocus={() => setFocusedDayIndex(dayIndex)}\n onKeyDown={(event) => handleDayKeyDown(event, dayIndex)}\n onClick={() => onDayClick(day)}\n aria-current={isCurrentDay ? \"date\" : undefined}\n aria-label={`${formatFullDate(day, locale)}${events.length > 0 ? `, ${t.pageCalendarEventCount(events.length)}` : \"\"}`}\n className=\"flex w-full cursor-pointer items-center justify-between text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary\"\n >\n <span\n className={`flex size-page-calendar-month-badge-size items-center justify-center rounded-full text-page-calendar-month-badge-text font-medium ${isCurrentDay ? \"bg-primary text-primary-foreground\" : \"text-foreground\"}`}\n >\n {formatDay(day, locale)}\n </span>\n <span\n aria-hidden=\"true\"\n className=\"text-page-calendar-overflow-text leading-none text-muted-foreground opacity-0 transition-opacity group-hover:opacity-40\"\n >\n +\n </span>\n </button>\n <div className=\"min-h-0 flex-1 overflow-y-auto\">\n <div className=\"flex flex-col gap-page-calendar-cell-gap-tight\">\n {events.map((event) => (\n <div\n key={event.id}\n role=\"presentation\"\n onClick={(event) => event.stopPropagation()}\n onKeyDown={(event) => event.stopPropagation()}\n >\n <EventPill compact event={event} onClick={() => onEventClick(event)} />\n </div>\n ))}\n </div>\n </div>\n </div>\n );\n })}\n </div>\n ))}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1,46 +1,93 @@
1
1
  import { isSameMonth, isToday } from "date-fns";
2
2
  import { useLocale } from "../../hooks/use-locale";
3
3
  import { useTranslations } from "../../hooks/use-translations";
4
+ import { css } from "../../lib/dom";
4
5
  import { EventPill } from "./event-pill";
5
6
  import { toDateKey, formatDay, getWeekDays, formatWeekDay, formatFullDate } from "./page-calendar.utils";
6
- import { useMemo } from "react";
7
+ import { useEffect, useMemo, useRef, useState } from "react";
8
+ const daysInWeek = 7;
7
9
  export function MonthView({ days, eventsByDate, currentDate, onEventClick, onDayClick }) {
8
10
  const locale = useLocale();
9
11
  const t = useTranslations();
10
12
  const WEEKDAY_LABELS = useMemo(() => getWeekDays(new Date()), []);
13
+ const selectedDateKey = toDateKey(currentDate);
14
+ const selectedDayIndex = useMemo(() => {
15
+ const index = days.findIndex((day) => toDateKey(day) === selectedDateKey);
16
+ return index >= 0 ? index : 0;
17
+ }, [days, selectedDateKey]);
18
+ const [focusedDayIndex, setFocusedDayIndex] = useState(selectedDayIndex);
19
+ const dayButtonRefs = useRef([]);
20
+ const weeks = useMemo(() => {
21
+ const rows = [];
22
+ for (let rowStart = 0; rowStart < days.length; rowStart += daysInWeek) {
23
+ rows.push(days.slice(rowStart, rowStart + daysInWeek));
24
+ }
25
+ return rows;
26
+ }, [days]);
27
+ useEffect(() => {
28
+ setFocusedDayIndex(selectedDayIndex);
29
+ }, [selectedDayIndex]);
30
+ const moveFocus = (nextIndex) => {
31
+ const boundedIndex = Math.min(Math.max(nextIndex, 0), days.length - 1);
32
+ setFocusedDayIndex(boundedIndex);
33
+ dayButtonRefs.current[boundedIndex]?.focus();
34
+ };
35
+ const handleDayKeyDown = (event, dayIndex) => {
36
+ const weekStart = Math.floor(dayIndex / daysInWeek) * daysInWeek;
37
+ const weekEnd = Math.min(weekStart + daysInWeek - 1, days.length - 1);
38
+ const keyMoves = {
39
+ ArrowRight: dayIndex + 1,
40
+ ArrowLeft: dayIndex - 1,
41
+ ArrowDown: dayIndex + daysInWeek,
42
+ ArrowUp: dayIndex - daysInWeek,
43
+ Home: weekStart,
44
+ End: weekEnd,
45
+ };
46
+ const nextIndex = keyMoves[event.key];
47
+ if (nextIndex === undefined)
48
+ return;
49
+ event.preventDefault();
50
+ moveFocus(nextIndex);
51
+ };
11
52
  return (<div className="flex h-full flex-1 flex-col">
12
- <ul role="row" aria-hidden="true" className="grid grid-cols-7 border-b border-border">
13
- {WEEKDAY_LABELS.map((date) => {
53
+ <div role="grid" aria-label={t.pageCalendarMonthGrid} className="flex flex-1 flex-col">
54
+ <div role="row" className="grid grid-cols-7 border-b border-border">
55
+ {WEEKDAY_LABELS.map((date) => {
14
56
  const day = formatWeekDay(date, locale);
15
- return (<li key={day} className="py-page-calendar-weekday-py text-center text-page-calendar-weekday-text font-medium text-muted-foreground">
16
- {day}
17
- </li>);
18
- })}
19
- </ul>
20
- <div role="grid" aria-label={t.pageCalendarMonthGrid} className="grid flex-1 auto-rows-fr grid-cols-7">
21
- {days.map((day, idx) => {
22
- const key = toDateKey(day);
23
- const events = eventsByDate.get(key) || [];
24
- const isCurrentMonth = isSameMonth(day, currentDate);
25
- const isCurrentDay = isToday(day);
26
- return (<button key={idx} type="button" onClick={() => onDayClick(day)} aria-label={`${formatFullDate(day, locale)}${events.length > 0 ? `, ${t.pageCalendarEventCount(events.length)}` : ""}`} className={`group flex min-h-page-calendar-cell-min-h cursor-pointer flex-col gap-page-calendar-cell-gap border-b border-r border-border p-page-calendar-cell-p transition-colors hover:bg-muted hover:bg-opacity-20 ${!isCurrentMonth ? "opacity-50" : ""}`}>
27
- <div className="flex items-center justify-between">
28
- <span className={`flex size-page-calendar-month-badge-size items-center justify-center rounded-full text-page-calendar-month-badge-text font-medium ${isCurrentDay ? "bg-primary text-primary-foreground" : "text-foreground"}`}>
29
- {formatDay(day, locale)}
30
- </span>
31
- <span aria-hidden="true" className="text-page-calendar-overflow-text leading-none text-muted-foreground opacity-0 transition-opacity group-hover:opacity-40">
32
- +
33
- </span>
34
- </div>
35
- <div className="min-h-0 flex-1 overflow-y-auto">
36
- <div className="flex flex-col gap-page-calendar-cell-gap-tight">
37
- {events.map((event) => (<div key={event.id} role="presentation" onClick={(e) => e.stopPropagation()} onKeyDown={(e) => e.stopPropagation()}>
38
- <EventPill compact event={event} onClick={() => onEventClick(event)}/>
39
- </div>))}
40
- </div>
41
- </div>
42
- </button>);
57
+ return (<div role="columnheader" key={day} className="py-page-calendar-weekday-py text-center text-page-calendar-weekday-text font-medium text-muted-foreground">
58
+ {day}
59
+ </div>);
43
60
  })}
61
+ </div>
62
+ {weeks.map((week, weekIndex) => (<div role="row" key={toDateKey(week[0])} className="grid flex-1 grid-cols-7">
63
+ {week.map((day, dayIndexInWeek) => {
64
+ const dayIndex = weekIndex * daysInWeek + dayIndexInWeek;
65
+ const key = toDateKey(day);
66
+ const events = eventsByDate.get(key) || [];
67
+ const isCurrentMonth = isSameMonth(day, currentDate);
68
+ const isCurrentDay = isToday(day);
69
+ const isSelected = key === selectedDateKey;
70
+ return (<div key={key} role="gridcell" aria-selected={isSelected ? true : undefined} className={css("group flex min-h-page-calendar-cell-min-h flex-col gap-page-calendar-cell-gap border-b border-r border-border p-page-calendar-cell-p transition-colors hover:bg-muted hover:bg-opacity-20", !isCurrentMonth && "opacity-50")}>
71
+ <button type="button" ref={(node) => {
72
+ dayButtonRefs.current[dayIndex] = node;
73
+ }} tabIndex={focusedDayIndex === dayIndex ? 0 : -1} onFocus={() => setFocusedDayIndex(dayIndex)} onKeyDown={(event) => handleDayKeyDown(event, dayIndex)} onClick={() => onDayClick(day)} aria-current={isCurrentDay ? "date" : undefined} aria-label={`${formatFullDate(day, locale)}${events.length > 0 ? `, ${t.pageCalendarEventCount(events.length)}` : ""}`} className="flex w-full cursor-pointer items-center justify-between text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary">
74
+ <span className={`flex size-page-calendar-month-badge-size items-center justify-center rounded-full text-page-calendar-month-badge-text font-medium ${isCurrentDay ? "bg-primary text-primary-foreground" : "text-foreground"}`}>
75
+ {formatDay(day, locale)}
76
+ </span>
77
+ <span aria-hidden="true" className="text-page-calendar-overflow-text leading-none text-muted-foreground opacity-0 transition-opacity group-hover:opacity-40">
78
+ +
79
+ </span>
80
+ </button>
81
+ <div className="min-h-0 flex-1 overflow-y-auto">
82
+ <div className="flex flex-col gap-page-calendar-cell-gap-tight">
83
+ {events.map((event) => (<div key={event.id} role="presentation" onClick={(event) => event.stopPropagation()} onKeyDown={(event) => event.stopPropagation()}>
84
+ <EventPill compact event={event} onClick={() => onEventClick(event)}/>
85
+ </div>))}
86
+ </div>
87
+ </div>
88
+ </div>);
89
+ })}
90
+ </div>))}
44
91
  </div>
45
92
  </div>);
46
93
  }
@@ -1 +1 @@
1
- {"version":3,"file":"page-calendar.d.ts","sourceRoot":"","sources":["../../../src/components/page-calendar/page-calendar.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAE1D,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAOxG,KAAK,iBAAiB,CAAC,CAAC,SAAS,iBAAiB,IAAI;IAClD,WAAW,CAAC,EAAE,IAAI,CAAC;IACnB,WAAW,CAAC,EAAE,QAAQ,CAAC;IACvB,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3B,OAAO,CAAC,EAAE,cAAc,EAAE,CAAC;IAC3B,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IACnC,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAC9C,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC;IACrD,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,IAAI,CAAC;CACzD,CAAC;AAIF,wBAAgB,YAAY,CAAC,CAAC,SAAS,iBAAiB,EAAE,EACtD,MAAM,EACN,UAAU,EACV,UAAU,EACV,WAAW,EACX,WAAW,EACX,WAAW,EACX,WAAW,EACX,YAAY,EACZ,OAAc,EACd,WAAqB,EACrB,eAAe,EAAE,qBAAqB,GACzC,EAAE,iBAAiB,CAAC,CAAC,CAAC,+BAyEtB"}
1
+ {"version":3,"file":"page-calendar.d.ts","sourceRoot":"","sources":["../../../src/components/page-calendar/page-calendar.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAE1D,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAOxG,KAAK,iBAAiB,CAAC,CAAC,SAAS,iBAAiB,IAAI;IAClD,WAAW,CAAC,EAAE,IAAI,CAAC;IACnB,WAAW,CAAC,EAAE,QAAQ,CAAC;IACvB,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3B,OAAO,CAAC,EAAE,cAAc,EAAE,CAAC;IAC3B,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IACnC,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAC9C,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC;IACrD,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,IAAI,CAAC;CACzD,CAAC;AAIF,wBAAgB,YAAY,CAAC,CAAC,SAAS,iBAAiB,EAAE,EACtD,MAAM,EACN,UAAU,EACV,UAAU,EACV,WAAW,EACX,WAAW,EACX,WAAW,EACX,WAAW,EACX,YAAY,EACZ,OAAc,EACd,WAAqB,EACrB,eAAe,EAAE,qBAAqB,GACzC,EAAE,iBAAiB,CAAC,CAAC,CAAC,+BA6EtB"}