@opengeni/react 1.4.0 → 1.4.2

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 (212) hide show
  1. package/README.md +8 -0
  2. package/dist/accounts.js +2 -0
  3. package/dist/accounts.js.map +1 -1
  4. package/dist/artifacts-document.js +5 -4
  5. package/dist/artifacts-presentation.js +5 -4
  6. package/dist/artifacts-spreadsheet.js +4 -3
  7. package/dist/artifacts.js +14 -13
  8. package/dist/artifacts.js.map +1 -1
  9. package/dist/browser-viewer-WGJ43YGI.js +17 -0
  10. package/dist/chat-interactive-block-ZFHOKTMS.js +12 -0
  11. package/dist/{chunk-WEHMPOXK.js → chunk-2DDJ6YH6.js} +3 -1
  12. package/dist/{chunk-WEHMPOXK.js.map → chunk-2DDJ6YH6.js.map} +1 -1
  13. package/dist/{chunk-C5X5AJXK.js → chunk-2HVLQ26H.js} +5 -4
  14. package/dist/{chunk-C5X5AJXK.js.map → chunk-2HVLQ26H.js.map} +1 -1
  15. package/dist/{chunk-A4UJB2MM.js → chunk-32CGLXW2.js} +4 -3
  16. package/dist/{chunk-A4UJB2MM.js.map → chunk-32CGLXW2.js.map} +1 -1
  17. package/dist/{chunk-5CVXZA3Y.js → chunk-45NUOSXQ.js} +3 -2
  18. package/dist/{chunk-5CVXZA3Y.js.map → chunk-45NUOSXQ.js.map} +1 -1
  19. package/dist/{chunk-WUISZ3WU.js → chunk-53KJBGPZ.js} +5 -4
  20. package/dist/{chunk-WUISZ3WU.js.map → chunk-53KJBGPZ.js.map} +1 -1
  21. package/dist/{chunk-MBMPHOMA.js → chunk-55DXD22O.js} +3 -2
  22. package/dist/{chunk-MBMPHOMA.js.map → chunk-55DXD22O.js.map} +1 -1
  23. package/dist/{chunk-JT4JW7BC.js → chunk-5I4VRWBB.js} +3 -1
  24. package/dist/{chunk-JT4JW7BC.js.map → chunk-5I4VRWBB.js.map} +1 -1
  25. package/dist/{chunk-UK4TINKT.js → chunk-B27E3V37.js} +3 -1
  26. package/dist/{chunk-UK4TINKT.js.map → chunk-B27E3V37.js.map} +1 -1
  27. package/dist/{chunk-J6DBS4T3.js → chunk-BNKV5ZLF.js} +5 -4
  28. package/dist/{chunk-J6DBS4T3.js.map → chunk-BNKV5ZLF.js.map} +1 -1
  29. package/dist/{chunk-YM2DE7BQ.js → chunk-C5BF4L26.js} +13 -12
  30. package/dist/{chunk-YM2DE7BQ.js.map → chunk-C5BF4L26.js.map} +1 -1
  31. package/dist/{chunk-YBXQDQFX.js → chunk-C7CMD56T.js} +6 -5
  32. package/dist/{chunk-YBXQDQFX.js.map → chunk-C7CMD56T.js.map} +1 -1
  33. package/dist/{chunk-UGLEYEMP.js → chunk-CM7LVUKC.js} +3 -1
  34. package/dist/{chunk-UGLEYEMP.js.map → chunk-CM7LVUKC.js.map} +1 -1
  35. package/dist/{chunk-LJ2UTJJE.js → chunk-CREMJMVN.js} +181 -96
  36. package/dist/chunk-CREMJMVN.js.map +1 -0
  37. package/dist/{chunk-JVYQRRC4.js → chunk-CVYCLFMH.js} +3 -1
  38. package/dist/{chunk-JVYQRRC4.js.map → chunk-CVYCLFMH.js.map} +1 -1
  39. package/dist/{chunk-Y2PRMYLC.js → chunk-G3U2A6GS.js} +3 -2
  40. package/dist/{chunk-Y2PRMYLC.js.map → chunk-G3U2A6GS.js.map} +1 -1
  41. package/dist/{chunk-WZMYFJD3.js → chunk-G6YRCIYJ.js} +16 -7
  42. package/dist/{chunk-WZMYFJD3.js.map → chunk-G6YRCIYJ.js.map} +1 -1
  43. package/dist/{chunk-B3V6TG77.js → chunk-GC3PH6N7.js} +3 -1
  44. package/dist/{chunk-B3V6TG77.js.map → chunk-GC3PH6N7.js.map} +1 -1
  45. package/dist/{chunk-CJUO7J5Z.js → chunk-HXYOSSQO.js} +3 -2
  46. package/dist/{chunk-CJUO7J5Z.js.map → chunk-HXYOSSQO.js.map} +1 -1
  47. package/dist/{chunk-BRM6FVZA.js → chunk-IEE7WCLN.js} +4 -3
  48. package/dist/{chunk-BRM6FVZA.js.map → chunk-IEE7WCLN.js.map} +1 -1
  49. package/dist/{chunk-DYWBUX5Q.js → chunk-IMSUVYQB.js} +6 -5
  50. package/dist/{chunk-DYWBUX5Q.js.map → chunk-IMSUVYQB.js.map} +1 -1
  51. package/dist/{chunk-LN6TCXD3.js → chunk-IUHHPMAX.js} +184 -48
  52. package/dist/chunk-IUHHPMAX.js.map +1 -0
  53. package/dist/{chunk-SGKD2OCN.js → chunk-IYQCWGU5.js} +6 -5
  54. package/dist/{chunk-SGKD2OCN.js.map → chunk-IYQCWGU5.js.map} +1 -1
  55. package/dist/{chunk-J2QWVSQY.js → chunk-JH7V627O.js} +8 -7
  56. package/dist/{chunk-J2QWVSQY.js.map → chunk-JH7V627O.js.map} +1 -1
  57. package/dist/{chunk-EESD3PY3.js → chunk-JHTIMBOL.js} +6 -5
  58. package/dist/{chunk-EESD3PY3.js.map → chunk-JHTIMBOL.js.map} +1 -1
  59. package/dist/{chunk-LNIRAOA3.js → chunk-L2J3PU7A.js} +7 -6
  60. package/dist/{chunk-LNIRAOA3.js.map → chunk-L2J3PU7A.js.map} +1 -1
  61. package/dist/{chunk-ZYRGEKWS.js → chunk-LJUMYUBO.js} +3 -1
  62. package/dist/{chunk-ZYRGEKWS.js.map → chunk-LJUMYUBO.js.map} +1 -1
  63. package/dist/{chunk-4RVYOY4O.js → chunk-LSW2OJVV.js} +4 -3
  64. package/dist/{chunk-4RVYOY4O.js.map → chunk-LSW2OJVV.js.map} +1 -1
  65. package/dist/{chunk-UTRTG6LH.js → chunk-LVS3MH5T.js} +3 -1
  66. package/dist/{chunk-UTRTG6LH.js.map → chunk-LVS3MH5T.js.map} +1 -1
  67. package/dist/chunk-M357MHH3.js +2 -0
  68. package/dist/{chunk-GYVRFZDY.js → chunk-MDIXFKA3.js} +9 -8
  69. package/dist/{chunk-GYVRFZDY.js.map → chunk-MDIXFKA3.js.map} +1 -1
  70. package/dist/{chunk-WRHIZYZF.js → chunk-MEQM4LI3.js} +6 -5
  71. package/dist/{chunk-WRHIZYZF.js.map → chunk-MEQM4LI3.js.map} +1 -1
  72. package/dist/chunk-NX4ADH73.js +14 -0
  73. package/dist/chunk-NX4ADH73.js.map +1 -0
  74. package/dist/{chunk-XCHWDJ22.js → chunk-OGTTUYNT.js} +3 -1
  75. package/dist/{chunk-XCHWDJ22.js.map → chunk-OGTTUYNT.js.map} +1 -1
  76. package/dist/{chunk-GIMRELBW.js → chunk-OYQQJL3J.js} +3 -1
  77. package/dist/{chunk-GIMRELBW.js.map → chunk-OYQQJL3J.js.map} +1 -1
  78. package/dist/{chunk-RSI7XYXL.js → chunk-PBCZL4JP.js} +6 -5
  79. package/dist/{chunk-RSI7XYXL.js.map → chunk-PBCZL4JP.js.map} +1 -1
  80. package/dist/{chunk-I7IWRQLN.js → chunk-PHBFJCEU.js} +17 -11
  81. package/dist/chunk-PHBFJCEU.js.map +1 -0
  82. package/dist/{chunk-3CTRFMAK.js → chunk-PKCAYHDC.js} +5 -4
  83. package/dist/{chunk-3CTRFMAK.js.map → chunk-PKCAYHDC.js.map} +1 -1
  84. package/dist/{chunk-K3HQAKQX.js → chunk-PMV53IMM.js} +3 -1
  85. package/dist/{chunk-K3HQAKQX.js.map → chunk-PMV53IMM.js.map} +1 -1
  86. package/dist/{chunk-YQEAA6LT.js → chunk-QHUE7E4N.js} +3 -2
  87. package/dist/{chunk-YQEAA6LT.js.map → chunk-QHUE7E4N.js.map} +1 -1
  88. package/dist/{chunk-OA6HFRQP.js → chunk-QMMCJGFI.js} +4 -3
  89. package/dist/{chunk-OA6HFRQP.js.map → chunk-QMMCJGFI.js.map} +1 -1
  90. package/dist/{chunk-YV4L3ILF.js → chunk-QV3DJVRZ.js} +3 -1
  91. package/dist/{chunk-YV4L3ILF.js.map → chunk-QV3DJVRZ.js.map} +1 -1
  92. package/dist/{chunk-447JLCBU.js → chunk-S2QH6EZ5.js} +3 -1
  93. package/dist/{chunk-447JLCBU.js.map → chunk-S2QH6EZ5.js.map} +1 -1
  94. package/dist/{chunk-PNY3JKBJ.js → chunk-SFH43JT2.js} +5 -4
  95. package/dist/{chunk-PNY3JKBJ.js.map → chunk-SFH43JT2.js.map} +1 -1
  96. package/dist/{chunk-AWZLIMKX.js → chunk-T46QZH3E.js} +3 -1
  97. package/dist/{chunk-AWZLIMKX.js.map → chunk-T46QZH3E.js.map} +1 -1
  98. package/dist/{chunk-5J4FOW6Q.js → chunk-TNEZNMSN.js} +3 -1
  99. package/dist/{chunk-5J4FOW6Q.js.map → chunk-TNEZNMSN.js.map} +1 -1
  100. package/dist/{chunk-22KP6LR5.js → chunk-TXS65BB2.js} +3 -1
  101. package/dist/{chunk-22KP6LR5.js.map → chunk-TXS65BB2.js.map} +1 -1
  102. package/dist/{chunk-H5X55XH7.js → chunk-UDPH5SLV.js} +4 -3
  103. package/dist/{chunk-H5X55XH7.js.map → chunk-UDPH5SLV.js.map} +1 -1
  104. package/dist/{chunk-HDJWDK7W.js → chunk-VCSERYXH.js} +10 -9
  105. package/dist/{chunk-HDJWDK7W.js.map → chunk-VCSERYXH.js.map} +1 -1
  106. package/dist/{chunk-VZTQ73XT.js → chunk-XEA5BCMA.js} +3 -1
  107. package/dist/{chunk-VZTQ73XT.js.map → chunk-XEA5BCMA.js.map} +1 -1
  108. package/dist/{chunk-5F4WR7X7.js → chunk-XS67YG5R.js} +3 -1
  109. package/dist/{chunk-5F4WR7X7.js.map → chunk-XS67YG5R.js.map} +1 -1
  110. package/dist/{chunk-TKOTKRWY.js → chunk-XTD7TZHW.js} +3 -1
  111. package/dist/{chunk-TKOTKRWY.js.map → chunk-XTD7TZHW.js.map} +1 -1
  112. package/dist/{chunk-A2PI6UMY.js → chunk-YSRBFJMQ.js} +3 -1
  113. package/dist/{chunk-A2PI6UMY.js.map → chunk-YSRBFJMQ.js.map} +1 -1
  114. package/dist/chunk-YVFRBXST.js +1420 -0
  115. package/dist/chunk-YVFRBXST.js.map +1 -0
  116. package/dist/{chunk-SCOTPE2I.js → chunk-YYLBXXTE.js} +3 -1
  117. package/dist/{chunk-SCOTPE2I.js.map → chunk-YYLBXXTE.js.map} +1 -1
  118. package/dist/{chunk-RHREZ7BO.js → chunk-ZUWF4NF7.js} +3 -1
  119. package/dist/{chunk-RHREZ7BO.js.map → chunk-ZUWF4NF7.js.map} +1 -1
  120. package/dist/clipboard.js +3 -2
  121. package/dist/components/composer-transcription-control.d.ts +4 -0
  122. package/dist/components/session-conversation.d.ts +6 -0
  123. package/dist/composer-voice-events.d.ts +8 -0
  124. package/dist/composer.js +15 -13
  125. package/dist/computer-viewer-46UIN7F3.js +20 -0
  126. package/dist/connect.js +15 -12
  127. package/dist/connect.js.map +1 -1
  128. package/dist/desktop.js +6 -5
  129. package/dist/desktop.js.map +1 -1
  130. package/dist/diffs.js +2 -1
  131. package/dist/diffs.js.map +1 -1
  132. package/dist/editor.js +4 -3
  133. package/dist/editor.js.map +1 -1
  134. package/dist/embedded-voice-NIL4RDX3.js +69 -0
  135. package/dist/embedded-voice-NIL4RDX3.js.map +1 -0
  136. package/dist/{fleet-decision-row-YZ3ZKWMM.js → fleet-decision-row-SI63O5V4.js} +3 -1
  137. package/dist/{fleet-decision-row-YZ3ZKWMM.js.map → fleet-decision-row-SI63O5V4.js.map} +1 -1
  138. package/dist/hooks/use-client-config-flags.d.ts +6 -0
  139. package/dist/hooks/use-realtime-voice-models.d.ts +9 -0
  140. package/dist/hooks/use-voice-input.d.ts +8 -1
  141. package/dist/index.js +47 -45
  142. package/dist/index.js.map +1 -1
  143. package/dist/interaction.js +14 -13
  144. package/dist/interaction.js.map +1 -1
  145. package/dist/{latest-question-GPYM2JNU.js → latest-question-2POFPYNB.js} +5 -4
  146. package/dist/{latest-question-GPYM2JNU.js.map → latest-question-2POFPYNB.js.map} +1 -1
  147. package/dist/machines.js +8 -7
  148. package/dist/{markdown-table-layout-QXSLK4BY.js → markdown-table-layout-DQ4DRNVT.js} +3 -1
  149. package/dist/{markdown-table-layout-QXSLK4BY.js.map → markdown-table-layout-DQ4DRNVT.js.map} +1 -1
  150. package/dist/model-policy-picker-menu-WRNSRFQC.js +15 -0
  151. package/dist/model-policy.js +2 -1
  152. package/dist/{noto-sans-arabic-loader-IA2T4X2A.js → noto-sans-arabic-loader-XSH2KYWJ.js} +3 -1
  153. package/dist/{noto-sans-arabic-loader-IA2T4X2A.js.map → noto-sans-arabic-loader-XSH2KYWJ.js.map} +1 -1
  154. package/dist/{noto-sans-jp-loader.generated-HFGLYBR3.js → noto-sans-jp-loader.generated-MR5L6V7K.js} +3 -1
  155. package/dist/{noto-sans-jp-loader.generated-HFGLYBR3.js.map → noto-sans-jp-loader.generated-MR5L6V7K.js.map} +1 -1
  156. package/dist/{platform-activity-row-627BFZ46.js → platform-activity-row-PJJVATTZ.js} +3 -1
  157. package/dist/{platform-activity-row-627BFZ46.js.map → platform-activity-row-PJJVATTZ.js.map} +1 -1
  158. package/dist/{queue-surface-implementation-ZHFI5JBP.js → queue-surface-implementation-67FS7FUI.js} +10 -9
  159. package/dist/{queue-surface-implementation-ZHFI5JBP.js.map → queue-surface-implementation-67FS7FUI.js.map} +1 -1
  160. package/dist/realtime/embedded-voice.d.ts +20 -0
  161. package/dist/realtime.js +22 -1353
  162. package/dist/realtime.js.map +1 -1
  163. package/dist/sandbox-files-34CJJNOY.js +21 -0
  164. package/dist/session-ui.js +32 -30
  165. package/dist/session-ui.js.map +1 -1
  166. package/dist/session.js +10 -9
  167. package/dist/sites.js +2 -1
  168. package/dist/terminal.js +6 -5
  169. package/dist/terminal.js.map +1 -1
  170. package/dist/{timeline-annotation-markers-GNDHTGBD.js → timeline-annotation-markers-U3G66KUD.js} +5 -4
  171. package/dist/{timeline-annotation-markers-GNDHTGBD.js.map → timeline-annotation-markers-U3G66KUD.js.map} +1 -1
  172. package/dist/{timeline-annotation-selection-DMLMM2TX.js → timeline-annotation-selection-BI7QTPTZ.js} +4 -3
  173. package/dist/{timeline-annotation-selection-DMLMM2TX.js.map → timeline-annotation-selection-BI7QTPTZ.js.map} +1 -1
  174. package/dist/{timeline-annotations-dialog-ELRDBHTS.js → timeline-annotations-dialog-FOMHSDTE.js} +7 -6
  175. package/dist/{timeline-annotations-dialog-ELRDBHTS.js.map → timeline-annotations-dialog-FOMHSDTE.js.map} +1 -1
  176. package/dist/usage.js +6 -5
  177. package/dist/usage.js.map +1 -1
  178. package/dist/voice-recording-owner.d.ts +7 -0
  179. package/package.json +3 -3
  180. package/src/components/composer-transcription-control.tsx +109 -27
  181. package/src/components/markdown.tsx +7 -2
  182. package/src/components/message-timeline.tsx +10 -1
  183. package/src/components/session-conversation.tsx +44 -0
  184. package/src/components/session-proxy-scope.tsx +26 -5
  185. package/src/composer-voice-events.ts +12 -0
  186. package/src/connection-discovery.tsx +4 -1
  187. package/src/hooks/use-client-config-flags.ts +8 -0
  188. package/src/hooks/use-goal.ts +12 -1
  189. package/src/hooks/use-realtime-voice-models.ts +67 -0
  190. package/src/hooks/use-voice-input.ts +109 -18
  191. package/src/realtime/embedded-voice.tsx +81 -0
  192. package/src/realtime/realtime-control.tsx +82 -17
  193. package/src/voice-recording-owner.ts +22 -0
  194. package/styles/compiled.css +72 -18
  195. package/styles/index.css +49 -0
  196. package/styles/responsive.css +61 -4
  197. package/styles/session-capability.css +1 -1
  198. package/dist/browser-viewer-SHYKQRNX.js +0 -16
  199. package/dist/chat-interactive-block-UGBTNB3L.js +0 -11
  200. package/dist/chunk-I7IWRQLN.js.map +0 -1
  201. package/dist/chunk-IWIDV7SB.js +0 -1
  202. package/dist/chunk-LJ2UTJJE.js.map +0 -1
  203. package/dist/chunk-LN6TCXD3.js.map +0 -1
  204. package/dist/computer-viewer-6SRGWRUX.js +0 -19
  205. package/dist/model-policy-picker-menu-DXHUL73H.js +0 -14
  206. package/dist/sandbox-files-GORZOUUJ.js +0 -20
  207. /package/dist/{browser-viewer-SHYKQRNX.js.map → browser-viewer-WGJ43YGI.js.map} +0 -0
  208. /package/dist/{chat-interactive-block-UGBTNB3L.js.map → chat-interactive-block-ZFHOKTMS.js.map} +0 -0
  209. /package/dist/{chunk-IWIDV7SB.js.map → chunk-M357MHH3.js.map} +0 -0
  210. /package/dist/{computer-viewer-6SRGWRUX.js.map → computer-viewer-46UIN7F3.js.map} +0 -0
  211. /package/dist/{model-policy-picker-menu-DXHUL73H.js.map → model-policy-picker-menu-WRNSRFQC.js.map} +0 -0
  212. /package/dist/{sandbox-files-GORZOUUJ.js.map → sandbox-files-34CJJNOY.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/timeline-annotation-selection.tsx"],"sourcesContent":["import type { DraftTimelineAnnotation } from \"@opengeni/sdk\";\nimport { QuoteIcon } from \"lucide-react\";\nimport { useEffect, useRef, useState, type RefObject } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { usePortalTokenStyle } from \"../lib/use-portal-token-style\";\nimport type { TimelineAnnotationSourceDescriptor } from \"../timeline\";\nimport {\n clipRangeToSource,\n matchingQuoteInSource,\n occurrenceOffsets,\n quoteOccurrenceIndex,\n truncateAnnotationQuote,\n visibleClientRect,\n} from \"./timeline-annotation-shared\";\n\ntype SelectionCandidate = {\n annotation: DraftTimelineAnnotation;\n left: number;\n top: number;\n keyboard: boolean;\n};\n\nconst CONTROL_SELECTOR = \"button,input,textarea,select,summary,[contenteditable='true']\";\nconst SOURCE_CONTEXT_BYTES = 160;\nconst MAX_QUOTE_BYTES = 16 * 1024;\nconst POPOVER_WIDTH = 280;\nconst POPOVER_HEIGHT = 64;\n\nfunction utf8Prefix(value: string, maxBytes: number): string {\n let output = \"\";\n let bytes = 0;\n for (const character of value) {\n const next = new TextEncoder().encode(character).byteLength;\n if (bytes + next > maxBytes) break;\n output += character;\n bytes += next;\n }\n return output;\n}\n\nfunction utf8Suffix(value: string, maxBytes: number): string {\n let output = \"\";\n let bytes = 0;\n for (const character of [...value].reverse()) {\n const next = new TextEncoder().encode(character).byteLength;\n if (bytes + next > maxBytes) break;\n output = character + output;\n bytes += next;\n }\n return output;\n}\n\nfunction selectionElement(node: Node | null): Element | null {\n return node instanceof Element ? node : (node?.parentElement ?? null);\n}\n\nfunction containingSource(node: Node | null): HTMLElement | null {\n const element = selectionElement(node);\n const source = element?.closest(\"[data-og-annotation-source-key]\");\n return source instanceof HTMLElement ? source : null;\n}\n\nfunction resolveSourceBoundary(range: Range, root: HTMLElement): HTMLElement | null {\n const start = containingSource(range.startContainer);\n const end = containingSource(range.endContainer);\n if (start && end && start !== end) return null;\n const boundary = start ?? end;\n if (!boundary || !root.contains(boundary)) return null;\n return boundary;\n}\n\nfunction isWhollyInsideControl(range: Range, boundary: HTMLElement): boolean {\n const start = selectionElement(range.startContainer)?.closest(CONTROL_SELECTOR);\n const end = selectionElement(range.endContainer)?.closest(CONTROL_SELECTOR);\n return (\n start instanceof Element && start === end && boundary.contains(start) && start !== boundary\n );\n}\n\nfunction annotationId(): string {\n if (typeof globalThis.crypto?.randomUUID === \"function\") {\n return globalThis.crypto.randomUUID();\n }\n return `annotation-${Date.now()}-${Math.random().toString(16).slice(2)}`;\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max);\n}\n\nfunction popoverPosition(rect: DOMRect): { left: number; top: number } {\n const half = POPOVER_WIDTH / 2;\n const left = clamp(rect.left + rect.width / 2, 12 + half, window.innerWidth - 12 - half);\n const preferBelow = rect.bottom + 8 + POPOVER_HEIGHT <= window.innerHeight - 12;\n const top = preferBelow ? rect.bottom + 8 : Math.max(12, rect.top - POPOVER_HEIGHT - 8);\n return { left, top };\n}\n\nfunction buildCandidate(\n root: HTMLElement,\n sources: ReadonlyMap<string, TimelineAnnotationSourceDescriptor>,\n keyboard: boolean,\n): SelectionCandidate | null {\n const selection = document.getSelection();\n if (!selection || selection.rangeCount !== 1 || selection.isCollapsed) return null;\n const range = selection.getRangeAt(0);\n const startBoundary = resolveSourceBoundary(range, root);\n if (!startBoundary) return null;\n if (isWhollyInsideControl(range, startBoundary)) return null;\n const clipped = clipRangeToSource(range, startBoundary);\n if (!clipped) return null;\n const sourceKey = startBoundary.dataset.ogAnnotationSourceKey;\n const source = sourceKey ? sources.get(sourceKey) : undefined;\n const rawQuote = clipped.toString();\n const quote = (source ? matchingQuoteInSource(source.text, rawQuote) : null) ?? rawQuote;\n if (\n !source ||\n quote.trim().length === 0 ||\n new TextEncoder().encode(quote).byteLength > MAX_QUOTE_BYTES\n ) {\n return null;\n }\n const sourceOffsets = occurrenceOffsets(source.text, quote);\n if (sourceOffsets.length === 0) return null;\n const occurrence = quoteOccurrenceIndex(startBoundary, clipped, quote);\n const startOffset = sourceOffsets[Math.min(occurrence, sourceOffsets.length - 1)]!;\n const endOffset = startOffset + quote.length;\n const rect = visibleClientRect(range) ?? visibleClientRect(clipped);\n if (!rect) return null;\n const position = popoverPosition(rect);\n return {\n annotation: {\n id: annotationId(),\n quote,\n note: \"\",\n source: {\n kind: source.kind,\n eventId: source.eventId,\n eventType: source.eventType,\n sequence: source.sequence,\n turnId: source.turnId,\n startOffset,\n endOffset,\n contextBefore: utf8Suffix(source.text.slice(0, startOffset), SOURCE_CONTEXT_BYTES),\n contextAfter: utf8Prefix(source.text.slice(endOffset), SOURCE_CONTEXT_BYTES),\n ...(source.label ? { label: source.label } : {}),\n },\n },\n left: position.left,\n top: position.top,\n keyboard,\n };\n}\n\nexport function TimelineAnnotationSelection({\n rootRef,\n sources,\n onAnnotate,\n}: {\n rootRef: RefObject<HTMLElement | null>;\n sources: ReadonlyMap<string, TimelineAnnotationSourceDescriptor>;\n onAnnotate?: ((annotation: DraftTimelineAnnotation) => void) | undefined;\n}) {\n const [candidate, setCandidate] = useState<SelectionCandidate | null>(null);\n const buttonRef = useRef<HTMLButtonElement | null>(null);\n const initialSelectionObservedRef = useRef(false);\n const pointerOriginRef = useRef<\"unset\" | \"inside\" | \"outside\">(\"unset\");\n const portalStyle = usePortalTokenStyle(rootRef.current);\n\n useEffect(() => {\n const root = rootRef.current;\n if (!root || !onAnnotate) {\n setCandidate(null);\n return;\n }\n const update = (keyboard: boolean) => {\n setCandidate(buildCandidate(root, sources, keyboard));\n };\n // A user may finish selecting text before this lazy component arrives.\n // Reconcile once; later prop changes must not revive dismissed selections.\n if (!initialSelectionObservedRef.current) {\n initialSelectionObservedRef.current = true;\n update(false);\n }\n const onRootPointerUp = (event: PointerEvent) => {\n if (event.target instanceof Node && buttonRef.current?.contains(event.target)) return;\n // Tests may fire only pointerup on the source. A real click that started\n // outside the timeline must not resurrect leftover selection.\n if (pointerOriginRef.current === \"outside\") return;\n window.setTimeout(() => update(false), 0);\n };\n const onDocumentPointerUp = (event: PointerEvent) => {\n if (event.target instanceof Node && buttonRef.current?.contains(event.target)) return;\n const startedInRoot = pointerOriginRef.current === \"inside\";\n pointerOriginRef.current = \"unset\";\n if (!startedInRoot) return;\n window.setTimeout(() => update(false), 0);\n };\n const onKeyUp = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n setCandidate(null);\n return;\n }\n window.setTimeout(() => update(true), 0);\n };\n const onPointerDown = (event: PointerEvent) => {\n if (event.target instanceof Node && buttonRef.current?.contains(event.target)) {\n event.preventDefault();\n return;\n }\n pointerOriginRef.current =\n event.target instanceof Node && root.contains(event.target) ? \"inside\" : \"outside\";\n setCandidate(null);\n };\n const onDocumentKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") setCandidate(null);\n };\n const onSelectionChange = () => {\n if (buttonRef.current && document.activeElement === buttonRef.current) return;\n const selection = document.getSelection();\n if (!selection || selection.isCollapsed) setCandidate(null);\n };\n root.addEventListener(\"pointerup\", onRootPointerUp);\n root.addEventListener(\"keyup\", onKeyUp);\n document.addEventListener(\"pointerup\", onDocumentPointerUp);\n document.addEventListener(\"pointerdown\", onPointerDown);\n document.addEventListener(\"keydown\", onDocumentKeyDown);\n document.addEventListener(\"selectionchange\", onSelectionChange);\n return () => {\n root.removeEventListener(\"pointerup\", onRootPointerUp);\n root.removeEventListener(\"keyup\", onKeyUp);\n document.removeEventListener(\"pointerup\", onDocumentPointerUp);\n document.removeEventListener(\"pointerdown\", onPointerDown);\n document.removeEventListener(\"keydown\", onDocumentKeyDown);\n document.removeEventListener(\"selectionchange\", onSelectionChange);\n };\n }, [onAnnotate, rootRef, sources]);\n\n useEffect(() => {\n if (candidate?.keyboard) buttonRef.current?.focus();\n }, [candidate]);\n\n if (!candidate || !onAnnotate || typeof document === \"undefined\") return null;\n const preview = truncateAnnotationQuote(candidate.annotation.quote, 72);\n return createPortal(\n <button\n ref={buttonRef}\n type=\"button\"\n data-og-annotation-popover=\"\"\n style={{ left: candidate.left, top: candidate.top, ...portalStyle }}\n className=\"og-root fixed z-[80] flex max-w-[min(18rem,calc(100vw-1.5rem))] -translate-x-1/2 items-start gap-2 rounded-2xl border border-og-border bg-og-surface-1 px-3 py-2 text-og-sm font-medium text-og-fg shadow-xl outline-hidden transition hover:border-og-accent/40 hover:bg-og-surface-2 focus-visible:ring-2 focus-visible:ring-og-accent pointer-coarse:min-h-[44px]\"\n aria-label={`Add a note about “${preview}”`}\n title={candidate.annotation.quote}\n onPointerDown={(event) => event.preventDefault()}\n onClick={() => {\n onAnnotate(candidate.annotation);\n document.getSelection()?.removeAllRanges();\n setCandidate(null);\n }}\n >\n <QuoteIcon className=\"mt-0.5 size-3.5 shrink-0 text-og-accent\" aria-hidden=\"true\" />\n <span className=\"min-w-0 text-left\">\n <span className=\"block leading-5\">Add note</span>\n <span className=\"mt-0.5 block truncate text-og-xs font-normal text-og-fg-muted\">\n {preview}\n </span>\n </span>\n </button>,\n document.body,\n );\n}\n\nexport default TimelineAnnotationSelection;\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/components/timeline-annotation-selection.tsx"],"sourcesContent":["import type { DraftTimelineAnnotation } from \"@opengeni/sdk\";\nimport { QuoteIcon } from \"lucide-react\";\nimport { useEffect, useRef, useState, type RefObject } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { usePortalTokenStyle } from \"../lib/use-portal-token-style\";\nimport type { TimelineAnnotationSourceDescriptor } from \"../timeline\";\nimport {\n clipRangeToSource,\n matchingQuoteInSource,\n occurrenceOffsets,\n quoteOccurrenceIndex,\n truncateAnnotationQuote,\n visibleClientRect,\n} from \"./timeline-annotation-shared\";\n\ntype SelectionCandidate = {\n annotation: DraftTimelineAnnotation;\n left: number;\n top: number;\n keyboard: boolean;\n};\n\nconst CONTROL_SELECTOR = \"button,input,textarea,select,summary,[contenteditable='true']\";\nconst SOURCE_CONTEXT_BYTES = 160;\nconst MAX_QUOTE_BYTES = 16 * 1024;\nconst POPOVER_WIDTH = 280;\nconst POPOVER_HEIGHT = 64;\n\nfunction utf8Prefix(value: string, maxBytes: number): string {\n let output = \"\";\n let bytes = 0;\n for (const character of value) {\n const next = new TextEncoder().encode(character).byteLength;\n if (bytes + next > maxBytes) break;\n output += character;\n bytes += next;\n }\n return output;\n}\n\nfunction utf8Suffix(value: string, maxBytes: number): string {\n let output = \"\";\n let bytes = 0;\n for (const character of [...value].reverse()) {\n const next = new TextEncoder().encode(character).byteLength;\n if (bytes + next > maxBytes) break;\n output = character + output;\n bytes += next;\n }\n return output;\n}\n\nfunction selectionElement(node: Node | null): Element | null {\n return node instanceof Element ? node : (node?.parentElement ?? null);\n}\n\nfunction containingSource(node: Node | null): HTMLElement | null {\n const element = selectionElement(node);\n const source = element?.closest(\"[data-og-annotation-source-key]\");\n return source instanceof HTMLElement ? source : null;\n}\n\nfunction resolveSourceBoundary(range: Range, root: HTMLElement): HTMLElement | null {\n const start = containingSource(range.startContainer);\n const end = containingSource(range.endContainer);\n if (start && end && start !== end) return null;\n const boundary = start ?? end;\n if (!boundary || !root.contains(boundary)) return null;\n return boundary;\n}\n\nfunction isWhollyInsideControl(range: Range, boundary: HTMLElement): boolean {\n const start = selectionElement(range.startContainer)?.closest(CONTROL_SELECTOR);\n const end = selectionElement(range.endContainer)?.closest(CONTROL_SELECTOR);\n return (\n start instanceof Element && start === end && boundary.contains(start) && start !== boundary\n );\n}\n\nfunction annotationId(): string {\n if (typeof globalThis.crypto?.randomUUID === \"function\") {\n return globalThis.crypto.randomUUID();\n }\n return `annotation-${Date.now()}-${Math.random().toString(16).slice(2)}`;\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max);\n}\n\nfunction popoverPosition(rect: DOMRect): { left: number; top: number } {\n const half = POPOVER_WIDTH / 2;\n const left = clamp(rect.left + rect.width / 2, 12 + half, window.innerWidth - 12 - half);\n const preferBelow = rect.bottom + 8 + POPOVER_HEIGHT <= window.innerHeight - 12;\n const top = preferBelow ? rect.bottom + 8 : Math.max(12, rect.top - POPOVER_HEIGHT - 8);\n return { left, top };\n}\n\nfunction buildCandidate(\n root: HTMLElement,\n sources: ReadonlyMap<string, TimelineAnnotationSourceDescriptor>,\n keyboard: boolean,\n): SelectionCandidate | null {\n const selection = document.getSelection();\n if (!selection || selection.rangeCount !== 1 || selection.isCollapsed) return null;\n const range = selection.getRangeAt(0);\n const startBoundary = resolveSourceBoundary(range, root);\n if (!startBoundary) return null;\n if (isWhollyInsideControl(range, startBoundary)) return null;\n const clipped = clipRangeToSource(range, startBoundary);\n if (!clipped) return null;\n const sourceKey = startBoundary.dataset.ogAnnotationSourceKey;\n const source = sourceKey ? sources.get(sourceKey) : undefined;\n const rawQuote = clipped.toString();\n const quote = (source ? matchingQuoteInSource(source.text, rawQuote) : null) ?? rawQuote;\n if (\n !source ||\n quote.trim().length === 0 ||\n new TextEncoder().encode(quote).byteLength > MAX_QUOTE_BYTES\n ) {\n return null;\n }\n const sourceOffsets = occurrenceOffsets(source.text, quote);\n if (sourceOffsets.length === 0) return null;\n const occurrence = quoteOccurrenceIndex(startBoundary, clipped, quote);\n const startOffset = sourceOffsets[Math.min(occurrence, sourceOffsets.length - 1)]!;\n const endOffset = startOffset + quote.length;\n const rect = visibleClientRect(range) ?? visibleClientRect(clipped);\n if (!rect) return null;\n const position = popoverPosition(rect);\n return {\n annotation: {\n id: annotationId(),\n quote,\n note: \"\",\n source: {\n kind: source.kind,\n eventId: source.eventId,\n eventType: source.eventType,\n sequence: source.sequence,\n turnId: source.turnId,\n startOffset,\n endOffset,\n contextBefore: utf8Suffix(source.text.slice(0, startOffset), SOURCE_CONTEXT_BYTES),\n contextAfter: utf8Prefix(source.text.slice(endOffset), SOURCE_CONTEXT_BYTES),\n ...(source.label ? { label: source.label } : {}),\n },\n },\n left: position.left,\n top: position.top,\n keyboard,\n };\n}\n\nexport function TimelineAnnotationSelection({\n rootRef,\n sources,\n onAnnotate,\n}: {\n rootRef: RefObject<HTMLElement | null>;\n sources: ReadonlyMap<string, TimelineAnnotationSourceDescriptor>;\n onAnnotate?: ((annotation: DraftTimelineAnnotation) => void) | undefined;\n}) {\n const [candidate, setCandidate] = useState<SelectionCandidate | null>(null);\n const buttonRef = useRef<HTMLButtonElement | null>(null);\n const initialSelectionObservedRef = useRef(false);\n const pointerOriginRef = useRef<\"unset\" | \"inside\" | \"outside\">(\"unset\");\n const portalStyle = usePortalTokenStyle(rootRef.current);\n\n useEffect(() => {\n const root = rootRef.current;\n if (!root || !onAnnotate) {\n setCandidate(null);\n return;\n }\n const update = (keyboard: boolean) => {\n setCandidate(buildCandidate(root, sources, keyboard));\n };\n // A user may finish selecting text before this lazy component arrives.\n // Reconcile once; later prop changes must not revive dismissed selections.\n if (!initialSelectionObservedRef.current) {\n initialSelectionObservedRef.current = true;\n update(false);\n }\n const onRootPointerUp = (event: PointerEvent) => {\n if (event.target instanceof Node && buttonRef.current?.contains(event.target)) return;\n // Tests may fire only pointerup on the source. A real click that started\n // outside the timeline must not resurrect leftover selection.\n if (pointerOriginRef.current === \"outside\") return;\n window.setTimeout(() => update(false), 0);\n };\n const onDocumentPointerUp = (event: PointerEvent) => {\n if (event.target instanceof Node && buttonRef.current?.contains(event.target)) return;\n const startedInRoot = pointerOriginRef.current === \"inside\";\n pointerOriginRef.current = \"unset\";\n if (!startedInRoot) return;\n window.setTimeout(() => update(false), 0);\n };\n const onKeyUp = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n setCandidate(null);\n return;\n }\n window.setTimeout(() => update(true), 0);\n };\n const onPointerDown = (event: PointerEvent) => {\n if (event.target instanceof Node && buttonRef.current?.contains(event.target)) {\n event.preventDefault();\n return;\n }\n pointerOriginRef.current =\n event.target instanceof Node && root.contains(event.target) ? \"inside\" : \"outside\";\n setCandidate(null);\n };\n const onDocumentKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") setCandidate(null);\n };\n const onSelectionChange = () => {\n if (buttonRef.current && document.activeElement === buttonRef.current) return;\n const selection = document.getSelection();\n if (!selection || selection.isCollapsed) setCandidate(null);\n };\n root.addEventListener(\"pointerup\", onRootPointerUp);\n root.addEventListener(\"keyup\", onKeyUp);\n document.addEventListener(\"pointerup\", onDocumentPointerUp);\n document.addEventListener(\"pointerdown\", onPointerDown);\n document.addEventListener(\"keydown\", onDocumentKeyDown);\n document.addEventListener(\"selectionchange\", onSelectionChange);\n return () => {\n root.removeEventListener(\"pointerup\", onRootPointerUp);\n root.removeEventListener(\"keyup\", onKeyUp);\n document.removeEventListener(\"pointerup\", onDocumentPointerUp);\n document.removeEventListener(\"pointerdown\", onPointerDown);\n document.removeEventListener(\"keydown\", onDocumentKeyDown);\n document.removeEventListener(\"selectionchange\", onSelectionChange);\n };\n }, [onAnnotate, rootRef, sources]);\n\n useEffect(() => {\n if (candidate?.keyboard) buttonRef.current?.focus();\n }, [candidate]);\n\n if (!candidate || !onAnnotate || typeof document === \"undefined\") return null;\n const preview = truncateAnnotationQuote(candidate.annotation.quote, 72);\n return createPortal(\n <button\n ref={buttonRef}\n type=\"button\"\n data-og-annotation-popover=\"\"\n style={{ left: candidate.left, top: candidate.top, ...portalStyle }}\n className=\"og-root fixed z-[80] flex max-w-[min(18rem,calc(100vw-1.5rem))] -translate-x-1/2 items-start gap-2 rounded-2xl border border-og-border bg-og-surface-1 px-3 py-2 text-og-sm font-medium text-og-fg shadow-xl outline-hidden transition hover:border-og-accent/40 hover:bg-og-surface-2 focus-visible:ring-2 focus-visible:ring-og-accent pointer-coarse:min-h-[44px]\"\n aria-label={`Add a note about “${preview}”`}\n title={candidate.annotation.quote}\n onPointerDown={(event) => event.preventDefault()}\n onClick={() => {\n onAnnotate(candidate.annotation);\n document.getSelection()?.removeAllRanges();\n setCandidate(null);\n }}\n >\n <QuoteIcon className=\"mt-0.5 size-3.5 shrink-0 text-og-accent\" aria-hidden=\"true\" />\n <span className=\"min-w-0 text-left\">\n <span className=\"block leading-5\">Add note</span>\n <span className=\"mt-0.5 block truncate text-og-xs font-normal text-og-fg-muted\">\n {preview}\n </span>\n </span>\n </button>,\n document.body,\n );\n}\n\nexport default TimelineAnnotationSelection;\n"],"mappings":"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","names":[]}
@@ -1,22 +1,23 @@
1
+ "use client";
1
2
  import {
2
3
  AnnotationAccentRow,
3
4
  AnnotationNoteField,
4
5
  AnnotationNotePreview,
5
6
  AnnotationQuoteSourceButton
6
- } from "./chunk-C5X5AJXK.js";
7
+ } from "./chunk-2HVLQ26H.js";
7
8
  import {
8
9
  ANNOTATION_REVIEW_DIALOG_WIDTH_PX,
9
10
  clampAnnotationDialogPlacement,
10
11
  scrollAnnotationRowIntoList
11
- } from "./chunk-ZYRGEKWS.js";
12
+ } from "./chunk-LJUMYUBO.js";
12
13
  import {
13
14
  annotationDisplayOrdinal,
14
15
  cssEscapeAttribute
15
- } from "./chunk-447JLCBU.js";
16
+ } from "./chunk-S2QH6EZ5.js";
16
17
  import {
17
18
  usePortalTokenStyle
18
- } from "./chunk-VZTQ73XT.js";
19
- import "./chunk-22KP6LR5.js";
19
+ } from "./chunk-XEA5BCMA.js";
20
+ import "./chunk-TXS65BB2.js";
20
21
 
21
22
  // src/components/timeline-annotations-dialog.tsx
22
23
  import { XIcon } from "lucide-react";
@@ -270,4 +271,4 @@ export {
270
271
  TimelineAnnotationsDialog,
271
272
  timeline_annotations_dialog_default as default
272
273
  };
273
- //# sourceMappingURL=timeline-annotations-dialog-ELRDBHTS.js.map
274
+ //# sourceMappingURL=timeline-annotations-dialog-FOMHSDTE.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/timeline-annotations-dialog.tsx"],"sourcesContent":["import type { TimelineAnnotationSource } from \"@opengeni/sdk\";\nimport { XIcon } from \"lucide-react\";\nimport { useEffect, useLayoutEffect, useRef, useState, type RefObject } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { usePortalTokenStyle } from \"../lib/use-portal-token-style\";\nimport {\n AnnotationAccentRow,\n AnnotationNoteField,\n AnnotationNotePreview,\n AnnotationQuoteSourceButton,\n type TimelineAnnotationLike,\n} from \"./timeline-annotation-chrome\";\nimport {\n ANNOTATION_REVIEW_DIALOG_WIDTH_PX,\n clampAnnotationDialogPlacement,\n scrollAnnotationRowIntoList,\n} from \"./timeline-annotation-layout\";\nimport { annotationDisplayOrdinal, cssEscapeAttribute } from \"./timeline-annotation-shared\";\n\nfunction focusableElements(root: HTMLElement): HTMLElement[] {\n return [\n ...root.querySelectorAll<HTMLElement>(\n 'button:not([disabled]),textarea:not([disabled]),input:not([disabled]),[href],[tabindex]:not([tabindex=\"-1\"])',\n ),\n ].filter((element) => element.tabIndex >= 0 && !element.closest(\"[inert]\"));\n}\n\nexport function TimelineAnnotationsDialog({\n annotations,\n editable,\n focusAnnotationId,\n onFocusConsumed,\n onUpdate,\n onRemove,\n onRevealSource,\n triggerRef,\n countLabel,\n onDismiss,\n onCommit,\n}: {\n annotations: readonly TimelineAnnotationLike[];\n editable: boolean;\n focusAnnotationId?: string | null | undefined;\n onFocusConsumed?: (() => void) | undefined;\n onUpdate?: ((id: string, note: string) => void) | undefined;\n onRemove?: ((id: string) => void) | undefined;\n onRevealSource?: ((source: TimelineAnnotationSource) => boolean) | undefined;\n triggerRef: RefObject<HTMLButtonElement | null>;\n countLabel: string;\n onDismiss: (restoreFocus: boolean) => void;\n onCommit: () => void;\n}) {\n const [unavailableId, setUnavailableId] = useState<string | null>(null);\n const [position, setPosition] = useState({ left: 12, top: 12, maxHeight: 0 });\n const panelRef = useRef<HTMLDivElement | null>(null);\n const headerRef = useRef<HTMLDivElement | null>(null);\n const listRef = useRef<HTMLDivElement | null>(null);\n const noteRefs = useRef(new Map<string, HTMLTextAreaElement>());\n const focusedAnnotationIdRef = useRef<string | null>(null);\n const portalStyle = usePortalTokenStyle(triggerRef.current);\n const revealNote = (id: string) => {\n const row = listRef.current?.querySelector<HTMLElement>(\n `[data-og-annotation-id=\"${cssEscapeAttribute(id)}\"]`,\n );\n scrollAnnotationRowIntoList(listRef.current, row);\n noteRefs.current.get(id)?.focus();\n };\n\n const commitNotes = (fromId: string) => {\n const incomplete = annotations.filter((annotation) => {\n const live = noteRefs.current.get(annotation.id);\n return (live?.value ?? annotation.note).trim().length === 0;\n });\n if (incomplete.length === 0) {\n onCommit();\n return;\n }\n const fromIndex = annotations.findIndex((annotation) => annotation.id === fromId);\n const next =\n incomplete.find(\n (item) => annotations.findIndex((annotation) => annotation.id === item.id) > fromIndex,\n ) ?? incomplete[0]!;\n revealNote(next.id);\n };\n\n useLayoutEffect(() => {\n const updatePosition = () => {\n const rect = triggerRef.current?.getBoundingClientRect();\n if (!rect) return;\n const contentHeight =\n (headerRef.current?.offsetHeight ?? 44) + (listRef.current?.scrollHeight ?? 200);\n setPosition(\n clampAnnotationDialogPlacement({\n triggerLeft: rect.left,\n triggerTop: rect.top,\n triggerBottom: rect.bottom,\n contentHeight,\n viewportWidth: window.innerWidth,\n viewportHeight: window.innerHeight,\n panelWidth: ANNOTATION_REVIEW_DIALOG_WIDTH_PX,\n }),\n );\n };\n updatePosition();\n window.addEventListener(\"resize\", updatePosition);\n window.addEventListener(\"scroll\", updatePosition, true);\n return () => {\n window.removeEventListener(\"resize\", updatePosition);\n window.removeEventListener(\"scroll\", updatePosition, true);\n };\n }, [annotations, triggerRef]);\n\n useLayoutEffect(() => {\n if (!focusAnnotationId) {\n focusedAnnotationIdRef.current = null;\n return;\n }\n // A consumed request must not reclaim focus or scroll on layout/callback updates.\n if (focusedAnnotationIdRef.current === focusAnnotationId) return;\n focusedAnnotationIdRef.current = null;\n if (position.maxHeight <= 0) return;\n revealNote(focusAnnotationId);\n const note = noteRefs.current.get(focusAnnotationId);\n if (note && document.activeElement === note) {\n focusedAnnotationIdRef.current = focusAnnotationId;\n onFocusConsumed?.();\n }\n }, [focusAnnotationId, onFocusConsumed, annotations.length, position.maxHeight]);\n\n useEffect(() => {\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n event.stopPropagation();\n onDismiss(true);\n return;\n }\n if (event.key !== \"Tab\" || !panelRef.current) return;\n const focusable = focusableElements(panelRef.current);\n if (focusable.length === 0) return;\n const first = focusable[0]!;\n const last = focusable[focusable.length - 1]!;\n if (event.shiftKey && document.activeElement === first) {\n event.preventDefault();\n last.focus();\n } else if (!event.shiftKey && document.activeElement === last) {\n event.preventDefault();\n first.focus();\n }\n };\n const onPointerDown = (event: PointerEvent) => {\n if (!(event.target instanceof Node)) return;\n if (panelRef.current?.contains(event.target) || triggerRef.current?.contains(event.target)) {\n return;\n }\n onDismiss(false);\n };\n document.addEventListener(\"keydown\", onKeyDown);\n document.addEventListener(\"pointerdown\", onPointerDown);\n if (!focusAnnotationId) {\n window.setTimeout(() => {\n if (document.activeElement === triggerRef.current) panelRef.current?.focus();\n }, 0);\n }\n return () => {\n document.removeEventListener(\"keydown\", onKeyDown);\n document.removeEventListener(\"pointerdown\", onPointerDown);\n };\n }, [focusAnnotationId, onDismiss, triggerRef]);\n\n if (typeof document === \"undefined\") return null;\n return createPortal(\n <div\n ref={panelRef}\n role=\"dialog\"\n tabIndex={-1}\n data-og-annotation-review=\"\"\n style={{\n left: position.left,\n top: position.top,\n maxHeight: position.maxHeight,\n ...portalStyle,\n }}\n className=\"og-root fixed z-[75] box-border flex w-[min(25rem,calc(100vw-1.5rem))] flex-col overflow-hidden rounded-og-lg border border-og-border bg-og-surface-1 text-og-fg shadow-xl outline-hidden\"\n aria-label={editable ? \"Edit quoted notes\" : \"Quoted notes\"}\n >\n <div\n ref={headerRef}\n data-og-annotation-review-header=\"\"\n className=\"flex shrink-0 items-start justify-between gap-3 px-3 pt-3 pb-2\"\n >\n <p className=\"min-w-0 pt-0.5 text-og-sm font-medium text-og-fg-muted\">{countLabel}</p>\n <button\n type=\"button\"\n className=\"inline-flex size-8 shrink-0 items-center justify-center rounded-md border-0 bg-transparent text-og-fg-muted outline-hidden hover:bg-og-surface-2 hover:text-og-fg focus-visible:ring-2 focus-visible:ring-og-accent pointer-coarse:size-11\"\n aria-label=\"Close\"\n onClick={() => onDismiss(true)}\n >\n <XIcon className=\"size-3.5\" aria-hidden=\"true\" />\n </button>\n </div>\n <div\n ref={listRef}\n data-og-annotation-review-list=\"\"\n className=\"grid min-h-0 flex-1 gap-2.5 overflow-x-hidden overflow-y-auto overscroll-contain px-3 pb-3\"\n >\n {annotations.map((annotation, index) => {\n const ordinal = annotationDisplayOrdinal(annotation, index);\n return (\n <section\n key={annotation.id}\n data-og-annotation-id={annotation.id}\n aria-label={`Annotation ${ordinal}`}\n >\n <AnnotationAccentRow>\n <div className=\"flex items-start gap-1\">\n <div className=\"min-w-0 flex-1\">\n <p className=\"mb-0.5 text-og-xs font-medium tabular-nums text-og-fg-subtle\">\n Annotation {ordinal}\n </p>\n <AnnotationQuoteSourceButton\n annotation={annotation}\n lines={2}\n onRevealSource={onRevealSource}\n onUnavailable={setUnavailableId}\n />\n </div>\n {editable && onRemove ? (\n <button\n type=\"button\"\n className=\"inline-flex size-7 shrink-0 items-center justify-center rounded-md border-0 bg-transparent text-og-fg-subtle outline-hidden hover:bg-og-surface-1 hover:text-og-status-failed focus-visible:ring-2 focus-visible:ring-og-accent pointer-coarse:size-11\"\n aria-label={`Remove annotation ${ordinal}`}\n onClick={() => onRemove(annotation.id)}\n >\n <XIcon className=\"size-3.5\" aria-hidden=\"true\" />\n </button>\n ) : null}\n </div>\n {unavailableId === annotation.id ? (\n <p role=\"status\" className=\"text-og-xs text-og-status-waiting\">\n Source is outside the loaded timeline window.\n </p>\n ) : null}\n {editable && onUpdate ? (\n <AnnotationNoteField\n annotation={annotation}\n inputRef={(node) => {\n if (node) noteRefs.current.set(annotation.id, node);\n else noteRefs.current.delete(annotation.id);\n }}\n onUpdate={onUpdate}\n onCommit={() => commitNotes(annotation.id)}\n />\n ) : (\n <AnnotationNotePreview\n note={annotation.note}\n annotationId={annotation.id}\n ordinal={ordinal}\n />\n )}\n </AnnotationAccentRow>\n </section>\n );\n })}\n </div>\n </div>,\n document.body,\n );\n}\n\nexport default TimelineAnnotationsDialog;\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/components/timeline-annotations-dialog.tsx"],"sourcesContent":["import type { TimelineAnnotationSource } from \"@opengeni/sdk\";\nimport { XIcon } from \"lucide-react\";\nimport { useEffect, useLayoutEffect, useRef, useState, type RefObject } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { usePortalTokenStyle } from \"../lib/use-portal-token-style\";\nimport {\n AnnotationAccentRow,\n AnnotationNoteField,\n AnnotationNotePreview,\n AnnotationQuoteSourceButton,\n type TimelineAnnotationLike,\n} from \"./timeline-annotation-chrome\";\nimport {\n ANNOTATION_REVIEW_DIALOG_WIDTH_PX,\n clampAnnotationDialogPlacement,\n scrollAnnotationRowIntoList,\n} from \"./timeline-annotation-layout\";\nimport { annotationDisplayOrdinal, cssEscapeAttribute } from \"./timeline-annotation-shared\";\n\nfunction focusableElements(root: HTMLElement): HTMLElement[] {\n return [\n ...root.querySelectorAll<HTMLElement>(\n 'button:not([disabled]),textarea:not([disabled]),input:not([disabled]),[href],[tabindex]:not([tabindex=\"-1\"])',\n ),\n ].filter((element) => element.tabIndex >= 0 && !element.closest(\"[inert]\"));\n}\n\nexport function TimelineAnnotationsDialog({\n annotations,\n editable,\n focusAnnotationId,\n onFocusConsumed,\n onUpdate,\n onRemove,\n onRevealSource,\n triggerRef,\n countLabel,\n onDismiss,\n onCommit,\n}: {\n annotations: readonly TimelineAnnotationLike[];\n editable: boolean;\n focusAnnotationId?: string | null | undefined;\n onFocusConsumed?: (() => void) | undefined;\n onUpdate?: ((id: string, note: string) => void) | undefined;\n onRemove?: ((id: string) => void) | undefined;\n onRevealSource?: ((source: TimelineAnnotationSource) => boolean) | undefined;\n triggerRef: RefObject<HTMLButtonElement | null>;\n countLabel: string;\n onDismiss: (restoreFocus: boolean) => void;\n onCommit: () => void;\n}) {\n const [unavailableId, setUnavailableId] = useState<string | null>(null);\n const [position, setPosition] = useState({ left: 12, top: 12, maxHeight: 0 });\n const panelRef = useRef<HTMLDivElement | null>(null);\n const headerRef = useRef<HTMLDivElement | null>(null);\n const listRef = useRef<HTMLDivElement | null>(null);\n const noteRefs = useRef(new Map<string, HTMLTextAreaElement>());\n const focusedAnnotationIdRef = useRef<string | null>(null);\n const portalStyle = usePortalTokenStyle(triggerRef.current);\n const revealNote = (id: string) => {\n const row = listRef.current?.querySelector<HTMLElement>(\n `[data-og-annotation-id=\"${cssEscapeAttribute(id)}\"]`,\n );\n scrollAnnotationRowIntoList(listRef.current, row);\n noteRefs.current.get(id)?.focus();\n };\n\n const commitNotes = (fromId: string) => {\n const incomplete = annotations.filter((annotation) => {\n const live = noteRefs.current.get(annotation.id);\n return (live?.value ?? annotation.note).trim().length === 0;\n });\n if (incomplete.length === 0) {\n onCommit();\n return;\n }\n const fromIndex = annotations.findIndex((annotation) => annotation.id === fromId);\n const next =\n incomplete.find(\n (item) => annotations.findIndex((annotation) => annotation.id === item.id) > fromIndex,\n ) ?? incomplete[0]!;\n revealNote(next.id);\n };\n\n useLayoutEffect(() => {\n const updatePosition = () => {\n const rect = triggerRef.current?.getBoundingClientRect();\n if (!rect) return;\n const contentHeight =\n (headerRef.current?.offsetHeight ?? 44) + (listRef.current?.scrollHeight ?? 200);\n setPosition(\n clampAnnotationDialogPlacement({\n triggerLeft: rect.left,\n triggerTop: rect.top,\n triggerBottom: rect.bottom,\n contentHeight,\n viewportWidth: window.innerWidth,\n viewportHeight: window.innerHeight,\n panelWidth: ANNOTATION_REVIEW_DIALOG_WIDTH_PX,\n }),\n );\n };\n updatePosition();\n window.addEventListener(\"resize\", updatePosition);\n window.addEventListener(\"scroll\", updatePosition, true);\n return () => {\n window.removeEventListener(\"resize\", updatePosition);\n window.removeEventListener(\"scroll\", updatePosition, true);\n };\n }, [annotations, triggerRef]);\n\n useLayoutEffect(() => {\n if (!focusAnnotationId) {\n focusedAnnotationIdRef.current = null;\n return;\n }\n // A consumed request must not reclaim focus or scroll on layout/callback updates.\n if (focusedAnnotationIdRef.current === focusAnnotationId) return;\n focusedAnnotationIdRef.current = null;\n if (position.maxHeight <= 0) return;\n revealNote(focusAnnotationId);\n const note = noteRefs.current.get(focusAnnotationId);\n if (note && document.activeElement === note) {\n focusedAnnotationIdRef.current = focusAnnotationId;\n onFocusConsumed?.();\n }\n }, [focusAnnotationId, onFocusConsumed, annotations.length, position.maxHeight]);\n\n useEffect(() => {\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n event.stopPropagation();\n onDismiss(true);\n return;\n }\n if (event.key !== \"Tab\" || !panelRef.current) return;\n const focusable = focusableElements(panelRef.current);\n if (focusable.length === 0) return;\n const first = focusable[0]!;\n const last = focusable[focusable.length - 1]!;\n if (event.shiftKey && document.activeElement === first) {\n event.preventDefault();\n last.focus();\n } else if (!event.shiftKey && document.activeElement === last) {\n event.preventDefault();\n first.focus();\n }\n };\n const onPointerDown = (event: PointerEvent) => {\n if (!(event.target instanceof Node)) return;\n if (panelRef.current?.contains(event.target) || triggerRef.current?.contains(event.target)) {\n return;\n }\n onDismiss(false);\n };\n document.addEventListener(\"keydown\", onKeyDown);\n document.addEventListener(\"pointerdown\", onPointerDown);\n if (!focusAnnotationId) {\n window.setTimeout(() => {\n if (document.activeElement === triggerRef.current) panelRef.current?.focus();\n }, 0);\n }\n return () => {\n document.removeEventListener(\"keydown\", onKeyDown);\n document.removeEventListener(\"pointerdown\", onPointerDown);\n };\n }, [focusAnnotationId, onDismiss, triggerRef]);\n\n if (typeof document === \"undefined\") return null;\n return createPortal(\n <div\n ref={panelRef}\n role=\"dialog\"\n tabIndex={-1}\n data-og-annotation-review=\"\"\n style={{\n left: position.left,\n top: position.top,\n maxHeight: position.maxHeight,\n ...portalStyle,\n }}\n className=\"og-root fixed z-[75] box-border flex w-[min(25rem,calc(100vw-1.5rem))] flex-col overflow-hidden rounded-og-lg border border-og-border bg-og-surface-1 text-og-fg shadow-xl outline-hidden\"\n aria-label={editable ? \"Edit quoted notes\" : \"Quoted notes\"}\n >\n <div\n ref={headerRef}\n data-og-annotation-review-header=\"\"\n className=\"flex shrink-0 items-start justify-between gap-3 px-3 pt-3 pb-2\"\n >\n <p className=\"min-w-0 pt-0.5 text-og-sm font-medium text-og-fg-muted\">{countLabel}</p>\n <button\n type=\"button\"\n className=\"inline-flex size-8 shrink-0 items-center justify-center rounded-md border-0 bg-transparent text-og-fg-muted outline-hidden hover:bg-og-surface-2 hover:text-og-fg focus-visible:ring-2 focus-visible:ring-og-accent pointer-coarse:size-11\"\n aria-label=\"Close\"\n onClick={() => onDismiss(true)}\n >\n <XIcon className=\"size-3.5\" aria-hidden=\"true\" />\n </button>\n </div>\n <div\n ref={listRef}\n data-og-annotation-review-list=\"\"\n className=\"grid min-h-0 flex-1 gap-2.5 overflow-x-hidden overflow-y-auto overscroll-contain px-3 pb-3\"\n >\n {annotations.map((annotation, index) => {\n const ordinal = annotationDisplayOrdinal(annotation, index);\n return (\n <section\n key={annotation.id}\n data-og-annotation-id={annotation.id}\n aria-label={`Annotation ${ordinal}`}\n >\n <AnnotationAccentRow>\n <div className=\"flex items-start gap-1\">\n <div className=\"min-w-0 flex-1\">\n <p className=\"mb-0.5 text-og-xs font-medium tabular-nums text-og-fg-subtle\">\n Annotation {ordinal}\n </p>\n <AnnotationQuoteSourceButton\n annotation={annotation}\n lines={2}\n onRevealSource={onRevealSource}\n onUnavailable={setUnavailableId}\n />\n </div>\n {editable && onRemove ? (\n <button\n type=\"button\"\n className=\"inline-flex size-7 shrink-0 items-center justify-center rounded-md border-0 bg-transparent text-og-fg-subtle outline-hidden hover:bg-og-surface-1 hover:text-og-status-failed focus-visible:ring-2 focus-visible:ring-og-accent pointer-coarse:size-11\"\n aria-label={`Remove annotation ${ordinal}`}\n onClick={() => onRemove(annotation.id)}\n >\n <XIcon className=\"size-3.5\" aria-hidden=\"true\" />\n </button>\n ) : null}\n </div>\n {unavailableId === annotation.id ? (\n <p role=\"status\" className=\"text-og-xs text-og-status-waiting\">\n Source is outside the loaded timeline window.\n </p>\n ) : null}\n {editable && onUpdate ? (\n <AnnotationNoteField\n annotation={annotation}\n inputRef={(node) => {\n if (node) noteRefs.current.set(annotation.id, node);\n else noteRefs.current.delete(annotation.id);\n }}\n onUpdate={onUpdate}\n onCommit={() => commitNotes(annotation.id)}\n />\n ) : (\n <AnnotationNotePreview\n note={annotation.note}\n annotationId={annotation.id}\n ordinal={ordinal}\n />\n )}\n </AnnotationAccentRow>\n </section>\n );\n })}\n </div>\n </div>,\n document.body,\n );\n}\n\nexport default TimelineAnnotationsDialog;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AACA,SAAS,aAAa;AACtB,SAAS,WAAW,iBAAiB,QAAQ,gBAAgC;AAC7E,SAAS,oBAAoB;AAsLvB,SAKE,KALF;AAtKN,SAAS,kBAAkB,MAAkC;AAC3D,SAAO;AAAA,IACL,GAAG,KAAK;AAAA,MACN;AAAA,IACF;AAAA,EACF,EAAE,OAAO,CAAC,YAAY,QAAQ,YAAY,KAAK,CAAC,QAAQ,QAAQ,SAAS,CAAC;AAC5E;AAEO,SAAS,0BAA0B;AAAA,EACxC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAYG;AACD,QAAM,CAAC,eAAe,gBAAgB,IAAI,SAAwB,IAAI;AACtE,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,EAAE,MAAM,IAAI,KAAK,IAAI,WAAW,EAAE,CAAC;AAC5E,QAAM,WAAW,OAA8B,IAAI;AACnD,QAAM,YAAY,OAA8B,IAAI;AACpD,QAAM,UAAU,OAA8B,IAAI;AAClD,QAAM,WAAW,OAAO,oBAAI,IAAiC,CAAC;AAC9D,QAAM,yBAAyB,OAAsB,IAAI;AACzD,QAAM,cAAc,oBAAoB,WAAW,OAAO;AAC1D,QAAM,aAAa,CAAC,OAAe;AACjC,UAAM,MAAM,QAAQ,SAAS;AAAA,MAC3B,2BAA2B,mBAAmB,EAAE,CAAC;AAAA,IACnD;AACA,gCAA4B,QAAQ,SAAS,GAAG;AAChD,aAAS,QAAQ,IAAI,EAAE,GAAG,MAAM;AAAA,EAClC;AAEA,QAAM,cAAc,CAAC,WAAmB;AACtC,UAAM,aAAa,YAAY,OAAO,CAAC,eAAe;AACpD,YAAM,OAAO,SAAS,QAAQ,IAAI,WAAW,EAAE;AAC/C,cAAQ,MAAM,SAAS,WAAW,MAAM,KAAK,EAAE,WAAW;AAAA,IAC5D,CAAC;AACD,QAAI,WAAW,WAAW,GAAG;AAC3B,eAAS;AACT;AAAA,IACF;AACA,UAAM,YAAY,YAAY,UAAU,CAAC,eAAe,WAAW,OAAO,MAAM;AAChF,UAAM,OACJ,WAAW;AAAA,MACT,CAAC,SAAS,YAAY,UAAU,CAAC,eAAe,WAAW,OAAO,KAAK,EAAE,IAAI;AAAA,IAC/E,KAAK,WAAW,CAAC;AACnB,eAAW,KAAK,EAAE;AAAA,EACpB;AAEA,kBAAgB,MAAM;AACpB,UAAM,iBAAiB,MAAM;AAC3B,YAAM,OAAO,WAAW,SAAS,sBAAsB;AACvD,UAAI,CAAC,KAAM;AACX,YAAM,iBACH,UAAU,SAAS,gBAAgB,OAAO,QAAQ,SAAS,gBAAgB;AAC9E;AAAA,QACE,+BAA+B;AAAA,UAC7B,aAAa,KAAK;AAAA,UAClB,YAAY,KAAK;AAAA,UACjB,eAAe,KAAK;AAAA,UACpB;AAAA,UACA,eAAe,OAAO;AAAA,UACtB,gBAAgB,OAAO;AAAA,UACvB,YAAY;AAAA,QACd,CAAC;AAAA,MACH;AAAA,IACF;AACA,mBAAe;AACf,WAAO,iBAAiB,UAAU,cAAc;AAChD,WAAO,iBAAiB,UAAU,gBAAgB,IAAI;AACtD,WAAO,MAAM;AACX,aAAO,oBAAoB,UAAU,cAAc;AACnD,aAAO,oBAAoB,UAAU,gBAAgB,IAAI;AAAA,IAC3D;AAAA,EACF,GAAG,CAAC,aAAa,UAAU,CAAC;AAE5B,kBAAgB,MAAM;AACpB,QAAI,CAAC,mBAAmB;AACtB,6BAAuB,UAAU;AACjC;AAAA,IACF;AAEA,QAAI,uBAAuB,YAAY,kBAAmB;AAC1D,2BAAuB,UAAU;AACjC,QAAI,SAAS,aAAa,EAAG;AAC7B,eAAW,iBAAiB;AAC5B,UAAM,OAAO,SAAS,QAAQ,IAAI,iBAAiB;AACnD,QAAI,QAAQ,SAAS,kBAAkB,MAAM;AAC3C,6BAAuB,UAAU;AACjC,wBAAkB;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,mBAAmB,iBAAiB,YAAY,QAAQ,SAAS,SAAS,CAAC;AAE/E,YAAU,MAAM;AACd,UAAM,YAAY,CAAC,UAAyB;AAC1C,UAAI,MAAM,QAAQ,UAAU;AAC1B,cAAM,gBAAgB;AACtB,kBAAU,IAAI;AACd;AAAA,MACF;AACA,UAAI,MAAM,QAAQ,SAAS,CAAC,SAAS,QAAS;AAC9C,YAAM,YAAY,kBAAkB,SAAS,OAAO;AACpD,UAAI,UAAU,WAAW,EAAG;AAC5B,YAAM,QAAQ,UAAU,CAAC;AACzB,YAAM,OAAO,UAAU,UAAU,SAAS,CAAC;AAC3C,UAAI,MAAM,YAAY,SAAS,kBAAkB,OAAO;AACtD,cAAM,eAAe;AACrB,aAAK,MAAM;AAAA,MACb,WAAW,CAAC,MAAM,YAAY,SAAS,kBAAkB,MAAM;AAC7D,cAAM,eAAe;AACrB,cAAM,MAAM;AAAA,MACd;AAAA,IACF;AACA,UAAM,gBAAgB,CAAC,UAAwB;AAC7C,UAAI,EAAE,MAAM,kBAAkB,MAAO;AACrC,UAAI,SAAS,SAAS,SAAS,MAAM,MAAM,KAAK,WAAW,SAAS,SAAS,MAAM,MAAM,GAAG;AAC1F;AAAA,MACF;AACA,gBAAU,KAAK;AAAA,IACjB;AACA,aAAS,iBAAiB,WAAW,SAAS;AAC9C,aAAS,iBAAiB,eAAe,aAAa;AACtD,QAAI,CAAC,mBAAmB;AACtB,aAAO,WAAW,MAAM;AACtB,YAAI,SAAS,kBAAkB,WAAW,QAAS,UAAS,SAAS,MAAM;AAAA,MAC7E,GAAG,CAAC;AAAA,IACN;AACA,WAAO,MAAM;AACX,eAAS,oBAAoB,WAAW,SAAS;AACjD,eAAS,oBAAoB,eAAe,aAAa;AAAA,IAC3D;AAAA,EACF,GAAG,CAAC,mBAAmB,WAAW,UAAU,CAAC;AAE7C,MAAI,OAAO,aAAa,YAAa,QAAO;AAC5C,SAAO;AAAA,IACL;AAAA,MAAC;AAAA;AAAA,QACC,KAAK;AAAA,QACL,MAAK;AAAA,QACL,UAAU;AAAA,QACV,6BAA0B;AAAA,QAC1B,OAAO;AAAA,UACL,MAAM,SAAS;AAAA,UACf,KAAK,SAAS;AAAA,UACd,WAAW,SAAS;AAAA,UACpB,GAAG;AAAA,QACL;AAAA,QACA,WAAU;AAAA,QACV,cAAY,WAAW,sBAAsB;AAAA,QAE7C;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,KAAK;AAAA,cACL,oCAAiC;AAAA,cACjC,WAAU;AAAA,cAEV;AAAA,oCAAC,OAAE,WAAU,0DAA0D,sBAAW;AAAA,gBAClF;AAAA,kBAAC;AAAA;AAAA,oBACC,MAAK;AAAA,oBACL,WAAU;AAAA,oBACV,cAAW;AAAA,oBACX,SAAS,MAAM,UAAU,IAAI;AAAA,oBAE7B,8BAAC,SAAM,WAAU,YAAW,eAAY,QAAO;AAAA;AAAA,gBACjD;AAAA;AAAA;AAAA,UACF;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,KAAK;AAAA,cACL,kCAA+B;AAAA,cAC/B,WAAU;AAAA,cAET,sBAAY,IAAI,CAAC,YAAY,UAAU;AACtC,sBAAM,UAAU,yBAAyB,YAAY,KAAK;AAC1D,uBACE;AAAA,kBAAC;AAAA;AAAA,oBAEC,yBAAuB,WAAW;AAAA,oBAClC,cAAY,cAAc,OAAO;AAAA,oBAEjC,+BAAC,uBACC;AAAA,2CAAC,SAAI,WAAU,0BACb;AAAA,6CAAC,SAAI,WAAU,kBACb;AAAA,+CAAC,OAAE,WAAU,gEAA+D;AAAA;AAAA,4BAC9D;AAAA,6BACd;AAAA,0BACA;AAAA,4BAAC;AAAA;AAAA,8BACC;AAAA,8BACA,OAAO;AAAA,8BACP;AAAA,8BACA,eAAe;AAAA;AAAA,0BACjB;AAAA,2BACF;AAAA,wBACC,YAAY,WACX;AAAA,0BAAC;AAAA;AAAA,4BACC,MAAK;AAAA,4BACL,WAAU;AAAA,4BACV,cAAY,qBAAqB,OAAO;AAAA,4BACxC,SAAS,MAAM,SAAS,WAAW,EAAE;AAAA,4BAErC,8BAAC,SAAM,WAAU,YAAW,eAAY,QAAO;AAAA;AAAA,wBACjD,IACE;AAAA,yBACN;AAAA,sBACC,kBAAkB,WAAW,KAC5B,oBAAC,OAAE,MAAK,UAAS,WAAU,qCAAoC,2DAE/D,IACE;AAAA,sBACH,YAAY,WACX;AAAA,wBAAC;AAAA;AAAA,0BACC;AAAA,0BACA,UAAU,CAAC,SAAS;AAClB,gCAAI,KAAM,UAAS,QAAQ,IAAI,WAAW,IAAI,IAAI;AAAA,gCAC7C,UAAS,QAAQ,OAAO,WAAW,EAAE;AAAA,0BAC5C;AAAA,0BACA;AAAA,0BACA,UAAU,MAAM,YAAY,WAAW,EAAE;AAAA;AAAA,sBAC3C,IAEA;AAAA,wBAAC;AAAA;AAAA,0BACC,MAAM,WAAW;AAAA,0BACjB,cAAc,WAAW;AAAA,0BACzB;AAAA;AAAA,sBACF;AAAA,uBAEJ;AAAA;AAAA,kBAlDK,WAAW;AAAA,gBAmDlB;AAAA,cAEJ,CAAC;AAAA;AAAA,UACH;AAAA;AAAA;AAAA,IACF;AAAA,IACA,SAAS;AAAA,EACX;AACF;AAEA,IAAO,sCAAQ;","names":[]}
package/dist/usage.js CHANGED
@@ -1,20 +1,21 @@
1
+ "use client";
1
2
  import {
2
3
  DEFAULT_ALLOWANCE_LABELS,
3
4
  allowanceLabels,
4
5
  allowanceResetSentence,
5
6
  formatAllowanceDate,
6
7
  formatAllowanceInstant
7
- } from "./chunk-B3V6TG77.js";
8
+ } from "./chunk-GC3PH6N7.js";
8
9
  import {
9
10
  usePolledValue
10
- } from "./chunk-YQEAA6LT.js";
11
- import "./chunk-UGLEYEMP.js";
11
+ } from "./chunk-QHUE7E4N.js";
12
+ import "./chunk-CM7LVUKC.js";
12
13
  import {
13
14
  OpenGeniContext
14
- } from "./chunk-TKOTKRWY.js";
15
+ } from "./chunk-XTD7TZHW.js";
15
16
  import {
16
17
  cn
17
- } from "./chunk-22KP6LR5.js";
18
+ } from "./chunk-TXS65BB2.js";
18
19
 
19
20
  // src/hooks/use-usage.ts
20
21
  import {