silvery 0.21.0 → 0.23.0

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 (224) hide show
  1. package/README.md +1 -1
  2. package/dist/{Text-Lq0dmj8-.mjs → Text-Ci6UCSTL.mjs} +46 -48
  3. package/dist/Text-Ci6UCSTL.mjs.map +1 -0
  4. package/dist/{render-string-DkQacASz.mjs → ag-q9lRlKlt.mjs} +5322 -4259
  5. package/dist/ag-q9lRlKlt.mjs.map +1 -0
  6. package/dist/{animation-ZMN2_XKv.mjs → animation-CZ4x2R7C.mjs} +1 -1
  7. package/dist/{animation-ZMN2_XKv.mjs.map → animation-CZ4x2R7C.mjs.map} +1 -1
  8. package/dist/{ansi-D1KQMAbf.mjs → ansi-CLmIMnop.mjs} +1 -1
  9. package/dist/{ansi-D1KQMAbf.mjs.map → ansi-CLmIMnop.mjs.map} +1 -1
  10. package/dist/{ansi-2Xn0yatP.d.mts → ansi-zmNzgkPB.d.mts} +1 -1
  11. package/dist/{ansi-2Xn0yatP.d.mts.map → ansi-zmNzgkPB.d.mts.map} +1 -1
  12. package/dist/{backend-B-WYLUib.mjs → backend-DSiSIc-h.mjs} +2 -2
  13. package/dist/{backend-B-WYLUib.mjs.map → backend-DSiSIc-h.mjs.map} +1 -1
  14. package/dist/chain-bridge-CkYcMxlq.mjs +4149 -0
  15. package/dist/chain-bridge-CkYcMxlq.mjs.map +1 -0
  16. package/dist/{chunk-BSw8zbkd.mjs → chunk-BEJ448es.mjs} +1 -3
  17. package/dist/cli-VNqUKlXw.mjs +4 -0
  18. package/dist/{context-BU5LkkIy.mjs → context-CEhuD1R_.mjs} +1 -1
  19. package/dist/{context-BU5LkkIy.mjs.map → context-CEhuD1R_.mjs.map} +1 -1
  20. package/dist/devtools-BF4IMumr.mjs +2 -0
  21. package/dist/{devtools-DcQjgyjL.mjs → devtools-td2AjFwc.mjs} +5 -5
  22. package/dist/{devtools-DcQjgyjL.mjs.map → devtools-td2AjFwc.mjs.map} +1 -1
  23. package/dist/{easing-BI-ASGMO.d.mts → easing-C5MrdO7V.d.mts} +1 -1
  24. package/dist/{easing-BI-ASGMO.d.mts.map → easing-C5MrdO7V.d.mts.map} +1 -1
  25. package/dist/{eta-CJlGH06n.mjs → eta-BwYWEjfS.mjs} +1 -1
  26. package/dist/{eta-CJlGH06n.mjs.map → eta-BwYWEjfS.mjs.map} +1 -1
  27. package/dist/{flexily-zero-adapter-C4lW_Ov5.mjs → flexily-zero-adapter-DktX3HsX.mjs} +1 -1
  28. package/dist/{flexily-zero-adapter-C3Vj0fPt.mjs → flexily-zero-adapter-VoBGHG14.mjs} +1 -1
  29. package/dist/{flexily-zero-adapter-C3Vj0fPt.mjs.map → flexily-zero-adapter-VoBGHG14.mjs.map} +1 -1
  30. package/dist/hit-registry-D_nxOivS.d.mts +71 -0
  31. package/dist/hit-registry-D_nxOivS.d.mts.map +1 -0
  32. package/dist/{UPNG-DosRPdF4.mjs → image-CIF75xMr.mjs} +891 -6
  33. package/dist/image-CIF75xMr.mjs.map +1 -0
  34. package/dist/{index-CSQf13CI.d.mts → index-377zdPLP.d.mts} +35 -12
  35. package/dist/index-377zdPLP.d.mts.map +1 -0
  36. package/dist/{index-Cl9KKjQ_.d.mts → index-BcSr0RAQ.d.mts} +8670 -10659
  37. package/dist/index-BcSr0RAQ.d.mts.map +1 -0
  38. package/dist/{index-XbNrPhWl.d.mts → index-DLnpxDAm.d.mts} +2 -2
  39. package/dist/{index-XbNrPhWl.d.mts.map → index-DLnpxDAm.d.mts.map} +1 -1
  40. package/dist/{index-BUMxS65f.d.mts → index-DlNmckTq.d.mts} +2 -2
  41. package/dist/{index-BUMxS65f.d.mts.map → index-DlNmckTq.d.mts.map} +1 -1
  42. package/dist/index.d.mts +12 -8
  43. package/dist/index.d.mts.map +1 -1
  44. package/dist/index.mjs +18 -15
  45. package/dist/index.mjs.map +1 -1
  46. package/dist/{layout-engine-C2px0RJE.mjs → layout-engine-BgR58vL0.mjs} +3 -3
  47. package/dist/{layout-engine-C2px0RJE.mjs.map → layout-engine-BgR58vL0.mjs.map} +1 -1
  48. package/dist/{layout-engine-C07LEXWT.mjs → layout-engine-DNjTha8f.mjs} +1 -1
  49. package/dist/{layout-signals-Cnw6xk8Q.mjs → layout-signals-CGYbHmxy.mjs} +146 -23
  50. package/dist/layout-signals-CGYbHmxy.mjs.map +1 -0
  51. package/dist/{bound-term-0sPrrzH1.d.mts → mouse-events-B2z5tbsL.d.mts} +780 -379
  52. package/dist/mouse-events-B2z5tbsL.d.mts.map +1 -0
  53. package/dist/{mouse-events-Dki3ISIp.mjs → mouse-events-WQ2h-uqG.mjs} +45 -10
  54. package/dist/mouse-events-WQ2h-uqG.mjs.map +1 -0
  55. package/dist/{multi-progress-DHZ2xUT2.d.mts → multi-progress-BaEFfHKP.d.mts} +2 -2
  56. package/dist/{multi-progress-DHZ2xUT2.d.mts.map → multi-progress-BaEFfHKP.d.mts.map} +1 -1
  57. package/dist/{multi-progress-CIRjrzma.mjs → multi-progress-zCWHEm9P.mjs} +3 -3
  58. package/dist/{multi-progress-CIRjrzma.mjs.map → multi-progress-zCWHEm9P.mjs.map} +1 -1
  59. package/dist/{node-CjM5Rt-M.mjs → node-CJ3J_rW-.mjs} +1 -1
  60. package/dist/{node-CjM5Rt-M.mjs.map → node-CJ3J_rW-.mjs.map} +1 -1
  61. package/dist/{progress-DB_Xo071.mjs → progress-6vJ7nxUg.mjs} +4 -4
  62. package/dist/{progress-DB_Xo071.mjs.map → progress-6vJ7nxUg.mjs.map} +1 -1
  63. package/dist/{progress-bar-oJwq22CR.mjs → progress-bar-BlFNsZL8.mjs} +4 -4
  64. package/dist/{progress-bar-oJwq22CR.mjs.map → progress-bar-BlFNsZL8.mjs.map} +1 -1
  65. package/dist/{reconciler-DldIJB93.mjs → reconciler--_-biN23.mjs} +190 -134
  66. package/dist/reconciler--_-biN23.mjs.map +1 -0
  67. package/dist/{render-string-BcoCpjCB.mjs → render-string-DaghHpLN.mjs} +1 -1
  68. package/dist/render-string-DtHZP0cU.mjs +215 -0
  69. package/dist/render-string-DtHZP0cU.mjs.map +1 -0
  70. package/dist/runtime.d.mts +4 -3
  71. package/dist/runtime.mjs +4 -3
  72. package/dist/schemes-DWQPxXAi.mjs +2516 -0
  73. package/dist/{schemes-JjNp4aSl.mjs.map → schemes-DWQPxXAi.mjs.map} +1 -1
  74. package/dist/{spinner-D9lrHr8s.mjs → spinner-B50hILqx.mjs} +19 -4
  75. package/dist/{spinner-D9lrHr8s.mjs.map → spinner-B50hILqx.mjs.map} +1 -1
  76. package/dist/{spinner-CZINHpkV.d.mts → spinner-DN10UfF0.d.mts} +2 -2
  77. package/dist/{spinner-CZINHpkV.d.mts.map → spinner-DN10UfF0.d.mts.map} +1 -1
  78. package/dist/{src-BNTToU7l.mjs → src-B8lf1kiR.mjs} +1507 -1166
  79. package/dist/src-B8lf1kiR.mjs.map +1 -0
  80. package/dist/{src-5w9QR6_8.mjs → src-BOLdi3WG.mjs} +105 -237
  81. package/dist/src-BOLdi3WG.mjs.map +1 -0
  82. package/dist/{src-BR4xNwdG.mjs → src-BXeTHHlL.mjs} +20240 -25437
  83. package/dist/src-BXeTHHlL.mjs.map +1 -0
  84. package/dist/{src-DKp-_OFG.mjs → src-BqeBFB3X.mjs} +90 -47
  85. package/dist/src-BqeBFB3X.mjs.map +1 -0
  86. package/dist/src-DbqcSrhy.mjs +3901 -0
  87. package/dist/src-DbqcSrhy.mjs.map +1 -0
  88. package/dist/{steps-Bp2uNqnn.d.mts → steps-B2kBmFpb.d.mts} +1 -1
  89. package/dist/{steps-Bp2uNqnn.d.mts.map → steps-B2kBmFpb.d.mts.map} +1 -1
  90. package/dist/{svg-Cz0UXcDj.mjs → svg-NmV9dgB9.mjs} +1 -1
  91. package/dist/{svg-Cz0UXcDj.mjs.map → svg-NmV9dgB9.mjs.map} +1 -1
  92. package/dist/{svg-g1D6ErwR.d.mts → svg-VUr78l5d.d.mts} +1 -1
  93. package/dist/{svg-g1D6ErwR.d.mts.map → svg-VUr78l5d.d.mts.map} +1 -1
  94. package/dist/term.d.mts +2 -2
  95. package/dist/term.mjs +3 -8
  96. package/dist/test.d.mts +673 -0
  97. package/dist/test.d.mts.map +1 -0
  98. package/dist/test.mjs +2829 -0
  99. package/dist/test.mjs.map +1 -0
  100. package/dist/theme.d.mts +2 -2
  101. package/dist/theme.d.mts.map +1 -1
  102. package/dist/theme.mjs +3 -8
  103. package/dist/{types-kt_fKR37.d.mts → types-D_E0FbqA.d.mts} +1 -1
  104. package/dist/{types-kt_fKR37.d.mts.map → types-D_E0FbqA.d.mts.map} +1 -1
  105. package/dist/ui/animation.d.mts +2 -2
  106. package/dist/ui/animation.mjs +1 -1
  107. package/dist/ui/ansi.d.mts +1 -1
  108. package/dist/ui/ansi.mjs +1 -1
  109. package/dist/ui/cli.d.mts +3 -3
  110. package/dist/ui/cli.mjs +5 -5
  111. package/dist/ui/image.d.mts +1 -1
  112. package/dist/ui/image.mjs +1 -1
  113. package/dist/ui/progress.d.mts +4 -4
  114. package/dist/ui/progress.mjs +4 -4
  115. package/dist/ui/react.d.mts +1 -1
  116. package/dist/ui/react.mjs +2 -2
  117. package/dist/ui/recording-chrome-react.d.mts +1 -1
  118. package/dist/ui/recording-chrome-react.mjs +2 -2
  119. package/dist/ui/recording-chrome.d.mts +1 -1
  120. package/dist/ui/recording-chrome.mjs +1 -1
  121. package/dist/ui/utils.mjs +1 -1
  122. package/dist/ui/wrappers.d.mts +2 -2
  123. package/dist/ui/wrappers.mjs +1 -1
  124. package/dist/ui.d.mts +6 -6
  125. package/dist/ui.mjs +7 -7
  126. package/dist/unicode-CxyxVGmB.mjs +11077 -0
  127. package/dist/unicode-CxyxVGmB.mjs.map +1 -0
  128. package/dist/{useLatest-DRDDVwjh.d.mts → useLatest-UOvWy0ZW.d.mts} +2 -2
  129. package/dist/{useLatest-DRDDVwjh.d.mts.map → useLatest-UOvWy0ZW.d.mts.map} +1 -1
  130. package/dist/useLayout-D5cE8OCI.mjs +424 -0
  131. package/dist/useLayout-D5cE8OCI.mjs.map +1 -0
  132. package/dist/{with-text-input-YeohVLeo.d.mts → with-text-input-DLoSCBrm.d.mts} +3 -3
  133. package/dist/{with-text-input-YeohVLeo.d.mts.map → with-text-input-DLoSCBrm.d.mts.map} +1 -1
  134. package/dist/wrap-measurer-registration-IV2HtcCd.d.mts +3106 -0
  135. package/dist/wrap-measurer-registration-IV2HtcCd.d.mts.map +1 -0
  136. package/dist/{wrapper-C70ATkVv.mjs → wrapper-CD29afOs.mjs} +59 -17
  137. package/dist/wrapper-CD29afOs.mjs.map +1 -0
  138. package/dist/{wrappers-BCUYITrY.mjs → wrappers-CInBJm44.mjs} +18 -8
  139. package/dist/wrappers-CInBJm44.mjs.map +1 -0
  140. package/dist/{yoga-adapter-BnZX1PAY.mjs → yoga-adapter-9uab5Qn-.mjs} +2 -2
  141. package/dist/{yoga-adapter-BnZX1PAY.mjs.map → yoga-adapter-9uab5Qn-.mjs.map} +1 -1
  142. package/dist/yoga-adapter-yqTl1aXK.mjs +2 -0
  143. package/package.json +59 -14
  144. package/dist/Text-Lq0dmj8-.mjs.map +0 -1
  145. package/dist/UPNG-Bo33r8rA.mjs +0 -3
  146. package/dist/UPNG-DosRPdF4.mjs.map +0 -1
  147. package/dist/__vite-browser-external-2447137e-D_JM6skp.mjs +0 -6
  148. package/dist/__vite-browser-external-2447137e-D_JM6skp.mjs.map +0 -1
  149. package/dist/ansi-yC4RyBNY.mjs +0 -22441
  150. package/dist/ansi-yC4RyBNY.mjs.map +0 -1
  151. package/dist/apng-CR08rIaH.mjs +0 -58
  152. package/dist/apng-CR08rIaH.mjs.map +0 -1
  153. package/dist/apng-DaHfVaVI.mjs +0 -3
  154. package/dist/assets/resvgjs.darwin-arm64-BtufyGW1.node +0 -0
  155. package/dist/assets/skia.darwin-arm64-DQs5sT6N.node +0 -0
  156. package/dist/backends-CUtan80W.mjs +0 -3
  157. package/dist/backends-DIVYzKqd.mjs +0 -1083
  158. package/dist/backends-DIVYzKqd.mjs.map +0 -1
  159. package/dist/bound-term-0sPrrzH1.d.mts.map +0 -1
  160. package/dist/canvas-1v7dPT-_.mjs +0 -3
  161. package/dist/canvas-CSuPOMNt.mjs +0 -1442
  162. package/dist/canvas-CSuPOMNt.mjs.map +0 -1
  163. package/dist/cli-dvo0r2fs.mjs +0 -4
  164. package/dist/compare-CQodSH4G.mjs +0 -376
  165. package/dist/compare-CQodSH4G.mjs.map +0 -1
  166. package/dist/compare-DHlcxEYA.mjs +0 -3
  167. package/dist/devtools-CJdt5H0X.mjs +0 -2
  168. package/dist/fonts-BFmhXDv7.mjs +0 -88
  169. package/dist/fonts-BFmhXDv7.mjs.map +0 -1
  170. package/dist/gif-C_AjaT9d.mjs +0 -188
  171. package/dist/gif-C_AjaT9d.mjs.map +0 -1
  172. package/dist/gif-DaC4XrxA.mjs +0 -3
  173. package/dist/gifenc-BOUT-KFB.mjs +0 -730
  174. package/dist/gifenc-BOUT-KFB.mjs.map +0 -1
  175. package/dist/image-C2Birh2x.mjs +0 -1252
  176. package/dist/image-C2Birh2x.mjs.map +0 -1
  177. package/dist/index-CSQf13CI.d.mts.map +0 -1
  178. package/dist/index-Cl9KKjQ_.d.mts.map +0 -1
  179. package/dist/key-mapping-CS-YD_cD.mjs +0 -132
  180. package/dist/key-mapping-CS-YD_cD.mjs.map +0 -1
  181. package/dist/key-mapping-Yn-Jgrij.mjs +0 -3
  182. package/dist/layout-signals-Cnw6xk8Q.mjs.map +0 -1
  183. package/dist/mouse-events-Dki3ISIp.mjs.map +0 -1
  184. package/dist/playwright-D5YiZcNS.mjs +0 -76397
  185. package/dist/playwright-D5YiZcNS.mjs.map +0 -1
  186. package/dist/png-codec-Dp84742B.mjs +0 -36
  187. package/dist/png-codec-Dp84742B.mjs.map +0 -1
  188. package/dist/png-codec-QwOtJ8Zs.mjs +0 -3
  189. package/dist/rasterizer-BRXrDdWx.mjs +0 -3
  190. package/dist/rasterizer-CpEhJvdR.mjs +0 -296
  191. package/dist/rasterizer-CpEhJvdR.mjs.map +0 -1
  192. package/dist/reconciler-DldIJB93.mjs.map +0 -1
  193. package/dist/render-string-DkQacASz.mjs.map +0 -1
  194. package/dist/resvg-js-DkOndZI3.mjs +0 -203
  195. package/dist/resvg-js-DkOndZI3.mjs.map +0 -1
  196. package/dist/schemes-JjNp4aSl.mjs +0 -2611
  197. package/dist/src-5w9QR6_8.mjs.map +0 -1
  198. package/dist/src-BNTToU7l.mjs.map +0 -1
  199. package/dist/src-BR4xNwdG.mjs.map +0 -1
  200. package/dist/src-DKp-_OFG.mjs.map +0 -1
  201. package/dist/src-bt8wSrfJ.mjs +0 -258
  202. package/dist/src-bt8wSrfJ.mjs.map +0 -1
  203. package/dist/src-e33Y6kNJ.mjs +0 -3
  204. package/dist/src-iDwu25UD.mjs +0 -1814
  205. package/dist/src-iDwu25UD.mjs.map +0 -1
  206. package/dist/svg-15lZZzxq.mjs +0 -486
  207. package/dist/svg-15lZZzxq.mjs.map +0 -1
  208. package/dist/svg-DY72a4HK.mjs +0 -3
  209. package/dist/term.mjs.map +0 -1
  210. package/dist/theme.mjs.map +0 -1
  211. package/dist/ui/display.d.mts +0 -35
  212. package/dist/ui/display.d.mts.map +0 -1
  213. package/dist/ui/display.mjs +0 -123
  214. package/dist/ui/display.mjs.map +0 -1
  215. package/dist/ui/input.d.mts +0 -184
  216. package/dist/ui/input.d.mts.map +0 -1
  217. package/dist/ui/input.mjs +0 -285
  218. package/dist/ui/input.mjs.map +0 -1
  219. package/dist/wrapper-C70ATkVv.mjs.map +0 -1
  220. package/dist/wrappers-BCUYITrY.mjs.map +0 -1
  221. package/dist/yoga-adapter-DxgsQ_gg.mjs +0 -2
  222. package/dist/zipBundle-3nqeDRtm.mjs +0 -3
  223. package/dist/zipBundle-VNAYFmqJ.mjs +0 -2003
  224. package/dist/zipBundle-VNAYFmqJ.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"progress-bar-oJwq22CR.mjs","names":[],"sources":["../packages/ag-react/src/ui/cli/progress-bar.ts"],"sourcesContent":["/**\n * CLI ProgressBar - Determinate progress indicator with ETA\n */\n\nimport chalk from \"@silvery/ink/chalk\"\nimport type { ProgressBarOptions } from \"../types.js\"\nimport {\n CURSOR_HIDE,\n CURSOR_SHOW,\n CURSOR_TO_START,\n CLEAR_LINE_END,\n write,\n isTTY,\n getTerminalWidth,\n} from \"./ansi\"\nimport { calculateETA, formatETA, DEFAULT_ETA_BUFFER_SIZE, type ETASample } from \"../utils/eta\"\n\n/** Default format string */\nconst DEFAULT_FORMAT = \":bar :percent | :current/:total | ETA: :eta\"\n\n/**\n * ProgressBar class for CLI progress indication\n *\n * @example\n * ```ts\n * const bar = new ProgressBar({ total: 100 });\n * bar.start();\n * for (let i = 0; i <= 100; i++) {\n * await doWork();\n * bar.update(i);\n * }\n * bar.stop();\n * ```\n */\nexport class ProgressBar {\n private total: number\n private format: string\n private width: number\n private complete: string\n private incomplete: string\n private stream: NodeJS.WriteStream\n private hideCursor: boolean\n private phases: Record<string, string>\n\n private current = 0\n private phase: string | null = null\n private startTime: number | null = null\n private isActive = false\n\n // ETA smoothing - track last N update times\n private etaBuffer: ETASample[] = []\n\n constructor(options: ProgressBarOptions = {}) {\n this.total = options.total ?? 100\n this.format = options.format ?? DEFAULT_FORMAT\n this.width = options.width ?? 40\n this.complete = options.complete ?? \"█\"\n this.incomplete = options.incomplete ?? \"░\"\n this.stream = options.stream ?? process.stdout\n this.hideCursor = options.hideCursor ?? true\n this.phases = options.phases ?? {}\n }\n\n /**\n * Start the progress bar\n */\n start(initialValue = 0, initialTotal?: number): this {\n if (initialTotal !== undefined) {\n this.total = initialTotal\n }\n\n this.current = initialValue\n this.startTime = Date.now()\n this.isActive = true\n this.etaBuffer = [{ time: this.startTime, value: initialValue }]\n\n if (this.hideCursor && isTTY(this.stream)) {\n write(CURSOR_HIDE, this.stream)\n }\n\n this.render()\n return this\n }\n\n /**\n * Update progress value\n */\n update(value: number, tokens?: Record<string, string | number>): this {\n this.current = Math.min(value, this.total)\n\n // Update ETA buffer\n const now = Date.now()\n this.etaBuffer.push({ time: now, value: this.current })\n if (this.etaBuffer.length > DEFAULT_ETA_BUFFER_SIZE) {\n this.etaBuffer.shift()\n }\n\n if (this.isActive) {\n this.render(tokens)\n }\n\n return this\n }\n\n /**\n * Increment progress by amount (default: 1)\n */\n increment(amount = 1, tokens?: Record<string, string | number>): this {\n return this.update(this.current + amount, tokens)\n }\n\n /**\n * Set the current phase (for multi-phase progress)\n */\n setPhase(phaseName: string, options?: { current?: number; total?: number }): this {\n this.phase = phaseName\n\n if (options?.total !== undefined) {\n this.total = options.total\n }\n if (options?.current !== undefined) {\n this.current = options.current\n // Reset ETA buffer on phase change\n this.etaBuffer = [{ time: Date.now(), value: this.current }]\n }\n\n if (this.isActive) {\n this.render()\n }\n\n return this\n }\n\n /**\n * Stop the progress bar\n */\n stop(clear = false): this {\n if (!this.isActive) {\n return this\n }\n\n this.isActive = false\n\n if (clear && isTTY(this.stream)) {\n write(`${CURSOR_TO_START}${CLEAR_LINE_END}`, this.stream)\n } else {\n write(\"\\n\", this.stream)\n }\n\n if (this.hideCursor && isTTY(this.stream)) {\n write(CURSOR_SHOW, this.stream)\n }\n\n return this\n }\n\n /** Get ETA in seconds using smoothed rate */\n private getETASeconds(): number | null {\n return calculateETA(this.etaBuffer, this.current, this.total)\n }\n\n /**\n * Render the progress bar\n */\n private render(tokens?: Record<string, string | number>): void {\n const percent = this.total > 0 ? this.current / this.total : 0\n const eta = this.getETASeconds()\n\n // Build the bar\n const completeLength = Math.round(this.width * percent)\n const incompleteLength = this.width - completeLength\n const bar = this.complete.repeat(completeLength) + this.incomplete.repeat(incompleteLength)\n\n // Get phase display name\n const phaseDisplay = this.phase ? (this.phases[this.phase] ?? this.phase) : \"\"\n\n // Calculate rate\n const elapsed = this.startTime ? (Date.now() - this.startTime) / 1000 : 0\n const rate = elapsed > 0 ? this.current / elapsed : 0\n\n // Replace tokens in format string\n let output = this.format\n .replace(\":bar\", chalk.cyan(bar))\n .replace(\":percent\", `${Math.round(percent * 100)}%`.padStart(4))\n .replace(\":current\", String(this.current))\n .replace(\":total\", String(this.total))\n .replace(\":eta\", formatETA(eta))\n .replace(\":elapsed\", formatETA(elapsed))\n .replace(\":rate\", rate.toFixed(1))\n .replace(\":phase\", chalk.dim(phaseDisplay))\n\n // Replace custom tokens\n if (tokens) {\n for (const [key, value] of Object.entries(tokens)) {\n output = output.replace(`:${key}`, String(value))\n }\n }\n\n // Truncate to terminal width\n const termWidth = getTerminalWidth(this.stream)\n if (output.length > termWidth) {\n output = output.slice(0, termWidth - 1)\n }\n\n if (isTTY(this.stream)) {\n write(`${CURSOR_TO_START}${output}${CLEAR_LINE_END}`, this.stream)\n }\n }\n\n /**\n * Get current progress ratio (0-1)\n */\n get ratio(): number {\n return this.total > 0 ? this.current / this.total : 0\n }\n\n /**\n * Get current progress percentage (0-100)\n */\n get percentage(): number {\n return Math.round(this.ratio * 100)\n }\n\n /**\n * Dispose the progress bar (calls stop)\n */\n [Symbol.dispose](): void {\n this.stop()\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"progress-bar-BlFNsZL8.mjs","names":[],"sources":["../packages/ag-react/src/ui/cli/progress-bar.ts"],"sourcesContent":["/**\n * CLI ProgressBar - Determinate progress indicator with ETA\n */\n\nimport chalk from \"@silvery/ink/chalk\"\nimport type { ProgressBarOptions } from \"../types.js\"\nimport {\n CURSOR_HIDE,\n CURSOR_SHOW,\n CURSOR_TO_START,\n CLEAR_LINE_END,\n write,\n isTTY,\n getTerminalWidth,\n} from \"./ansi\"\nimport { calculateETA, formatETA, DEFAULT_ETA_BUFFER_SIZE, type ETASample } from \"../utils/eta\"\n\n/** Default format string */\nconst DEFAULT_FORMAT = \":bar :percent | :current/:total | ETA: :eta\"\n\n/**\n * ProgressBar class for CLI progress indication\n *\n * @example\n * ```ts\n * const bar = new ProgressBar({ total: 100 });\n * bar.start();\n * for (let i = 0; i <= 100; i++) {\n * await doWork();\n * bar.update(i);\n * }\n * bar.stop();\n * ```\n */\nexport class ProgressBar {\n private total: number\n private format: string\n private width: number\n private complete: string\n private incomplete: string\n private stream: NodeJS.WriteStream\n private hideCursor: boolean\n private phases: Record<string, string>\n\n private current = 0\n private phase: string | null = null\n private startTime: number | null = null\n private isActive = false\n\n // ETA smoothing - track last N update times\n private etaBuffer: ETASample[] = []\n\n constructor(options: ProgressBarOptions = {}) {\n this.total = options.total ?? 100\n this.format = options.format ?? DEFAULT_FORMAT\n this.width = options.width ?? 40\n this.complete = options.complete ?? \"█\"\n this.incomplete = options.incomplete ?? \"░\"\n this.stream = options.stream ?? process.stdout\n this.hideCursor = options.hideCursor ?? true\n this.phases = options.phases ?? {}\n }\n\n /**\n * Start the progress bar\n */\n start(initialValue = 0, initialTotal?: number): this {\n if (initialTotal !== undefined) {\n this.total = initialTotal\n }\n\n this.current = initialValue\n this.startTime = Date.now()\n this.isActive = true\n this.etaBuffer = [{ time: this.startTime, value: initialValue }]\n\n if (this.hideCursor && isTTY(this.stream)) {\n write(CURSOR_HIDE, this.stream)\n }\n\n this.render()\n return this\n }\n\n /**\n * Update progress value\n */\n update(value: number, tokens?: Record<string, string | number>): this {\n this.current = Math.min(value, this.total)\n\n // Update ETA buffer\n const now = Date.now()\n this.etaBuffer.push({ time: now, value: this.current })\n if (this.etaBuffer.length > DEFAULT_ETA_BUFFER_SIZE) {\n this.etaBuffer.shift()\n }\n\n if (this.isActive) {\n this.render(tokens)\n }\n\n return this\n }\n\n /**\n * Increment progress by amount (default: 1)\n */\n increment(amount = 1, tokens?: Record<string, string | number>): this {\n return this.update(this.current + amount, tokens)\n }\n\n /**\n * Set the current phase (for multi-phase progress)\n */\n setPhase(phaseName: string, options?: { current?: number; total?: number }): this {\n this.phase = phaseName\n\n if (options?.total !== undefined) {\n this.total = options.total\n }\n if (options?.current !== undefined) {\n this.current = options.current\n // Reset ETA buffer on phase change\n this.etaBuffer = [{ time: Date.now(), value: this.current }]\n }\n\n if (this.isActive) {\n this.render()\n }\n\n return this\n }\n\n /**\n * Stop the progress bar\n */\n stop(clear = false): this {\n if (!this.isActive) {\n return this\n }\n\n this.isActive = false\n\n if (clear && isTTY(this.stream)) {\n write(`${CURSOR_TO_START}${CLEAR_LINE_END}`, this.stream)\n } else {\n write(\"\\n\", this.stream)\n }\n\n if (this.hideCursor && isTTY(this.stream)) {\n write(CURSOR_SHOW, this.stream)\n }\n\n return this\n }\n\n /** Get ETA in seconds using smoothed rate */\n private getETASeconds(): number | null {\n return calculateETA(this.etaBuffer, this.current, this.total)\n }\n\n /**\n * Render the progress bar\n */\n private render(tokens?: Record<string, string | number>): void {\n const percent = this.total > 0 ? this.current / this.total : 0\n const eta = this.getETASeconds()\n\n // Build the bar\n const completeLength = Math.round(this.width * percent)\n const incompleteLength = this.width - completeLength\n const bar = this.complete.repeat(completeLength) + this.incomplete.repeat(incompleteLength)\n\n // Get phase display name\n const phaseDisplay = this.phase ? (this.phases[this.phase] ?? this.phase) : \"\"\n\n // Calculate rate\n const elapsed = this.startTime ? (Date.now() - this.startTime) / 1000 : 0\n const rate = elapsed > 0 ? this.current / elapsed : 0\n\n // Replace tokens in format string\n let output = this.format\n .replace(\":bar\", chalk.cyan(bar))\n .replace(\":percent\", `${Math.round(percent * 100)}%`.padStart(4))\n .replace(\":current\", String(this.current))\n .replace(\":total\", String(this.total))\n .replace(\":eta\", formatETA(eta))\n .replace(\":elapsed\", formatETA(elapsed))\n .replace(\":rate\", rate.toFixed(1))\n .replace(\":phase\", chalk.dim(phaseDisplay))\n\n // Replace custom tokens\n if (tokens) {\n for (const [key, value] of Object.entries(tokens)) {\n output = output.replace(`:${key}`, String(value))\n }\n }\n\n // Truncate to terminal width\n const termWidth = getTerminalWidth(this.stream)\n if (output.length > termWidth) {\n output = output.slice(0, termWidth - 1)\n }\n\n if (isTTY(this.stream)) {\n write(`${CURSOR_TO_START}${output}${CLEAR_LINE_END}`, this.stream)\n }\n }\n\n /**\n * Get current progress ratio (0-1)\n */\n get ratio(): number {\n return this.total > 0 ? this.current / this.total : 0\n }\n\n /**\n * Get current progress percentage (0-100)\n */\n get percentage(): number {\n return Math.round(this.ratio * 100)\n }\n\n /**\n * Dispose the progress bar (calls stop)\n */\n [Symbol.dispose](): void {\n this.stop()\n }\n}\n"],"mappings":"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"}
@@ -1,11 +1,113 @@
1
- import { d as syncTextContentSignal } from "./layout-signals-Cnw6xk8Q.mjs";
2
- import { k as warnOnce, t as init_src } from "./src-BNTToU7l.mjs";
3
- import { A as getActiveLineHeight, D as displayWidth, rt as wrapText, z as isSoftBreakPoint } from "./ansi-yC4RyBNY.mjs";
4
- import { a as requireCapability, n as getConstants, r as getLayoutEngine } from "./layout-engine-C2px0RJE.mjs";
5
- import { createContext } from "react";
1
+ import { m as syncTextContentSignal } from "./layout-signals-CGYbHmxy.mjs";
2
+ import { I as wrapText, i as displayWidth, l as getActiveLineHeight, v as isSoftBreakPoint } from "./unicode-CxyxVGmB.mjs";
3
+ import { O as warnOnce } from "./src-B8lf1kiR.mjs";
4
+ import { a as requireCapability, n as getConstants, r as getLayoutEngine } from "./layout-engine-BgR58vL0.mjs";
6
5
  import { createLogger } from "loggily";
6
+ import { createContext } from "react";
7
7
  import Reconciler from "react-reconciler";
8
8
  import { DefaultEventPriority, DiscreteEventPriority, NoEventPriority } from "react-reconciler/constants.js";
9
+ //#region packages/ag/src/epoch.ts
10
+ /**
11
+ * The current render epoch. Incremented after each render pass.
12
+ * Reconciler stamps dirty nodes with this value; render phase checks equality.
13
+ */
14
+ let renderEpoch = 0;
15
+ /** Get the current render epoch value. */
16
+ function getRenderEpoch() {
17
+ return renderEpoch;
18
+ }
19
+ /**
20
+ * Advance the render epoch. Called once at the end of each render pass.
21
+ * All nodes stamped with the old epoch instantly become "not dirty".
22
+ */
23
+ function advanceRenderEpoch() {
24
+ renderEpoch++;
25
+ }
26
+ /**
27
+ * Check if an epoch stamp matches the current render epoch (i.e., "is dirty").
28
+ */
29
+ function isCurrentEpoch(epoch) {
30
+ return epoch === renderEpoch;
31
+ }
32
+ /**
33
+ * Check if a specific dirty bit is set for the current epoch.
34
+ * Returns true if dirtyEpoch matches the current render epoch AND the bit is set.
35
+ */
36
+ function isDirty(dirtyBits, dirtyEpoch, bit) {
37
+ return dirtyEpoch === renderEpoch && (dirtyBits & bit) !== 0;
38
+ }
39
+ /**
40
+ * Check if ANY dirty bit is set for the current epoch.
41
+ */
42
+ function isAnyDirty(dirtyBits, dirtyEpoch) {
43
+ return dirtyEpoch === renderEpoch && dirtyBits !== 0;
44
+ }
45
+ //#endregion
46
+ //#region packages/ag-term/src/pipeline/collect-text.ts
47
+ /**
48
+ * Collect plain text from a node tree, applying internal_transform.
49
+ *
50
+ * This is the base traversal used by:
51
+ * - measure-phase.ts (fit-content measurement)
52
+ * - render-text.ts (DOM-level truncation budget)
53
+ *
54
+ * Does NOT filter hidden or display:none nodes — those are handled by
55
+ * the layout engine (display:none gets 0x0 size) or by other phases.
56
+ */
57
+ function collectPlainText(node) {
58
+ if (node.textContent !== void 0) return node.textContent;
59
+ let result = "";
60
+ for (let i = 0; i < node.children.length; i++) {
61
+ const child = node.children[i];
62
+ let childText = collectPlainText(child);
63
+ if (childText.length > 0 && child.props.internal_transform) childText = child.props.internal_transform(childText, i);
64
+ result += childText;
65
+ }
66
+ return result;
67
+ }
68
+ /**
69
+ * Collect plain text from a node tree, skipping hidden children.
70
+ *
71
+ * Used by the reconciler's Yoga measure function where hidden nodes
72
+ * (from Suspense) must not contribute to measured size.
73
+ *
74
+ * Identical to collectPlainText except for the hidden check.
75
+ */
76
+ function collectPlainTextSkipHidden(node) {
77
+ if (node.textContent !== void 0) return node.textContent;
78
+ let result = "";
79
+ for (let i = 0; i < node.children.length; i++) {
80
+ const child = node.children[i];
81
+ if (child.hidden) continue;
82
+ let childText = collectPlainTextSkipHidden(child);
83
+ if (childText.length > 0 && child.props.internal_transform) childText = child.props.internal_transform(childText, i);
84
+ result += childText;
85
+ }
86
+ return result;
87
+ }
88
+ //#endregion
89
+ //#region packages/ag-term/src/pipeline/measure-stats.ts
90
+ /**
91
+ * Profiling counters for measure function performance analysis (dev only).
92
+ *
93
+ * Shared between @silvery/ag-react/reconciler/nodes (where measure happens)
94
+ * and @silvery/ag-term/pipeline/layout-phase (where stats are logged).
95
+ *
96
+ * Lives in @silvery/ag-term to keep the @silvery/ag-term barrel React-free.
97
+ */
98
+ const measureStats = {
99
+ calls: 0,
100
+ cacheHits: 0,
101
+ textCollects: 0,
102
+ displayWidthCalls: 0,
103
+ reset() {
104
+ this.calls = 0;
105
+ this.cacheHits = 0;
106
+ this.textCollects = 0;
107
+ this.displayWidthCalls = 0;
108
+ }
109
+ };
110
+ //#endregion
9
111
  //#region packages/ag/src/dirty-tracking.ts
10
112
  /**
11
113
  * Nodes with any content/style dirty flag. Written by reconciler,
@@ -59,43 +161,6 @@ function clearDirtyTracking() {
59
161
  scrollDirtyNodes.clear();
60
162
  }
61
163
  //#endregion
62
- //#region packages/ag/src/epoch.ts
63
- /**
64
- * The current render epoch. Incremented after each render pass.
65
- * Reconciler stamps dirty nodes with this value; render phase checks equality.
66
- */
67
- let renderEpoch = 0;
68
- /** Get the current render epoch value. */
69
- function getRenderEpoch() {
70
- return renderEpoch;
71
- }
72
- /**
73
- * Advance the render epoch. Called once at the end of each render pass.
74
- * All nodes stamped with the old epoch instantly become "not dirty".
75
- */
76
- function advanceRenderEpoch() {
77
- renderEpoch++;
78
- }
79
- /**
80
- * Check if an epoch stamp matches the current render epoch (i.e., "is dirty").
81
- */
82
- function isCurrentEpoch(epoch) {
83
- return epoch === renderEpoch;
84
- }
85
- /**
86
- * Check if a specific dirty bit is set for the current epoch.
87
- * Returns true if dirtyEpoch matches the current render epoch AND the bit is set.
88
- */
89
- function isDirty(dirtyBits, dirtyEpoch, bit) {
90
- return dirtyEpoch === renderEpoch && (dirtyBits & bit) !== 0;
91
- }
92
- /**
93
- * Check if ANY dirty bit is set for the current epoch.
94
- */
95
- function isAnyDirty(dirtyBits, dirtyEpoch) {
96
- return dirtyEpoch === renderEpoch && dirtyBits !== 0;
97
- }
98
- //#endregion
99
164
  //#region packages/scope/src/trace.ts
100
165
  /**
101
166
  * @silvery/scope/trace — opt-in leak detector for scopes and disposables.
@@ -601,71 +666,6 @@ function reportDisposeError(error, context) {
601
666
  } catch {}
602
667
  }
603
668
  //#endregion
604
- //#region packages/ag-term/src/pipeline/collect-text.ts
605
- /**
606
- * Collect plain text from a node tree, applying internal_transform.
607
- *
608
- * This is the base traversal used by:
609
- * - measure-phase.ts (fit-content measurement)
610
- * - render-text.ts (DOM-level truncation budget)
611
- *
612
- * Does NOT filter hidden or display:none nodes — those are handled by
613
- * the layout engine (display:none gets 0x0 size) or by other phases.
614
- */
615
- function collectPlainText(node) {
616
- if (node.textContent !== void 0) return node.textContent;
617
- let result = "";
618
- for (let i = 0; i < node.children.length; i++) {
619
- const child = node.children[i];
620
- let childText = collectPlainText(child);
621
- if (childText.length > 0 && child.props.internal_transform) childText = child.props.internal_transform(childText, i);
622
- result += childText;
623
- }
624
- return result;
625
- }
626
- /**
627
- * Collect plain text from a node tree, skipping hidden children.
628
- *
629
- * Used by the reconciler's Yoga measure function where hidden nodes
630
- * (from Suspense) must not contribute to measured size.
631
- *
632
- * Identical to collectPlainText except for the hidden check.
633
- */
634
- function collectPlainTextSkipHidden(node) {
635
- if (node.textContent !== void 0) return node.textContent;
636
- let result = "";
637
- for (let i = 0; i < node.children.length; i++) {
638
- const child = node.children[i];
639
- if (child.hidden) continue;
640
- let childText = collectPlainTextSkipHidden(child);
641
- if (childText.length > 0 && child.props.internal_transform) childText = child.props.internal_transform(childText, i);
642
- result += childText;
643
- }
644
- return result;
645
- }
646
- //#endregion
647
- //#region packages/ag-term/src/pipeline/measure-stats.ts
648
- /**
649
- * Profiling counters for measure function performance analysis (dev only).
650
- *
651
- * Shared between @silvery/ag-react/reconciler/nodes (where measure happens)
652
- * and @silvery/ag-term/pipeline/layout-phase (where stats are logged).
653
- *
654
- * Lives in @silvery/ag-term to keep the @silvery/ag-term barrel React-free.
655
- */
656
- const measureStats = {
657
- calls: 0,
658
- cacheHits: 0,
659
- textCollects: 0,
660
- displayWidthCalls: 0,
661
- reset() {
662
- this.calls = 0;
663
- this.cacheHits = 0;
664
- this.textCollects = 0;
665
- this.displayWidthCalls = 0;
666
- }
667
- };
668
- //#endregion
669
669
  //#region packages/ag-react/src/reconciler/helpers.ts
670
670
  /**
671
671
  * Reconciler Helper Functions
@@ -729,9 +729,16 @@ const LAYOUT_PROPS = new Set([
729
729
  ]);
730
730
  /**
731
731
  * Set of content props that affect layout dimensions (trigger contentDirty + Flexily markDirty()).
732
- * wrap changes text line count; internal_transform changes text width.
732
+ * wrap changes text line count; internal_transform changes text width; truncate
733
+ * is a per-line elision hook whose output changes the painted line, so a change
734
+ * to it must force a content re-render (its identity is unstable across renders,
735
+ * which is also why render-text.ts bypasses the format cache when it is present).
733
736
  */
734
- const TEXT_CONTENT_PROPS = new Set(["wrap", "internal_transform"]);
737
+ const TEXT_CONTENT_PROPS = new Set([
738
+ "wrap",
739
+ "internal_transform",
740
+ "truncate"
741
+ ]);
735
742
  /**
736
743
  * Set of style props that affect content (paint) but NOT layout dimensions.
737
744
  * borderColor, color, bold, etc. don't change how much space a node takes.
@@ -741,8 +748,10 @@ const TEXT_CONTENT_PROPS = new Set(["wrap", "internal_transform"]);
741
748
  */
742
749
  const STYLE_PROPS = new Set([
743
750
  "color",
751
+ "truncateMarkerColor",
744
752
  "backgroundColor",
745
753
  "bold",
754
+ "internal_dim",
746
755
  "italic",
747
756
  "underline",
748
757
  "underlineStyle",
@@ -764,6 +773,8 @@ const STYLE_PROPS = new Set([
764
773
  "outlineBottom",
765
774
  "outlineLeft",
766
775
  "outlineRight",
776
+ "data-subtree-fade",
777
+ "userSelect",
767
778
  "theme"
768
779
  ]);
769
780
  /** Shared singleton for the no-changes fast path (identity check). */
@@ -1342,7 +1353,6 @@ function justifyToConstant(justify) {
1342
1353
  * This is the bridge between React's reconciliation algorithm
1343
1354
  * and our custom terminal node tree.
1344
1355
  */
1345
- init_src();
1346
1356
  const log = createLogger("silvery:reconciler");
1347
1357
  const mountLog = createLogger("silvery:mount");
1348
1358
  const DEBUG_PROP_NAMES = [
@@ -1435,19 +1445,42 @@ function normalizeNodeType(type) {
1435
1445
  if (type === "ink-text") return "silvery-text";
1436
1446
  return type;
1437
1447
  }
1438
- /**
1439
- * Callback invoked when a node is removed from the tree.
1440
- * Used by the app layer to coordinate focus cleanup — if the focused element
1441
- * is within a removed subtree, focus must be cleared to prevent dangling
1442
- * references and broken navigation (indexOf → -1, hasFocusWithin lies).
1443
- */
1444
- let onNodeRemovedCallback = null;
1445
- /**
1446
- * Register a callback to be called when any node is removed from the tree.
1447
- * Returns a cleanup function to unregister. Only one callback at a time.
1448
- */
1449
- function setOnNodeRemoved(callback) {
1450
- onNodeRemovedCallback = callback;
1448
+ const NODE_CONTAINERS_KEY = Symbol.for("@silvery/ag-react/reconciler/nodeContainers");
1449
+ const nodeContainers = globalThis[NODE_CONTAINERS_KEY] ?? (globalThis[NODE_CONTAINERS_KEY] = /* @__PURE__ */ new WeakMap());
1450
+ function bindSubtreeToContainer(node, container) {
1451
+ nodeContainers.set(node, container);
1452
+ for (const child of node.children) bindSubtreeToContainer(child, container);
1453
+ }
1454
+ function unbindSubtreeFromContainer(node) {
1455
+ nodeContainers.delete(node);
1456
+ for (const child of node.children) unbindSubtreeFromContainer(child);
1457
+ }
1458
+ function getOwningContainer(node) {
1459
+ let current = node;
1460
+ while (current) {
1461
+ const container = nodeContainers.get(current);
1462
+ if (container) return container;
1463
+ current = current.parent;
1464
+ }
1465
+ }
1466
+ function registerContainer(container) {
1467
+ bindSubtreeToContainer(container.root, container);
1468
+ }
1469
+ function releaseContainerLifecycle(container) {
1470
+ container.nodeLifecycle = null;
1471
+ unbindSubtreeFromContainer(container.root);
1472
+ }
1473
+ function setContainerNodeLifecycle(container, observer) {
1474
+ container.nodeLifecycle = observer;
1475
+ }
1476
+ function notifyNodeRemoved(container, removedNode) {
1477
+ container?.nodeLifecycle?.onNodeRemoved?.(removedNode);
1478
+ }
1479
+ function notifyNodeUpdated(updatedNode) {
1480
+ getOwningContainer(updatedNode)?.nodeLifecycle?.onNodeUpdated?.(updatedNode);
1481
+ }
1482
+ function notifySubtreeAttached(container, attachedRoot) {
1483
+ container?.nodeLifecycle?.onSubtreeAttached?.(attachedRoot);
1451
1484
  }
1452
1485
  const NODE_SCOPES_KEY = Symbol.for("@silvery/ag-react/reconciler/nodeScopes");
1453
1486
  const nodeScopes = globalThis[NODE_SCOPES_KEY] ?? (globalThis[NODE_SCOPES_KEY] = /* @__PURE__ */ new WeakMap());
@@ -1600,6 +1633,8 @@ const hostConfig = {
1600
1633
  }
1601
1634
  child.parent = parentInstance;
1602
1635
  parentInstance.children.push(child);
1636
+ const container = getOwningContainer(parentInstance);
1637
+ if (container) bindSubtreeToContainer(child, container);
1603
1638
  if (parentInstance.layoutNode && child.layoutNode) {
1604
1639
  const layoutIndex = parentInstance.children.filter((c) => c.layoutNode !== null).length - 1;
1605
1640
  parentInstance.layoutNode.insertChild(child.layoutNode, layoutIndex);
@@ -1614,10 +1649,13 @@ const hostConfig = {
1614
1649
  trackContentDirty(parentInstance);
1615
1650
  markLayoutAncestorDirty(parentInstance);
1616
1651
  markSubtreeDirty(parentInstance);
1652
+ notifySubtreeAttached(container, child);
1617
1653
  },
1618
1654
  appendInitialChild(parentInstance, child) {
1619
1655
  child.parent = parentInstance;
1620
1656
  parentInstance.children.push(child);
1657
+ const container = getOwningContainer(parentInstance);
1658
+ if (container) bindSubtreeToContainer(child, container);
1621
1659
  if (parentInstance.layoutNode && child.layoutNode) {
1622
1660
  const layoutIndex = parentInstance.children.filter((c) => c.layoutNode !== null).length - 1;
1623
1661
  parentInstance.layoutNode.insertChild(child.layoutNode, layoutIndex);
@@ -1631,6 +1669,7 @@ const hostConfig = {
1631
1669
  }
1632
1670
  child.parent = container.root;
1633
1671
  container.root.children.push(child);
1672
+ bindSubtreeToContainer(child, container);
1634
1673
  if (container.root.layoutNode && child.layoutNode) {
1635
1674
  const layoutIndex = container.root.children.filter((c) => c.layoutNode !== null).length - 1;
1636
1675
  container.root.layoutNode.insertChild(child.layoutNode, layoutIndex);
@@ -1644,11 +1683,12 @@ const hostConfig = {
1644
1683
  container.root.layoutNode?.markDirty();
1645
1684
  trackContentDirty(container.root);
1646
1685
  markSubtreeDirty(container.root);
1686
+ notifySubtreeAttached(container, child);
1647
1687
  },
1648
1688
  removeChild(parentInstance, child) {
1649
1689
  const index = parentInstance.children.indexOf(child);
1650
1690
  if (index !== -1) {
1651
- onNodeRemovedCallback?.(child);
1691
+ notifyNodeRemoved(getOwningContainer(parentInstance) ?? getOwningContainer(child), child);
1652
1692
  logUnmountSubtree(child);
1653
1693
  disposeSubtreeScopes(child);
1654
1694
  parentInstance.children.splice(index, 1);
@@ -1656,6 +1696,7 @@ const hostConfig = {
1656
1696
  parentInstance.layoutNode.removeChild(child.layoutNode);
1657
1697
  child.layoutNode.free();
1658
1698
  }
1699
+ unbindSubtreeFromContainer(child);
1659
1700
  child.parent = null;
1660
1701
  {
1661
1702
  const epoch = getRenderEpoch();
@@ -1672,7 +1713,7 @@ const hostConfig = {
1672
1713
  removeChildFromContainer(container, child) {
1673
1714
  const index = container.root.children.indexOf(child);
1674
1715
  if (index !== -1) {
1675
- onNodeRemovedCallback?.(child);
1716
+ notifyNodeRemoved(container, child);
1676
1717
  logUnmountSubtree(child);
1677
1718
  disposeSubtreeScopes(child);
1678
1719
  container.root.children.splice(index, 1);
@@ -1680,6 +1721,7 @@ const hostConfig = {
1680
1721
  container.root.layoutNode.removeChild(child.layoutNode);
1681
1722
  child.layoutNode.free();
1682
1723
  }
1724
+ unbindSubtreeFromContainer(child);
1683
1725
  child.parent = null;
1684
1726
  {
1685
1727
  const epoch = getRenderEpoch();
@@ -1702,6 +1744,8 @@ const hostConfig = {
1702
1744
  if (beforeIndex !== -1) {
1703
1745
  child.parent = parentInstance;
1704
1746
  parentInstance.children.splice(beforeIndex, 0, child);
1747
+ const container = getOwningContainer(parentInstance);
1748
+ if (container) bindSubtreeToContainer(child, container);
1705
1749
  if (parentInstance.layoutNode && child.layoutNode) {
1706
1750
  const layoutIndex = parentInstance.children.slice(0, beforeIndex).filter((c) => c.layoutNode !== null).length;
1707
1751
  parentInstance.layoutNode.insertChild(child.layoutNode, layoutIndex);
@@ -1716,6 +1760,7 @@ const hostConfig = {
1716
1760
  trackContentDirty(parentInstance);
1717
1761
  markLayoutAncestorDirty(parentInstance);
1718
1762
  markSubtreeDirty(parentInstance);
1763
+ notifySubtreeAttached(container, child);
1719
1764
  }
1720
1765
  },
1721
1766
  insertInContainerBefore(container, child, beforeChild) {
@@ -1728,6 +1773,7 @@ const hostConfig = {
1728
1773
  if (beforeIndex !== -1) {
1729
1774
  child.parent = container.root;
1730
1775
  container.root.children.splice(beforeIndex, 0, child);
1776
+ bindSubtreeToContainer(child, container);
1731
1777
  if (container.root.layoutNode && child.layoutNode) {
1732
1778
  const layoutIndex = container.root.children.slice(0, beforeIndex).filter((c) => c.layoutNode !== null).length;
1733
1779
  container.root.layoutNode.insertChild(child.layoutNode, layoutIndex);
@@ -1741,6 +1787,7 @@ const hostConfig = {
1741
1787
  container.root.layoutNode?.markDirty();
1742
1788
  trackContentDirty(container.root);
1743
1789
  markSubtreeDirty(container.root);
1790
+ notifySubtreeAttached(container, child);
1744
1791
  }
1745
1792
  },
1746
1793
  prepareUpdate(_instance, _type, oldProps, newProps) {
@@ -1786,6 +1833,7 @@ const hostConfig = {
1786
1833
  if (contentChanged === "style" && !layoutChanged && !isDirty(instance.dirtyBits, instance.dirtyEpoch, 4) && !isDirty(instance.dirtyBits, instance.dirtyEpoch, 1) && !isDirty(instance.dirtyBits, instance.dirtyEpoch, 8)) trackStyleOnlyDirty(instance);
1787
1834
  instance.props = newProps;
1788
1835
  logNodeLifecycle("update", instance);
1836
+ notifyNodeUpdated(instance);
1789
1837
  const scrollToChanged = oldProps.scrollTo !== newProps.scrollTo;
1790
1838
  const scrollOffsetChanged = oldProps.scrollOffset !== newProps.scrollOffset;
1791
1839
  if (scrollToChanged || scrollOffsetChanged) trackScrollDirty(instance);
@@ -1830,13 +1878,16 @@ const hostConfig = {
1830
1878
  },
1831
1879
  clearContainer(container) {
1832
1880
  for (const child of container.root.children) {
1833
- onNodeRemovedCallback?.(child);
1881
+ notifyNodeRemoved(container, child);
1834
1882
  logUnmountSubtree(child);
1835
1883
  }
1836
1884
  disposeSubtreeScopes(container.root);
1837
- for (const child of container.root.children) if (container.root.layoutNode && child.layoutNode) {
1838
- container.root.layoutNode.removeChild(child.layoutNode);
1839
- child.layoutNode.free();
1885
+ for (const child of container.root.children) {
1886
+ if (container.root.layoutNode && child.layoutNode) {
1887
+ container.root.layoutNode.removeChild(child.layoutNode);
1888
+ child.layoutNode.free();
1889
+ }
1890
+ unbindSubtreeFromContainer(child);
1840
1891
  }
1841
1892
  container.root.children = [];
1842
1893
  {
@@ -1865,6 +1916,7 @@ const hostConfig = {
1865
1916
  },
1866
1917
  detachDeletedInstance(node) {
1867
1918
  disposeSubtreeScopes(node);
1919
+ unbindSubtreeFromContainer(node);
1868
1920
  },
1869
1921
  setCurrentUpdatePriority(newPriority) {
1870
1922
  currentUpdatePriority = newPriority;
@@ -1992,10 +2044,13 @@ const reconciler = Reconciler(hostConfig);
1992
2044
  * Create a container for rendering.
1993
2045
  */
1994
2046
  function createContainer(onRender) {
1995
- return {
2047
+ const container = {
1996
2048
  root: createRootNode(),
1997
- onRender
2049
+ onRender,
2050
+ nodeLifecycle: null
1998
2051
  };
2052
+ registerContainer(container);
2053
+ return container;
1999
2054
  }
2000
2055
  /**
2001
2056
  * Create a React fiber root for a container (wraps the 10-argument reconciler call).
@@ -2024,7 +2079,7 @@ function getContainerRoot(container) {
2024
2079
  * 1. `createFiberRoot` uses `ConcurrentRoot` (mode 1). React's async
2025
2080
  * `updateContainer(null, fiberRoot, ...)` does NOT run layout-effect
2026
2081
  * cleanups before returning — useLayoutEffect / useBoxRect /
2027
- * useBoxMetrics / signal-effect disposers are scheduled but may not
2082
+ * signal-effect disposers are scheduled but may not
2028
2083
  * fire promptly. That keeps signal subscriptions alive past unmount,
2029
2084
  * which keeps the React tree reachable, which keeps the host
2030
2085
  * `RenderInstance` reachable. `updateContainerSync` + `flushSyncWork`
@@ -2060,6 +2115,7 @@ function unmountFiberRoot(fiberRoot, container) {
2060
2115
  */
2061
2116
  function releaseContainer(container) {
2062
2117
  disposeSubtreeScopes(container.root);
2118
+ releaseContainerLifecycle(container);
2063
2119
  container.onRender = () => {};
2064
2120
  const root = container.root;
2065
2121
  root.children = [];
@@ -2078,6 +2134,6 @@ function releaseContainer(container) {
2078
2134
  }
2079
2135
  }
2080
2136
  //#endregion
2081
- export { trackContentDirty as S, isAnyDirty as _, unmountFiberRoot as a, clearDirtyTracking as b, setOnNodeRemoved as c, createScope as d, reportDisposeError as f, getRenderEpoch as g, advanceRenderEpoch as h, reconciler as i, measureStats as l, finaliseHandle as m, createFiberRoot as n, hostConfig as o, defineHandle as p, getContainerRoot as r, runWithDiscreteEvent as s, createContainer as t, collectPlainText as u, isCurrentEpoch as v, hasScrollDirty as x, isDirty as y };
2137
+ export { isDirty as C, isCurrentEpoch as S, measureStats as _, releaseContainer as a, getRenderEpoch as b, runWithDiscreteEvent as c, reportDisposeError as d, defineHandle as f, trackContentDirty as g, hasScrollDirty as h, reconciler as i, setContainerNodeLifecycle as l, clearDirtyTracking as m, createFiberRoot as n, unmountFiberRoot as o, finaliseHandle as p, getContainerRoot as r, hostConfig as s, createContainer as t, createScope as u, collectPlainText as v, isAnyDirty as x, advanceRenderEpoch as y };
2082
2138
 
2083
- //# sourceMappingURL=reconciler-DldIJB93.mjs.map
2139
+ //# sourceMappingURL=reconciler--_-biN23.mjs.map