@zaly/tui 0.2.0 → 0.3.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 (155) hide show
  1. package/README.md +3 -0
  2. package/dist/{actions-B0yyZ-Ww.d.mts → actions-CH6ndYvf.d.mts} +4 -4
  3. package/dist/{actions-B0yyZ-Ww.d.mts.map → actions-CH6ndYvf.d.mts.map} +1 -1
  4. package/dist/{ansi-CxgRPLA2.mjs → ansi-oiRnTQr9.mjs} +11 -2
  5. package/dist/ansi-oiRnTQr9.mjs.map +1 -0
  6. package/dist/ansi.d.mts +2 -0
  7. package/dist/ansi.d.mts.map +1 -1
  8. package/dist/ansi.mjs +1 -1
  9. package/dist/{autocomplete-wgceuhLr.d.mts → autocomplete-ZmzqQZNq.d.mts} +4 -4
  10. package/dist/{autocomplete-wgceuhLr.d.mts.map → autocomplete-ZmzqQZNq.d.mts.map} +1 -1
  11. package/dist/{box-DbIjxh39.mjs → box-BOJcFW8f.mjs} +4 -4
  12. package/dist/{box-DbIjxh39.mjs.map → box-BOJcFW8f.mjs.map} +1 -1
  13. package/dist/{builder-BdYlK1Ew.mjs → builder-D8Sx5N8a.mjs} +3 -3
  14. package/dist/{builder-BdYlK1Ew.mjs.map → builder-D8Sx5N8a.mjs.map} +1 -1
  15. package/dist/{callbacks-UaBfDStQ.mjs → callbacks-CruJEvm8.mjs} +12 -4
  16. package/dist/{callbacks-UaBfDStQ.mjs.map → callbacks-CruJEvm8.mjs.map} +1 -1
  17. package/dist/client-C7iR8kp-.mjs +1 -0
  18. package/dist/{client-BWm6dNZF.mjs → client-DsNEilJG.mjs} +1 -3
  19. package/dist/client-DsNEilJG.mjs.map +1 -0
  20. package/dist/{clipboard-UEoX9sup.mjs → clipboard-wzJ1EVfy.mjs} +2 -2
  21. package/dist/{clipboard-UEoX9sup.mjs.map → clipboard-wzJ1EVfy.mjs.map} +1 -1
  22. package/dist/clipboard.mjs +1 -1
  23. package/dist/ctx-CM0YMy26.mjs +1 -0
  24. package/dist/{ctx-DBeFcZt6.mjs → ctx-D_rMOcp5.mjs} +2 -2
  25. package/dist/{ctx-DBeFcZt6.mjs.map → ctx-D_rMOcp5.mjs.map} +1 -1
  26. package/dist/{divider-BPmnQ0Eu.mjs → divider-CiNpoiuP.mjs} +2 -2
  27. package/dist/{divider-BPmnQ0Eu.mjs.map → divider-CiNpoiuP.mjs.map} +1 -1
  28. package/dist/{files-CdiDnwA_.d.mts → files-82Il_nUh.d.mts} +3 -3
  29. package/dist/{files-CdiDnwA_.d.mts.map → files-82Il_nUh.d.mts.map} +1 -1
  30. package/dist/{github-DC0XemKa.d.mts → github-yVfk9BE4.d.mts} +3 -3
  31. package/dist/{github-DC0XemKa.d.mts.map → github-yVfk9BE4.d.mts.map} +1 -1
  32. package/dist/{image-M--Bw4bs.mjs → image--PBiHfwV.mjs} +2 -2
  33. package/dist/{image-M--Bw4bs.mjs.map → image--PBiHfwV.mjs.map} +1 -1
  34. package/dist/{image-DdRDv7q6.d.mts → image-CO6YJj6F.d.mts} +2 -2
  35. package/dist/{image-DdRDv7q6.d.mts.map → image-CO6YJj6F.d.mts.map} +1 -1
  36. package/dist/image.d.mts +1 -1
  37. package/dist/index.d.mts +1 -1
  38. package/dist/index.mjs +6 -6
  39. package/dist/{input-CtGmVrKa.mjs → input-5ktO2fvO.mjs} +4 -4
  40. package/dist/{input-CtGmVrKa.mjs.map → input-5ktO2fvO.mjs.map} +1 -1
  41. package/dist/{input-C3kfYoEJ.d.mts → input-C8MEpAg6.d.mts} +2 -2
  42. package/dist/{input-C3kfYoEJ.d.mts.map → input-C8MEpAg6.d.mts.map} +1 -1
  43. package/dist/{inspect-Cli1beu8.mjs → inspect-CxtcQch-.mjs} +2 -2
  44. package/dist/{inspect-Cli1beu8.mjs.map → inspect-CxtcQch-.mjs.map} +1 -1
  45. package/dist/{log-D6gGicwQ.mjs → log-D7PTmOzE.mjs} +8 -5
  46. package/dist/log-D7PTmOzE.mjs.map +1 -0
  47. package/dist/{logger-C0WuIlAh.mjs → logger-DXK8D8Vb.mjs} +3 -3
  48. package/dist/{logger-C0WuIlAh.mjs.map → logger-DXK8D8Vb.mjs.map} +1 -1
  49. package/dist/{markdown-DvDIPT5L.mjs → markdown-D6quhsm0.mjs} +10 -9
  50. package/dist/markdown-D6quhsm0.mjs.map +1 -0
  51. package/dist/markdown.d.mts +3 -1
  52. package/dist/markdown.d.mts.map +1 -1
  53. package/dist/markdown.mjs +1 -1
  54. package/dist/{overlay-zDNpwKu0.mjs → overlay-6kh2gG4K.mjs} +2 -2
  55. package/dist/{overlay-zDNpwKu0.mjs.map → overlay-6kh2gG4K.mjs.map} +1 -1
  56. package/dist/{picker-DV_oxKEv.mjs → picker-B3XS2HKe.mjs} +4 -4
  57. package/dist/{picker-DV_oxKEv.mjs.map → picker-B3XS2HKe.mjs.map} +1 -1
  58. package/dist/{picker-DsB6--GN.d.mts → picker-H_ubc2nk.d.mts} +5 -5
  59. package/dist/{picker-DsB6--GN.d.mts.map → picker-H_ubc2nk.d.mts.map} +1 -1
  60. package/dist/{queries-Dmd3IjSd.d.mts → queries-BqFMpQAf.d.mts} +3 -1
  61. package/dist/queries-BqFMpQAf.d.mts.map +1 -0
  62. package/dist/{render-Bp2N2i6J.mjs → render-bm-x85jl.mjs} +2 -2
  63. package/dist/{render-Bp2N2i6J.mjs.map → render-bm-x85jl.mjs.map} +1 -1
  64. package/dist/{renderer-OplFCBMq.mjs → renderer-Cc8-s72G.mjs} +9 -9
  65. package/dist/{renderer-OplFCBMq.mjs.map → renderer-Cc8-s72G.mjs.map} +1 -1
  66. package/dist/renderer-DJg8vAoQ.mjs +1 -0
  67. package/dist/{renderer-Ksfkfv5X.mjs → renderer-D_n6LCWd.mjs} +2 -2
  68. package/dist/renderer-D_n6LCWd.mjs.map +1 -0
  69. package/dist/{select-BZCFXdjp.d.mts → select-BeP7rFkP.d.mts} +2 -2
  70. package/dist/{select-BZCFXdjp.d.mts.map → select-BeP7rFkP.d.mts.map} +1 -1
  71. package/dist/{select-CUmAFKJh.mjs → select-BlsSDBlV.mjs} +2 -2
  72. package/dist/{select-CUmAFKJh.mjs.map → select-BlsSDBlV.mjs.map} +1 -1
  73. package/dist/services/logger.d.mts +1 -1
  74. package/dist/services/logger.mjs +1 -1
  75. package/dist/services/notifier.d.mts +1 -1
  76. package/dist/services/notifier.mjs +2 -2
  77. package/dist/services/picker.d.mts +5 -5
  78. package/dist/services/picker.mjs +6 -6
  79. package/dist/services/prompt.d.mts +4 -4
  80. package/dist/services/prompt.mjs +5 -5
  81. package/dist/shiki/server.mjs +2 -2
  82. package/dist/{shiki-BAf9PdIc.mjs → shiki-CUJQssUJ.mjs} +2 -2
  83. package/dist/{shiki-BAf9PdIc.mjs.map → shiki-CUJQssUJ.mjs.map} +1 -1
  84. package/dist/{show-D5XNXgZf.mjs → show-BfIUw8A1.mjs} +2 -2
  85. package/dist/{show-D5XNXgZf.mjs.map → show-BfIUw8A1.mjs.map} +1 -1
  86. package/dist/{style-Cw_EuszU.mjs → style-DTwmlkfR.mjs} +2 -2
  87. package/dist/{style-Cw_EuszU.mjs.map → style-DTwmlkfR.mjs.map} +1 -1
  88. package/dist/style.d.mts +1 -1
  89. package/dist/style.mjs +2 -2
  90. package/dist/{text-H_2kzwaz.mjs → text-BKLHPMsQ.mjs} +3 -3
  91. package/dist/{text-H_2kzwaz.mjs.map → text-BKLHPMsQ.mjs.map} +1 -1
  92. package/dist/{text-BEuhhxr7.mjs → text-BLQXIh6Z.mjs} +2 -2
  93. package/dist/{text-BEuhhxr7.mjs.map → text-BLQXIh6Z.mjs.map} +1 -1
  94. package/dist/{text-DdkJXgoC.d.mts → text-BnlU1Q9y.d.mts} +2 -2
  95. package/dist/{text-DdkJXgoC.d.mts.map → text-BnlU1Q9y.d.mts.map} +1 -1
  96. package/dist/text.d.mts +1 -1
  97. package/dist/text.mjs +1 -1
  98. package/dist/{theme-B8hb1lPU.mjs → theme-CG51x7aG.mjs} +2 -2
  99. package/dist/{theme-B8hb1lPU.mjs.map → theme-CG51x7aG.mjs.map} +1 -1
  100. package/dist/{tree-D6NvMQx8.mjs → tree-4aaQKFtF.mjs} +2 -2
  101. package/dist/{tree-D6NvMQx8.mjs.map → tree-4aaQKFtF.mjs.map} +1 -1
  102. package/dist/{tree-Berzv8Rz.d.mts → tree-DNAE_C7w.d.mts} +3 -3
  103. package/dist/{tree-Berzv8Rz.d.mts.map → tree-DNAE_C7w.d.mts.map} +1 -1
  104. package/dist/{widget-sPJaKVU2.d.mts → widget-CHWHCg1j.d.mts} +2 -2
  105. package/dist/{widget-sPJaKVU2.d.mts.map → widget-CHWHCg1j.d.mts.map} +1 -1
  106. package/dist/widgets/autocomplete.d.mts +1 -1
  107. package/dist/widgets/autocomplete.mjs +3 -3
  108. package/dist/widgets/box.d.mts +1 -1
  109. package/dist/widgets/box.mjs +1 -1
  110. package/dist/widgets/code.d.mts +2 -2
  111. package/dist/widgets/code.mjs +7 -7
  112. package/dist/widgets/completions/actions.d.mts +1 -1
  113. package/dist/widgets/completions/files.d.mts +1 -1
  114. package/dist/widgets/completions/github.d.mts +1 -1
  115. package/dist/widgets/completions/index.d.mts +3 -3
  116. package/dist/widgets/diff.d.mts +2 -2
  117. package/dist/widgets/diff.mjs +5 -5
  118. package/dist/widgets/divider.d.mts +1 -1
  119. package/dist/widgets/divider.mjs +1 -1
  120. package/dist/widgets/image.d.mts +1 -1
  121. package/dist/widgets/image.mjs +2 -2
  122. package/dist/widgets/input.d.mts +1 -1
  123. package/dist/widgets/input.mjs +1 -1
  124. package/dist/widgets/log.d.mts +1 -1
  125. package/dist/widgets/log.mjs +1 -1
  126. package/dist/widgets/markdown.d.mts +6 -4
  127. package/dist/widgets/markdown.d.mts.map +1 -1
  128. package/dist/widgets/markdown.mjs +1 -1
  129. package/dist/widgets/overlay.d.mts +1 -1
  130. package/dist/widgets/overlay.mjs +1 -1
  131. package/dist/widgets/picker.d.mts +1 -1
  132. package/dist/widgets/picker.mjs +1 -1
  133. package/dist/widgets/progress.d.mts +1 -1
  134. package/dist/widgets/progress.mjs +1 -1
  135. package/dist/widgets/select.d.mts +1 -1
  136. package/dist/widgets/select.mjs +1 -1
  137. package/dist/widgets/show.d.mts +1 -1
  138. package/dist/widgets/show.mjs +1 -1
  139. package/dist/widgets/spinner.d.mts +1 -1
  140. package/dist/widgets/spinner.mjs +1 -1
  141. package/dist/widgets/text.d.mts +1 -1
  142. package/dist/widgets/text.mjs +1 -1
  143. package/dist/widgets/tree.d.mts +1 -1
  144. package/dist/widgets/tree.mjs +1 -1
  145. package/dist/widgets/widget.d.mts +1 -1
  146. package/package.json +6 -6
  147. package/dist/ansi-CxgRPLA2.mjs.map +0 -1
  148. package/dist/client-BWm6dNZF.mjs.map +0 -1
  149. package/dist/client-C69qWhMG.mjs +0 -1
  150. package/dist/ctx-CYEzzH-7.mjs +0 -1
  151. package/dist/log-D6gGicwQ.mjs.map +0 -1
  152. package/dist/markdown-DvDIPT5L.mjs.map +0 -1
  153. package/dist/queries-Dmd3IjSd.d.mts.map +0 -1
  154. package/dist/renderer-Dv5fIuIk.mjs +0 -1
  155. package/dist/renderer-Ksfkfv5X.mjs.map +0 -1
@@ -0,0 +1 @@
1
+ export { t as MarkdownRenderer } from "./renderer-D_n6LCWd.mjs";
@@ -10,7 +10,7 @@ var MarkdownRenderer = class {
10
10
  }
11
11
  async render(source, ctx) {
12
12
  this.#render ??= this.#opts.render ?? (await import("#md")).renderMarkdown;
13
- const [{ createCallbacks }, { createImageCallback }] = await Promise.all([import("./callbacks-UaBfDStQ.mjs"), import("./image-M--Bw4bs.mjs")]);
13
+ const [{ createCallbacks }, { createImageCallback }] = await Promise.all([import("./callbacks-CruJEvm8.mjs"), import("./image--PBiHfwV.mjs")]);
14
14
  const callbacks = createCallbacks(ctx);
15
15
  const image = createImageCallback({
16
16
  add: (child) => this.#parent?.add(child),
@@ -37,4 +37,4 @@ var MarkdownRenderer = class {
37
37
  };
38
38
  export { MarkdownRenderer as t };
39
39
 
40
- //# sourceMappingURL=renderer-Ksfkfv5X.mjs.map
40
+ //# sourceMappingURL=renderer-D_n6LCWd.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderer-D_n6LCWd.mjs","names":[],"sources":["../src/markdown/renderer.ts"],"sourcesContent":["import type { RenderCtx } from \"../core/ctx.ts\"\nimport type { Node } from \"../core/node.ts\"\nimport type { Image } from \"../widgets/image.ts\"\nimport type { MdOptions, RenderMarkdown } from \"./types.ts\"\n\nexport type MarkdownOptions = MdOptions & {\n parent?: Node\n}\n\nexport type MarkdownCtx = RenderCtx & {\n /** Base directory for relative file links. Defaults to process.cwd(). */\n cwd?: string\n images?: boolean\n highlight?: (code: string, lang?: string) => string\n}\n\nexport class MarkdownRenderer {\n #render?: RenderMarkdown\n #images = new Map<string, Image>()\n #parent?: Node\n #opts: MarkdownOptions\n\n constructor(opts: MarkdownOptions = {}) {\n this.#opts = opts\n this.#parent = opts.parent\n }\n\n async render(source: string, ctx: MarkdownCtx): Promise<string> {\n // oxlint-disable-next-line unicorn/no-await-expression-member\n this.#render ??= this.#opts.render ?? (await import(\"#md\")).renderMarkdown\n\n const [{ createCallbacks }, { createImageCallback }] = await Promise.all([\n import(\"./callbacks.ts\"),\n import(\"./image.ts\"),\n ])\n\n const callbacks = createCallbacks(ctx)\n\n // Image handling: the callback emits `<img id=N>` markers during\n // rendering; a post-processing resolver then renders the referenced\n // images concurrently and splices their rows back in. Keeps the\n // markdown callback surface synchronous while supporting async\n // image preparation.\n const image = createImageCallback({\n add: (child) => this.#parent?.add(child),\n images: this.#images,\n queries: ctx.images === false ? undefined : this.#parent?.ctx?.input.queries,\n remove: (child) => this.#parent?.remove(child) ?? child.unmount(),\n })\n\n if (ctx.images ?? true) callbacks.image = image.cb\n\n let rendered = this.#render(image.prepare(source), callbacks, this.#opts)\n rendered = await image.resolve(ctx, rendered)\n return this.normalizeEol(source, rendered)\n }\n\n /** Mirror the source's trailing newlines: the renderer adds its own\n /* padding after blocks (`\\n\\n` after paragraphs, etc.) which would\n /* leave stray blank rows. Normalizing to what the caller typed keeps\n /* single-line inputs compact and preserves explicit spacing when\n /* they asked for it. */\n normalizeEol(source: string, rendered: string): string {\n // Collapse multiple blank lines to a maximum of one\n rendered = rendered.replace(/\\n\\n+/g, \"\\n\\n\")\n // Trim leading blank lines\n rendered = rendered.replace(/^\\s*\\n/, \"\")\n const trailing = /\\n*$/.exec(source)?.[0] ?? \"\"\n return rendered.replace(/\\n+$/, trailing)\n }\n}\n"],"mappings":";AAgBA,IAAa,mBAAb,MAA8B;CAC5B;CACA,0BAAU,IAAI,IAAmB;CACjC;CACA;CAEA,YAAY,OAAwB,CAAC,GAAG;EACtC,KAAK,QAAQ;EACb,KAAK,UAAU,KAAK;CACtB;CAEA,MAAM,OAAO,QAAgB,KAAmC;EAE9D,KAAK,YAAY,KAAK,MAAM,WAAW,MAAM,OAAO,OAAA,CAAQ;EAE5D,MAAM,CAAC,EAAE,mBAAmB,EAAE,yBAAyB,MAAM,QAAQ,IAAI,CACvE,OAAO,6BACP,OAAO,uBACT,CAAC;EAED,MAAM,YAAY,gBAAgB,GAAG;EAOrC,MAAM,QAAQ,oBAAoB;GAChC,MAAM,UAAU,KAAK,SAAS,IAAI,KAAK;GACvC,QAAQ,KAAK;GACb,SAAS,IAAI,WAAW,QAAQ,KAAA,IAAY,KAAK,SAAS,KAAK,MAAM;GACrE,SAAS,UAAU,KAAK,SAAS,OAAO,KAAK,KAAK,MAAM,QAAQ;EAClE,CAAC;EAED,IAAI,IAAI,UAAU,MAAM,UAAU,QAAQ,MAAM;EAEhD,IAAI,WAAW,KAAK,QAAQ,MAAM,QAAQ,MAAM,GAAG,WAAW,KAAK,KAAK;EACxE,WAAW,MAAM,MAAM,QAAQ,KAAK,QAAQ;EAC5C,OAAO,KAAK,aAAa,QAAQ,QAAQ;CAC3C;;;;;;CAOA,aAAa,QAAgB,UAA0B;EAErD,WAAW,SAAS,QAAQ,UAAU,MAAM;EAE5C,WAAW,SAAS,QAAQ,UAAU,EAAE;EACxC,MAAM,WAAW,OAAO,KAAK,MAAM,CAAC,GAAG,MAAM;EAC7C,OAAO,SAAS,QAAQ,QAAQ,QAAQ;CAC1C;AACF"}
@@ -1,5 +1,5 @@
1
+ import { Ft as Size, I as RenderCtx, Q as State, at as Ref, h as Node, it as Reactive, m as BaseEvents } from "./queries-BqFMpQAf.mjs";
1
2
  import { u as Style } from "./types-ByMHEdCF.mjs";
2
- import { Ft as Size, I as RenderCtx, Q as State, at as Ref, h as Node, it as Reactive, m as BaseEvents } from "./queries-Dmd3IjSd.mjs";
3
3
  /** Default shape for selectable options. `text` is the canonical
4
4
  * searchable/fallback label. `name` overrides the displayed label in the
5
5
  * default renderer, and `desc` is shown as a dim right-column description. */
@@ -111,4 +111,4 @@ declare class Select<T extends Option = Option> extends Node<SelectState<T>, Sel
111
111
  */
112
112
  declare function select<T extends Option = Option>(state: State<SelectState<T>>): Select<T>;
113
113
  export { SelectEvents as a, Select as i, OptionRender as n, SelectState as o, OptionRenderCtx as r, select as s, Option as t };
114
- //# sourceMappingURL=select-BZCFXdjp.d.mts.map
114
+ //# sourceMappingURL=select-BeP7rFkP.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"select-BZCFXdjp.d.mts","names":[],"sources":["../src/widgets/select.ts"],"mappings":";;;;;KAgBY;EACV;EACA;EACA;;KAGU,gBAAgB,KAAK;EAC/B,kBAAkB;EAClB,gBAAgB;EAChB;EACA;;;;;;;KAQU,aAAa,MAAM,MAAM,GAAG,KAAK,gBAAgB;UAE5C,YAAY,UAAU,SAAS,gBAAgB;;;EAG9D,OAAO,kBAAkB;;EAEzB;;;;EAIA,YAAY;;;;EAIZ;;EAEA,QAAQ;;;;EAIR;;;EAGA,SAAS,SAAS,aAAa;EAC/B;;;EAGA;;UAGe,aAAa,UAAU,SAAS,gBAAgB;;EAE/D;IAAY,MAAM;;;EAElB;IAAU,MAAM;;;EAEhB;EACA;IAAW;IAAgB,OAAO;;;;;;;;;;;;;cAavB,OAAO,UAAU,SAAS,gBAAgB,KAAK,YAAY,IAAI,aAAa;;kBACvE;WACE;EAET;IACc;IAKD;IAGG;IAKH;IAID;IAKA;IAKK;IAMF;IAMH;;EAarB,YAAY,SAAS,YAAY;MAyB7B,OAAO;MAKP;EAOJ,KAAK,MAAM,OAAO,IAAI;MASlB;MAIA;MAIA,QAAQ;YAIF,QAAQ,KAAK;MA2CnB,YAAY,aAAa;EAI7B,eAAe,KAAK,MAAM,aAAa,OAAO,aAAa;EAM3D,mBAAmB,aAAa;;;;;;;;;;iBAmClB,OAAO,UAAU,SAAS,QAAQ,OAAO,MAAM,YAAY,MAAM,OAAO"}
1
+ {"version":3,"file":"select-BeP7rFkP.d.mts","names":[],"sources":["../src/widgets/select.ts"],"mappings":";;;;;KAgBY;EACV;EACA;EACA;;KAGU,gBAAgB,KAAK;EAC/B,kBAAkB;EAClB,gBAAgB;EAChB;EACA;;;;;;;KAQU,aAAa,MAAM,MAAM,GAAG,KAAK,gBAAgB;UAE5C,YAAY,UAAU,SAAS,gBAAgB;;;EAG9D,OAAO,kBAAkB;;EAEzB;;;;EAIA,YAAY;;;;EAIZ;;EAEA,QAAQ;;;;EAIR;;;EAGA,SAAS,SAAS,aAAa;EAC/B;;;EAGA;;UAGe,aAAa,UAAU,SAAS,gBAAgB;;EAE/D;IAAY,MAAM;;;EAElB;IAAU,MAAM;;;EAEhB;EACA;IAAW;IAAgB,OAAO;;;;;;;;;;;;;cAavB,OAAO,UAAU,SAAS,gBAAgB,KAAK,YAAY,IAAI,aAAa;;kBACvE;WACE;EAET;IACc;IAKD;IAGG;IAKH;IAID;IAKA;IAKK;IAMF;IAMH;;EAarB,YAAY,SAAS,YAAY;MAyB7B,OAAO;MAKP;EAOJ,KAAK,MAAM,OAAO,IAAI;MASlB;MAIA;MAIA,QAAQ;YAIF,QAAQ,KAAK;MA2CnB,YAAY,aAAa;EAI7B,eAAe,KAAK,MAAM,aAAa,OAAO,aAAa;EAM3D,mBAAmB,aAAa;;;;;;;;;;iBAmClB,OAAO,UAAU,SAAS,QAAQ,OAAO,MAAM,YAAY,MAAM,OAAO"}
@@ -1,5 +1,5 @@
1
- import { S as unwrap, f as effect } from "./reactive-DkP75TPk.mjs";
2
1
  import { t as Node } from "./node-CXNobGaP.mjs";
2
+ import { S as unwrap, f as effect } from "./reactive-DkP75TPk.mjs";
3
3
  import { n as resolveSize } from "./size-BHRJuRk9.mjs";
4
4
  import { fitAnsi, stringWidth } from "@zaly/shared/ansi";
5
5
  // src/widgets/select.ts
@@ -191,4 +191,4 @@ function select(state) {
191
191
  }
192
192
  export { select as n, Select as t };
193
193
 
194
- //# sourceMappingURL=select-CUmAFKJh.mjs.map
194
+ //# sourceMappingURL=select-BlsSDBlV.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"select-CUmAFKJh.mjs","names":[],"sources":["../src/widgets/select.ts"],"sourcesContent":["import type { RenderCtx } from \"../core/ctx.ts\"\nimport type { BaseEvents } from \"../core/node.ts\"\nimport type { Reactive, Ref } from \"../core/reactive.ts\"\nimport type { State } from \"../core/state.ts\"\nimport type { NodeActionMap } from \"../input/actions.ts\"\nimport type { Size } from \"../layout/size.ts\"\nimport type { Style } from \"../style/types.ts\"\n\nimport { fitAnsi, stringWidth } from \"@zaly/shared/ansi\"\nimport { Node } from \"../core/node.ts\"\nimport { effect, unwrap } from \"../core/reactive.ts\"\nimport { resolveSize } from \"../layout/size.ts\"\n\n/** Default shape for selectable options. `text` is the canonical\n * searchable/fallback label. `name` overrides the displayed label in the\n * default renderer, and `desc` is shown as a dim right-column description. */\nexport type Option = {\n name?: string\n desc?: string\n text: string\n}\n\nexport type OptionRenderCtx<T> = RenderCtx & {\n visible: readonly T[]\n items: readonly T[]\n active?: boolean\n prefixWidth?: number\n}\n\n/** Per-row rendering hook. `ctx.active` lets callers branch on selection\n * state (e.g. swap an icon or pick a different fg) — but Select still\n * applies the `optionActive` theme slot uniformly so the highlight stays\n * visually consistent. The returned string is clipped/padded to the row\n * width by Select. */\nexport type OptionRender<T> = (item: T, ctx: OptionRenderCtx<T>) => string\n\nexport interface SelectState<T extends Option = Option> extends Style {\n /** Items to show. Accepts a signal accessor so the list can be\n * driven from reactive state (filtered results, search, etc.). */\n items: Reactive<readonly T[]>\n /** Index of the highlighted row. Defaults to 0; clamped on render. */\n active?: number\n /** Max item rows visible at once. The counter (when shown) is an\n * extra row on top of this, not counted against the cap. Window\n * slides to keep `active` in view (pin-until-leave). */\n maxHeight?: Reactive<number>\n /** Show a `(active+1 / total)` footer as an extra row when items\n * don't fit. `undefined` (default) auto-shows when needed;\n * `false` disables, `true` forces on. */\n counter?: boolean\n /** Render width. Defaults to `fill`. */\n width?: Size\n /** Width of the label column for the default renderer. Defaults to the\n * widest visible label, capped to half the row width. Ignored when\n * `render` is set. */\n labelWidth?: number\n /** Per-item renderer. When omitted, the default two-column layout uses\n * `name ?? text` as the label and `desc` as the right-column hint. */\n render?: Reactive<OptionRender<T> | undefined>\n reverse?: boolean\n /** Whether there are more items available than are currently shown. This is a hint for the\n * default renderer to show a \"more\" indicator in the counter. */\n more?: boolean\n}\n\nexport interface SelectEvents<T extends Option = Option> extends BaseEvents {\n /** Fired when the user completes the active item. Payload is the item. */\n complete: { item: T }\n /** Fired when the user picks the active item. Payload is the item. */\n accept: { item: T }\n /** Fired when the user closes the select (esc). */\n close: {}\n changed: { active: number; item?: T }\n}\n\n/**\n * Selectable list. Items are rendered one per row with an active-row\n * highlight; navigation actions (`next`, `prev`, `first`, `last`,\n * `accept`, `complete`, `cancel`) live on `this.actions`, same pattern as\n * `Input`.\n *\n * Used standalone for simple lists and as the underlying list primitive for\n * `picker`, `tree`, and `autocomplete`. Doesn't open/close itself — callers\n * control visibility via `state.visible`.\n */\nexport class Select<T extends Option = Option> extends Node<SelectState<T>, SelectEvents<T>> {\n static readonly type = \"select\"\n override readonly type = Select.type\n\n override actions = {\n \"select.accept\": (): void => {\n const items = this.#items\n if (items.length === 0) return\n void this.emit(\"accept\", { item: items[this.active] })\n },\n \"select.close\": (): void => {\n void this.emit(\"close\")\n },\n \"select.complete\": (): void => {\n const items = this.#items\n if (items.length === 0) return\n void this.emit(\"complete\", { item: items[this.active] })\n },\n \"select.first\": (): void => {\n if (this.#items.length === 0) return\n this.active = 0\n },\n \"select.last\": (): void => {\n const n = this.#items.length\n if (n === 0) return\n this.active = n - 1\n },\n \"select.next\": (): void => {\n const n = this.#items.length\n if (n === 0) return\n this.active += this.#direction\n },\n \"select.page-down\": (): void => {\n const n = this.#items.length\n if (n === 0) return\n const page = Math.max(this.pageSize - 1, 1)\n this.state.active = this.#clamp(this.active + this.#direction * page)\n },\n \"select.page-up\": (): void => {\n const n = this.#items.length\n if (n === 0) return\n const page = Math.max(this.pageSize - 1, 1)\n this.state.active = this.#clamp(this.active - this.#direction * page)\n },\n \"select.prev\": (): void => {\n const n = this.#items.length\n if (n === 0) return\n this.active -= this.#direction\n },\n } satisfies NodeActionMap\n\n /** Top of the currently-rendered window, in absolute item indices.\n * Updated per render using the pin-until-leave rule: stays put\n * while `active` remains in `[start, start + visible)`, slides just\n * enough to re-admit it otherwise. */\n #windowStart = 0\n\n constructor(initial: SelectState<T>) {\n super({ active: 0, ...initial } as SelectState<T>)\n\n let active = this.item\n effect(() => {\n const next = this.item\n if (next === active) return\n active = next\n void this.emit(\"changed\", { active: this.active, item: next })\n })\n }\n\n get #direction(): 1 | -1 {\n return this.state.reverse ? -1 : 1\n }\n\n get #items() {\n return unwrap(this.state.items)\n }\n\n #clamp(i: number): number {\n const n = this.#items.length\n return n === 0 ? 0 : Math.max(0, Math.min(n - 1, i))\n }\n\n set active(i: number) {\n const n = this.#items.length\n this.state.active = n === 0 ? 0 : ((i % n) + n) % n\n }\n\n get active(): number {\n const a = this.state.active ?? 0\n const n = this.#items.length\n if (n === 0) return 0\n return Math.max(0, Math.min(n - 1, a))\n }\n\n bind(node: Node | Ref<Node>): this {\n let n: Node | undefined\n const getn = () => (n = node instanceof Node ? node : node())\n this.on(\"mount\", () => getn().addActionTarget(this))\n this.on(\"unmount\", () => n?.removeActionTarget(this))\n if (this.mounted) getn().addActionTarget(this)\n return this\n }\n\n get count(): number {\n return this.#items.length\n }\n\n get pageSize(): number {\n return unwrap(this.state.maxHeight) ?? Math.max(this.#items.length, 1)\n }\n\n get item(): T | undefined {\n return this.#items[this.active]\n }\n\n protected _render(ctx: RenderCtx): string[] {\n const items = this.#items\n if (items.length === 0) return []\n\n const width = resolveSize(this.state.width ?? \"fill\", ctx.width) ?? ctx.width\n const active = this.active\n const height = Math.min(this.pageSize, items.length)\n if (height === 0) return []\n\n // Pin-until-leave window. `#windowStart` is kept across renders so\n // the list doesn't recenter while the user nudges up/down inside\n let start = this.#windowStart\n if (active < start) start = active\n else if (active >= start + height) start = active - height + 1\n start = Math.max(0, Math.min(Math.max(0, items.length - height), start))\n this.#windowStart = start\n\n const visible = items.slice(start, start + height)\n const renderer = this.renderer\n\n const rows: string[] = []\n for (let i = start; i < start + height; i++) {\n const item = items[i]\n let row = renderer(item, {\n ...ctx,\n active: i === active,\n items,\n visible,\n }).replace(/\\n/g, \" \")\n row = fitAnsi(row, width)\n rows.push(i === active ? ctx.style.optionActive(row) : row)\n }\n if (this.state.reverse) rows.reverse()\n\n if (this.state.counter ?? items.length > height) {\n const shown = items.length === 0 ? 0 : active + 1\n const label = `(${shown}/${items.length}${this.state.more ? \"+\" : \"\"})`\n rows.push(ctx.style.gutter(fitAnsi(label, width)))\n }\n\n return rows\n }\n\n get renderer(): OptionRender<T> {\n return unwrap(this.state.render) ?? this.defaultRenderer()\n }\n\n extendRenderer(fn: (prev: OptionRender<T>) => OptionRender<T>): this {\n const prev = this.renderer\n this.state.render = fn(prev)\n return this\n }\n\n defaultRenderer(): OptionRender<Option> {\n let visible: readonly Option[] = []\n let labelWidth = 0\n\n const update = (ctx: OptionRenderCtx<Option>) => {\n if (ctx.visible === visible) return\n visible = ctx.visible\n if (!visible.some((i) => i.desc)) return (labelWidth = ctx.width) // No desc, so full width\n labelWidth = this.state.labelWidth ?? 0\n labelWidth ||= visible\n .map(itemLabel)\n .reduce((max, label) => Math.max(max, stringWidth(label)), 0)\n labelWidth = Math.min(labelWidth, Math.floor(ctx.width / 2))\n }\n\n return (item: Option, ctx): string => {\n update(ctx)\n const label = fitAnsi(itemLabel(item), labelWidth)\n if (!item.desc) return ctx.style.optionName(label)\n const desc = fitAnsi(item.desc ?? \"\", Math.max(0, ctx.width - labelWidth - 2))\n return `${ctx.style.optionName(label)} ${ctx.style.optionDesc(desc)}`\n }\n }\n}\n\nconst itemLabel = (item: Option): string => (item.name ?? item.text).replace(/\\s+/g, \" \").trim()\n\n/**\n * Factory for a selectable list.\n *\n * ```ts\n * const s = select({ items: [{ text: \"/help\" }, { text: \"/quit\" }] })\n * s.on(\"accept\", ({ item }) => console.log(\"picked\", item.text))\n * ```\n */\nexport function select<T extends Option = Option>(state: State<SelectState<T>>): Select<T> {\n return new Select<T>(state)\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"select-BlsSDBlV.mjs","names":[],"sources":["../src/widgets/select.ts"],"sourcesContent":["import type { RenderCtx } from \"../core/ctx.ts\"\nimport type { BaseEvents } from \"../core/node.ts\"\nimport type { Reactive, Ref } from \"../core/reactive.ts\"\nimport type { State } from \"../core/state.ts\"\nimport type { NodeActionMap } from \"../input/actions.ts\"\nimport type { Size } from \"../layout/size.ts\"\nimport type { Style } from \"../style/types.ts\"\n\nimport { fitAnsi, stringWidth } from \"@zaly/shared/ansi\"\nimport { Node } from \"../core/node.ts\"\nimport { effect, unwrap } from \"../core/reactive.ts\"\nimport { resolveSize } from \"../layout/size.ts\"\n\n/** Default shape for selectable options. `text` is the canonical\n * searchable/fallback label. `name` overrides the displayed label in the\n * default renderer, and `desc` is shown as a dim right-column description. */\nexport type Option = {\n name?: string\n desc?: string\n text: string\n}\n\nexport type OptionRenderCtx<T> = RenderCtx & {\n visible: readonly T[]\n items: readonly T[]\n active?: boolean\n prefixWidth?: number\n}\n\n/** Per-row rendering hook. `ctx.active` lets callers branch on selection\n * state (e.g. swap an icon or pick a different fg) — but Select still\n * applies the `optionActive` theme slot uniformly so the highlight stays\n * visually consistent. The returned string is clipped/padded to the row\n * width by Select. */\nexport type OptionRender<T> = (item: T, ctx: OptionRenderCtx<T>) => string\n\nexport interface SelectState<T extends Option = Option> extends Style {\n /** Items to show. Accepts a signal accessor so the list can be\n * driven from reactive state (filtered results, search, etc.). */\n items: Reactive<readonly T[]>\n /** Index of the highlighted row. Defaults to 0; clamped on render. */\n active?: number\n /** Max item rows visible at once. The counter (when shown) is an\n * extra row on top of this, not counted against the cap. Window\n * slides to keep `active` in view (pin-until-leave). */\n maxHeight?: Reactive<number>\n /** Show a `(active+1 / total)` footer as an extra row when items\n * don't fit. `undefined` (default) auto-shows when needed;\n * `false` disables, `true` forces on. */\n counter?: boolean\n /** Render width. Defaults to `fill`. */\n width?: Size\n /** Width of the label column for the default renderer. Defaults to the\n * widest visible label, capped to half the row width. Ignored when\n * `render` is set. */\n labelWidth?: number\n /** Per-item renderer. When omitted, the default two-column layout uses\n * `name ?? text` as the label and `desc` as the right-column hint. */\n render?: Reactive<OptionRender<T> | undefined>\n reverse?: boolean\n /** Whether there are more items available than are currently shown. This is a hint for the\n * default renderer to show a \"more\" indicator in the counter. */\n more?: boolean\n}\n\nexport interface SelectEvents<T extends Option = Option> extends BaseEvents {\n /** Fired when the user completes the active item. Payload is the item. */\n complete: { item: T }\n /** Fired when the user picks the active item. Payload is the item. */\n accept: { item: T }\n /** Fired when the user closes the select (esc). */\n close: {}\n changed: { active: number; item?: T }\n}\n\n/**\n * Selectable list. Items are rendered one per row with an active-row\n * highlight; navigation actions (`next`, `prev`, `first`, `last`,\n * `accept`, `complete`, `cancel`) live on `this.actions`, same pattern as\n * `Input`.\n *\n * Used standalone for simple lists and as the underlying list primitive for\n * `picker`, `tree`, and `autocomplete`. Doesn't open/close itself — callers\n * control visibility via `state.visible`.\n */\nexport class Select<T extends Option = Option> extends Node<SelectState<T>, SelectEvents<T>> {\n static readonly type = \"select\"\n override readonly type = Select.type\n\n override actions = {\n \"select.accept\": (): void => {\n const items = this.#items\n if (items.length === 0) return\n void this.emit(\"accept\", { item: items[this.active] })\n },\n \"select.close\": (): void => {\n void this.emit(\"close\")\n },\n \"select.complete\": (): void => {\n const items = this.#items\n if (items.length === 0) return\n void this.emit(\"complete\", { item: items[this.active] })\n },\n \"select.first\": (): void => {\n if (this.#items.length === 0) return\n this.active = 0\n },\n \"select.last\": (): void => {\n const n = this.#items.length\n if (n === 0) return\n this.active = n - 1\n },\n \"select.next\": (): void => {\n const n = this.#items.length\n if (n === 0) return\n this.active += this.#direction\n },\n \"select.page-down\": (): void => {\n const n = this.#items.length\n if (n === 0) return\n const page = Math.max(this.pageSize - 1, 1)\n this.state.active = this.#clamp(this.active + this.#direction * page)\n },\n \"select.page-up\": (): void => {\n const n = this.#items.length\n if (n === 0) return\n const page = Math.max(this.pageSize - 1, 1)\n this.state.active = this.#clamp(this.active - this.#direction * page)\n },\n \"select.prev\": (): void => {\n const n = this.#items.length\n if (n === 0) return\n this.active -= this.#direction\n },\n } satisfies NodeActionMap\n\n /** Top of the currently-rendered window, in absolute item indices.\n * Updated per render using the pin-until-leave rule: stays put\n * while `active` remains in `[start, start + visible)`, slides just\n * enough to re-admit it otherwise. */\n #windowStart = 0\n\n constructor(initial: SelectState<T>) {\n super({ active: 0, ...initial } as SelectState<T>)\n\n let active = this.item\n effect(() => {\n const next = this.item\n if (next === active) return\n active = next\n void this.emit(\"changed\", { active: this.active, item: next })\n })\n }\n\n get #direction(): 1 | -1 {\n return this.state.reverse ? -1 : 1\n }\n\n get #items() {\n return unwrap(this.state.items)\n }\n\n #clamp(i: number): number {\n const n = this.#items.length\n return n === 0 ? 0 : Math.max(0, Math.min(n - 1, i))\n }\n\n set active(i: number) {\n const n = this.#items.length\n this.state.active = n === 0 ? 0 : ((i % n) + n) % n\n }\n\n get active(): number {\n const a = this.state.active ?? 0\n const n = this.#items.length\n if (n === 0) return 0\n return Math.max(0, Math.min(n - 1, a))\n }\n\n bind(node: Node | Ref<Node>): this {\n let n: Node | undefined\n const getn = () => (n = node instanceof Node ? node : node())\n this.on(\"mount\", () => getn().addActionTarget(this))\n this.on(\"unmount\", () => n?.removeActionTarget(this))\n if (this.mounted) getn().addActionTarget(this)\n return this\n }\n\n get count(): number {\n return this.#items.length\n }\n\n get pageSize(): number {\n return unwrap(this.state.maxHeight) ?? Math.max(this.#items.length, 1)\n }\n\n get item(): T | undefined {\n return this.#items[this.active]\n }\n\n protected _render(ctx: RenderCtx): string[] {\n const items = this.#items\n if (items.length === 0) return []\n\n const width = resolveSize(this.state.width ?? \"fill\", ctx.width) ?? ctx.width\n const active = this.active\n const height = Math.min(this.pageSize, items.length)\n if (height === 0) return []\n\n // Pin-until-leave window. `#windowStart` is kept across renders so\n // the list doesn't recenter while the user nudges up/down inside\n let start = this.#windowStart\n if (active < start) start = active\n else if (active >= start + height) start = active - height + 1\n start = Math.max(0, Math.min(Math.max(0, items.length - height), start))\n this.#windowStart = start\n\n const visible = items.slice(start, start + height)\n const renderer = this.renderer\n\n const rows: string[] = []\n for (let i = start; i < start + height; i++) {\n const item = items[i]\n let row = renderer(item, {\n ...ctx,\n active: i === active,\n items,\n visible,\n }).replace(/\\n/g, \" \")\n row = fitAnsi(row, width)\n rows.push(i === active ? ctx.style.optionActive(row) : row)\n }\n if (this.state.reverse) rows.reverse()\n\n if (this.state.counter ?? items.length > height) {\n const shown = items.length === 0 ? 0 : active + 1\n const label = `(${shown}/${items.length}${this.state.more ? \"+\" : \"\"})`\n rows.push(ctx.style.gutter(fitAnsi(label, width)))\n }\n\n return rows\n }\n\n get renderer(): OptionRender<T> {\n return unwrap(this.state.render) ?? this.defaultRenderer()\n }\n\n extendRenderer(fn: (prev: OptionRender<T>) => OptionRender<T>): this {\n const prev = this.renderer\n this.state.render = fn(prev)\n return this\n }\n\n defaultRenderer(): OptionRender<Option> {\n let visible: readonly Option[] = []\n let labelWidth = 0\n\n const update = (ctx: OptionRenderCtx<Option>) => {\n if (ctx.visible === visible) return\n visible = ctx.visible\n if (!visible.some((i) => i.desc)) return (labelWidth = ctx.width) // No desc, so full width\n labelWidth = this.state.labelWidth ?? 0\n labelWidth ||= visible\n .map(itemLabel)\n .reduce((max, label) => Math.max(max, stringWidth(label)), 0)\n labelWidth = Math.min(labelWidth, Math.floor(ctx.width / 2))\n }\n\n return (item: Option, ctx): string => {\n update(ctx)\n const label = fitAnsi(itemLabel(item), labelWidth)\n if (!item.desc) return ctx.style.optionName(label)\n const desc = fitAnsi(item.desc ?? \"\", Math.max(0, ctx.width - labelWidth - 2))\n return `${ctx.style.optionName(label)} ${ctx.style.optionDesc(desc)}`\n }\n }\n}\n\nconst itemLabel = (item: Option): string => (item.name ?? item.text).replace(/\\s+/g, \" \").trim()\n\n/**\n * Factory for a selectable list.\n *\n * ```ts\n * const s = select({ items: [{ text: \"/help\" }, { text: \"/quit\" }] })\n * s.on(\"accept\", ({ item }) => console.log(\"picked\", item.text))\n * ```\n */\nexport function select<T extends Option = Option>(state: State<SelectState<T>>): Select<T> {\n return new Select<T>(state)\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import { A as TuiReporter, D as LogEntryFactory, O as LogStyleOverride, j as TuiReporterOpts, k as LoggerStream } from "../queries-Dmd3IjSd.mjs";
1
+ import { A as TuiReporter, D as LogEntryFactory, O as LogStyleOverride, j as TuiReporterOpts, k as LoggerStream } from "../queries-BqFMpQAf.mjs";
2
2
  export { LogEntryFactory, LogStyleOverride, LoggerStream, TuiReporter, TuiReporterOpts };
@@ -1 +1 @@
1
- export { t as TuiReporter } from "../logger-C0WuIlAh.mjs";
1
+ export { t as TuiReporter } from "../logger-DXK8D8Vb.mjs";
@@ -1,4 +1,4 @@
1
- import { L as Overlay, M as LogState, T as OverlaySurface, it as Reactive } from "../queries-Dmd3IjSd.mjs";
1
+ import { L as Overlay, M as LogState, T as OverlaySurface, it as Reactive } from "../queries-BqFMpQAf.mjs";
2
2
  import { LogLevel } from "@zaly/shared/logger";
3
3
  export type NotifProps = Omit<LogState, "content" | "level"> & {
4
4
  level?: LogLevel;
@@ -1,5 +1,5 @@
1
- import { t as log } from "../log-D6gGicwQ.mjs";
2
- import { t as overlay } from "../overlay-zDNpwKu0.mjs";
1
+ import { t as log } from "../log-D7PTmOzE.mjs";
2
+ import { t as overlay } from "../overlay-6kh2gG4K.mjs";
3
3
  // src/services/notifier.ts
4
4
  var Notifier = class {
5
5
  #ui;
@@ -1,8 +1,8 @@
1
- import { L as Overlay, T as OverlaySurface, at as Ref, et as Accessor, it as Reactive, zt as ActionFilter } from "../queries-Dmd3IjSd.mjs";
2
- import { t as Input } from "../input-C3kfYoEJ.mjs";
3
- import { i as Select, t as Option } from "../select-BZCFXdjp.mjs";
4
- import { i as PickerTreeProps, n as PickerItem, r as PickerSelectProps } from "../picker-DsB6--GN.mjs";
5
- import { n as Widget } from "../widget-sPJaKVU2.mjs";
1
+ import { L as Overlay, T as OverlaySurface, at as Ref, et as Accessor, it as Reactive, zt as ActionFilter } from "../queries-BqFMpQAf.mjs";
2
+ import { t as Input } from "../input-C8MEpAg6.mjs";
3
+ import { i as PickerTreeProps, n as PickerItem, r as PickerSelectProps } from "../picker-H_ubc2nk.mjs";
4
+ import { i as Select, t as Option } from "../select-BeP7rFkP.mjs";
5
+ import { n as Widget } from "../widget-CHWHCg1j.mjs";
6
6
  export type ToggleItem = PickerItem & {
7
7
  enabled?: boolean;
8
8
  };
@@ -1,10 +1,10 @@
1
1
  import { c as createRef, y as signal } from "../reactive-DkP75TPk.mjs";
2
- import { r as isMarkdown } from "../inspect-Cli1beu8.mjs";
3
- import { n as text } from "../text-H_2kzwaz.mjs";
4
- import { n as markdown } from "../markdown-DvDIPT5L.mjs";
5
- import { t as overlay } from "../overlay-zDNpwKu0.mjs";
6
- import { t as divider } from "../divider-BPmnQ0Eu.mjs";
7
- import { t as picker } from "../picker-DV_oxKEv.mjs";
2
+ import { r as isMarkdown } from "../inspect-CxtcQch-.mjs";
3
+ import { t as divider } from "../divider-CiNpoiuP.mjs";
4
+ import { n as markdown } from "../markdown-D6quhsm0.mjs";
5
+ import { t as overlay } from "../overlay-6kh2gG4K.mjs";
6
+ import { t as picker } from "../picker-B3XS2HKe.mjs";
7
+ import { n as text } from "../text-BKLHPMsQ.mjs";
8
8
  // src/services/picker.ts
9
9
  var Picker = class {
10
10
  #ui;
@@ -1,7 +1,7 @@
1
- import { T as OverlaySurface, et as Accessor } from "../queries-Dmd3IjSd.mjs";
2
- import { t as Input } from "../input-C3kfYoEJ.mjs";
3
- import { n as PickerItem } from "../picker-DsB6--GN.mjs";
4
- import { n as Widget } from "../widget-sPJaKVU2.mjs";
1
+ import { T as OverlaySurface, et as Accessor } from "../queries-BqFMpQAf.mjs";
2
+ import { t as Input } from "../input-C8MEpAg6.mjs";
3
+ import { n as PickerItem } from "../picker-H_ubc2nk.mjs";
4
+ import { n as Widget } from "../widget-CHWHCg1j.mjs";
5
5
  export type ToggleItem = PickerItem & {
6
6
  enabled?: boolean;
7
7
  };
@@ -1,9 +1,9 @@
1
1
  import { y as signal } from "../reactive-DkP75TPk.mjs";
2
- import { r as isMarkdown } from "../inspect-Cli1beu8.mjs";
3
- import { n as text } from "../text-H_2kzwaz.mjs";
4
- import { n as markdown } from "../markdown-DvDIPT5L.mjs";
5
- import { t as overlay } from "../overlay-zDNpwKu0.mjs";
6
- import { t as divider } from "../divider-BPmnQ0Eu.mjs";
2
+ import { r as isMarkdown } from "../inspect-CxtcQch-.mjs";
3
+ import { t as divider } from "../divider-CiNpoiuP.mjs";
4
+ import { n as markdown } from "../markdown-D6quhsm0.mjs";
5
+ import { t as overlay } from "../overlay-6kh2gG4K.mjs";
6
+ import { n as text } from "../text-BKLHPMsQ.mjs";
7
7
  // src/services/prompt.ts
8
8
  var Prompt = class {
9
9
  #ui;
@@ -1,6 +1,6 @@
1
- import { o as openAnsi, t as RESET } from "../ansi-CxgRPLA2.mjs";
2
1
  import { n as isShikiTheme, t as isShikiLang } from "../shiki-DUUAIE6f.mjs";
3
- import { n as syntaxScopes } from "../theme-B8hb1lPU.mjs";
2
+ import { s as openAnsi, t as RESET } from "../ansi-oiRnTQr9.mjs";
3
+ import { n as syntaxScopes } from "../theme-CG51x7aG.mjs";
4
4
  import { n as workerHost } from "../worker-CtEowucz.mjs";
5
5
  import { createHighlighterCore } from "shiki/core";
6
6
  import { createOnigurumaEngine } from "shiki/engine/oniguruma";
@@ -11,9 +11,9 @@ async function shikiThemes() {
11
11
  }
12
12
  async function codeToAnsi(code, lang, opts) {
13
13
  if (!hasColors || !lang || !isShikiLang(lang)) return code;
14
- const { shikiWorker } = await import("./client-C69qWhMG.mjs");
14
+ const { shikiWorker } = await import("./client-C7iR8kp-.mjs");
15
15
  return (await shikiWorker.highlight(code, lang, opts)).value;
16
16
  }
17
17
  export { shikiThemes as n, codeToAnsi as t };
18
18
 
19
- //# sourceMappingURL=shiki-BAf9PdIc.mjs.map
19
+ //# sourceMappingURL=shiki-CUJQssUJ.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"shiki-BAf9PdIc.mjs","names":[],"sources":["../src/shiki/shiki.ts"],"sourcesContent":["import type { ShikiOpts, ShikiTheme } from \"./types.ts\"\n\nimport { hasColors } from \"@zaly/shared/env\"\nimport { isShikiLang } from \"../schemas/shiki.ts\"\n\n/** List bundled highlighting themes without loading their color definitions. */\nexport async function shikiThemes() {\n const { bundledThemesInfo } = await import(\"shiki/themes\")\n return bundledThemesInfo.map(({ id, displayName }) => ({\n id: id as ShikiTheme,\n name: displayName,\n }))\n}\n\nexport async function codeToAnsi(code: string, lang: string, opts?: ShikiOpts): Promise<string> {\n if (!hasColors || !lang || !isShikiLang(lang)) return code\n const { shikiWorker } = await import(\"../shiki/client.ts\")\n const ret = await shikiWorker.highlight(code, lang, opts)\n return ret.value\n}\n"],"mappings":";;;;AAMA,eAAsB,cAAc;CAClC,MAAM,EAAE,sBAAsB,MAAM,OAAO;CAC3C,OAAO,kBAAkB,KAAK,EAAE,IAAI,mBAAmB;EACjD;EACJ,MAAM;CACR,EAAE;AACJ;AAEA,eAAsB,WAAW,MAAc,MAAc,MAAmC;CAC9F,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,YAAY,IAAI,GAAG,OAAO;CACtD,MAAM,EAAE,gBAAgB,MAAM,OAAO;CAErC,QAAO,MADW,YAAY,UAAU,MAAM,MAAM,IAAI,EAAA,CAC7C;AACb"}
1
+ {"version":3,"file":"shiki-CUJQssUJ.mjs","names":[],"sources":["../src/shiki/shiki.ts"],"sourcesContent":["import type { ShikiOpts, ShikiTheme } from \"./types.ts\"\n\nimport { hasColors } from \"@zaly/shared/env\"\nimport { isShikiLang } from \"../schemas/shiki.ts\"\n\n/** List bundled highlighting themes without loading their color definitions. */\nexport async function shikiThemes() {\n const { bundledThemesInfo } = await import(\"shiki/themes\")\n return bundledThemesInfo.map(({ id, displayName }) => ({\n id: id as ShikiTheme,\n name: displayName,\n }))\n}\n\nexport async function codeToAnsi(code: string, lang: string, opts?: ShikiOpts): Promise<string> {\n if (!hasColors || !lang || !isShikiLang(lang)) return code\n const { shikiWorker } = await import(\"../shiki/client.ts\")\n const ret = await shikiWorker.highlight(code, lang, opts)\n return ret.value\n}\n"],"mappings":";;;;AAMA,eAAsB,cAAc;CAClC,MAAM,EAAE,sBAAsB,MAAM,OAAO;CAC3C,OAAO,kBAAkB,KAAK,EAAE,IAAI,mBAAmB;EACjD;EACJ,MAAM;CACR,EAAE;AACJ;AAEA,eAAsB,WAAW,MAAc,MAAc,MAAmC;CAC9F,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,YAAY,IAAI,GAAG,OAAO;CACtD,MAAM,EAAE,gBAAgB,MAAM,OAAO;CAErC,QAAO,MADW,YAAY,UAAU,MAAM,MAAM,IAAI,EAAA,CAC7C;AACb"}
@@ -1,5 +1,5 @@
1
- import { C as useActiveOwner, E as withOwner, S as unwrap, x as untrack } from "./reactive-DkP75TPk.mjs";
2
1
  import { t as Node } from "./node-CXNobGaP.mjs";
2
+ import { C as useActiveOwner, E as withOwner, S as unwrap, x as untrack } from "./reactive-DkP75TPk.mjs";
3
3
  // src/widgets/show.ts
4
4
  /** Conditional fragment backing `show()`. Branches are created lazily:
5
5
  * a `use` factory only runs the first time its condition wins. Once
@@ -81,4 +81,4 @@ function show(...spec) {
81
81
  }
82
82
  export { show as t };
83
83
 
84
- //# sourceMappingURL=show-D5XNXgZf.mjs.map
84
+ //# sourceMappingURL=show-BfIUw8A1.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"show-D5XNXgZf.mjs","names":[],"sources":["../src/widgets/show.ts"],"sourcesContent":["import type { RenderCtx } from \"../core/ctx.ts\"\nimport type { Reactive } from \"../core/reactive.ts\"\n\nimport { Node } from \"../core/node.ts\"\nimport { untrack, unwrap, useActiveOwner, withOwner } from \"../core/reactive.ts\"\n\nexport type ShowGate = { when: Reactive<unknown> }\nexport type ShowBranch = { when: Reactive<unknown>; use: ShowChildren }\nexport type ShowChildren = () => Node | Node[]\nexport type ShowSpec = (ShowGate | ShowBranch)[] | [...(ShowGate | ShowBranch)[], ShowChildren]\n\ntype ShowState = {\n when: Reactive<unknown>\n use?: ShowChildren\n children?: Node[]\n}\n\nexport type { Show }\n\n/** Conditional fragment backing `show()`. Branches are created lazily:\n * a `use` factory only runs the first time its condition wins. Once\n * created, the branch remains mounted and owned; inactive branches simply\n * don't participate in layout/rendering and contribute zero rows.\n *\n * Lazy factories run under the owner captured at `show()` creation time,\n * so context reads behave as if the branch had been constructed eagerly.\n */\nclass Show extends Node {\n #state: ShowState[] = []\n #owner = useActiveOwner()\n\n constructor(spec: ShowSpec) {\n super({})\n let fallback = false\n for (const s of spec) {\n if (fallback) throw new Error(\"Show: `fallback` must be the final argument\")\n if (typeof s === \"function\") {\n this.#state.push({ use: s, when: true })\n fallback = true\n } else this.#state.push(s)\n }\n }\n\n #nodes(s: ShowState, use: ShowChildren): Node[] {\n if (s.children) return s.children\n const create = () => untrack(use)\n const nodes = this.#owner ? withOwner(this.#owner, create) : create()\n s.children = Array.isArray(nodes) ? nodes : [nodes]\n for (const c of s.children) this.add(c)\n return s.children\n }\n\n override layoutChildren(): readonly Node[] {\n for (const s of this.#state) {\n const matches = unwrap(s.when)\n if (s.use === undefined) {\n if (!matches) return []\n continue\n } else if (!matches) continue\n return this.#nodes(s, s.use)\n }\n return []\n }\n\n /** Standalone-render fallback. Box parents go through\n * `layoutChildren` and bypass this; only fires when `Show` sits\n * outside a layout container (root, overlay, etc.). */\n protected async _render(ctx: RenderCtx): Promise<string[]> {\n const targets = this.layoutChildren()\n const rows = await Promise.all(targets.map((c) => c.render(ctx)))\n return rows.flat()\n }\n}\n\n/** Lazy conditional rendering.\n *\n * Specs are evaluated from left to right:\n * - `{ when }` is a guard. When false, rendering stops with no rows; when\n * true, evaluation continues.\n * - `{ when, use }` is a conditional branch. The first branch whose\n * condition is truthy is rendered.\n * - A final bare factory is the fallback branch and must be the last\n * argument.\n *\n * Branch factories are lazy and run at most once. Created branches stay\n * mounted across toggles, preserving state, effects, and async resources.\n *\n * ```ts\n * show({ when: isLoading }, () => spinner({ color: \"accent\" }))\n *\n * show(\n * { when: full },\n * { when: isError, use: () => errorView() },\n * () => resultView()\n * )\n * ```\n */\nexport function show(...spec: ShowSpec): Show {\n return new Show(spec)\n}\n"],"mappings":";;;;;;;;;;;AA2BA,IAAM,OAAN,cAAmB,KAAK;CACtB,SAAsB,CAAC;CACvB,SAAS,eAAe;CAExB,YAAY,MAAgB;EAC1B,MAAM,CAAC,CAAC;EACR,IAAI,WAAW;EACf,KAAK,MAAM,KAAK,MAAM;GACpB,IAAI,UAAU,MAAM,IAAI,MAAM,6CAA6C;GAC3E,IAAI,OAAO,MAAM,YAAY;IAC3B,KAAK,OAAO,KAAK;KAAE,KAAK;KAAG,MAAM;IAAK,CAAC;IACvC,WAAW;GACb,OAAO,KAAK,OAAO,KAAK,CAAC;EAC3B;CACF;CAEA,OAAO,GAAc,KAA2B;EAC9C,IAAI,EAAE,UAAU,OAAO,EAAE;EACzB,MAAM,eAAe,QAAQ,GAAG;EAChC,MAAM,QAAQ,KAAK,SAAS,UAAU,KAAK,QAAQ,MAAM,IAAI,OAAO;EACpE,EAAE,WAAW,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK;EAClD,KAAK,MAAM,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;EACtC,OAAO,EAAE;CACX;CAEA,iBAA2C;EACzC,KAAK,MAAM,KAAK,KAAK,QAAQ;GAC3B,MAAM,UAAU,OAAO,EAAE,IAAI;GAC7B,IAAI,EAAE,QAAQ,KAAA,GAAW;IACvB,IAAI,CAAC,SAAS,OAAO,CAAC;IACtB;GACF,OAAO,IAAI,CAAC,SAAS;GACrB,OAAO,KAAK,OAAO,GAAG,EAAE,GAAG;EAC7B;EACA,OAAO,CAAC;CACV;;;;CAKA,MAAgB,QAAQ,KAAmC;EACzD,MAAM,UAAU,KAAK,eAAe;EAEpC,QAAO,MADY,QAAQ,IAAI,QAAQ,KAAK,MAAM,EAAE,OAAO,GAAG,CAAC,CAAC,EAAA,CACpD,KAAK;CACnB;AACF;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,SAAgB,KAAK,GAAG,MAAsB;CAC5C,OAAO,IAAI,KAAK,IAAI;AACtB"}
1
+ {"version":3,"file":"show-BfIUw8A1.mjs","names":[],"sources":["../src/widgets/show.ts"],"sourcesContent":["import type { RenderCtx } from \"../core/ctx.ts\"\nimport type { Reactive } from \"../core/reactive.ts\"\n\nimport { Node } from \"../core/node.ts\"\nimport { untrack, unwrap, useActiveOwner, withOwner } from \"../core/reactive.ts\"\n\nexport type ShowGate = { when: Reactive<unknown> }\nexport type ShowBranch = { when: Reactive<unknown>; use: ShowChildren }\nexport type ShowChildren = () => Node | Node[]\nexport type ShowSpec = (ShowGate | ShowBranch)[] | [...(ShowGate | ShowBranch)[], ShowChildren]\n\ntype ShowState = {\n when: Reactive<unknown>\n use?: ShowChildren\n children?: Node[]\n}\n\nexport type { Show }\n\n/** Conditional fragment backing `show()`. Branches are created lazily:\n * a `use` factory only runs the first time its condition wins. Once\n * created, the branch remains mounted and owned; inactive branches simply\n * don't participate in layout/rendering and contribute zero rows.\n *\n * Lazy factories run under the owner captured at `show()` creation time,\n * so context reads behave as if the branch had been constructed eagerly.\n */\nclass Show extends Node {\n #state: ShowState[] = []\n #owner = useActiveOwner()\n\n constructor(spec: ShowSpec) {\n super({})\n let fallback = false\n for (const s of spec) {\n if (fallback) throw new Error(\"Show: `fallback` must be the final argument\")\n if (typeof s === \"function\") {\n this.#state.push({ use: s, when: true })\n fallback = true\n } else this.#state.push(s)\n }\n }\n\n #nodes(s: ShowState, use: ShowChildren): Node[] {\n if (s.children) return s.children\n const create = () => untrack(use)\n const nodes = this.#owner ? withOwner(this.#owner, create) : create()\n s.children = Array.isArray(nodes) ? nodes : [nodes]\n for (const c of s.children) this.add(c)\n return s.children\n }\n\n override layoutChildren(): readonly Node[] {\n for (const s of this.#state) {\n const matches = unwrap(s.when)\n if (s.use === undefined) {\n if (!matches) return []\n continue\n } else if (!matches) continue\n return this.#nodes(s, s.use)\n }\n return []\n }\n\n /** Standalone-render fallback. Box parents go through\n * `layoutChildren` and bypass this; only fires when `Show` sits\n * outside a layout container (root, overlay, etc.). */\n protected async _render(ctx: RenderCtx): Promise<string[]> {\n const targets = this.layoutChildren()\n const rows = await Promise.all(targets.map((c) => c.render(ctx)))\n return rows.flat()\n }\n}\n\n/** Lazy conditional rendering.\n *\n * Specs are evaluated from left to right:\n * - `{ when }` is a guard. When false, rendering stops with no rows; when\n * true, evaluation continues.\n * - `{ when, use }` is a conditional branch. The first branch whose\n * condition is truthy is rendered.\n * - A final bare factory is the fallback branch and must be the last\n * argument.\n *\n * Branch factories are lazy and run at most once. Created branches stay\n * mounted across toggles, preserving state, effects, and async resources.\n *\n * ```ts\n * show({ when: isLoading }, () => spinner({ color: \"accent\" }))\n *\n * show(\n * { when: full },\n * { when: isError, use: () => errorView() },\n * () => resultView()\n * )\n * ```\n */\nexport function show(...spec: ShowSpec): Show {\n return new Show(spec)\n}\n"],"mappings":";;;;;;;;;;;AA2BA,IAAM,OAAN,cAAmB,KAAK;CACtB,SAAsB,CAAC;CACvB,SAAS,eAAe;CAExB,YAAY,MAAgB;EAC1B,MAAM,CAAC,CAAC;EACR,IAAI,WAAW;EACf,KAAK,MAAM,KAAK,MAAM;GACpB,IAAI,UAAU,MAAM,IAAI,MAAM,6CAA6C;GAC3E,IAAI,OAAO,MAAM,YAAY;IAC3B,KAAK,OAAO,KAAK;KAAE,KAAK;KAAG,MAAM;IAAK,CAAC;IACvC,WAAW;GACb,OAAO,KAAK,OAAO,KAAK,CAAC;EAC3B;CACF;CAEA,OAAO,GAAc,KAA2B;EAC9C,IAAI,EAAE,UAAU,OAAO,EAAE;EACzB,MAAM,eAAe,QAAQ,GAAG;EAChC,MAAM,QAAQ,KAAK,SAAS,UAAU,KAAK,QAAQ,MAAM,IAAI,OAAO;EACpE,EAAE,WAAW,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK;EAClD,KAAK,MAAM,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;EACtC,OAAO,EAAE;CACX;CAEA,iBAA2C;EACzC,KAAK,MAAM,KAAK,KAAK,QAAQ;GAC3B,MAAM,UAAU,OAAO,EAAE,IAAI;GAC7B,IAAI,EAAE,QAAQ,KAAA,GAAW;IACvB,IAAI,CAAC,SAAS,OAAO,CAAC;IACtB;GACF,OAAO,IAAI,CAAC,SAAS;GACrB,OAAO,KAAK,OAAO,GAAG,EAAE,GAAG;EAC7B;EACA,OAAO,CAAC;CACV;;;;CAKA,MAAgB,QAAQ,KAAmC;EACzD,MAAM,UAAU,KAAK,eAAe;EAEpC,QAAO,MADY,QAAQ,IAAI,QAAQ,KAAK,MAAM,EAAE,OAAO,GAAG,CAAC,CAAC,EAAA,CACpD,KAAK;CACnB;AACF;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,SAAgB,KAAK,GAAG,MAAsB;CAC5C,OAAO,IAAI,KAAK,IAAI;AACtB"}
@@ -1,6 +1,6 @@
1
+ import { s as openAnsi } from "./ansi-oiRnTQr9.mjs";
1
2
  import { n as isHexColor } from "./color-Cr1VoL49.mjs";
2
3
  import { n as shiftLightness } from "./oklch-Boh4YHEc.mjs";
3
- import { o as openAnsi } from "./ansi-CxgRPLA2.mjs";
4
4
  // src/style/style.ts
5
5
  /**
6
6
  * Build the opening SGR escape for a style descriptor. Returns '' if nothing
@@ -105,4 +105,4 @@ var ThemeResolver = class ThemeResolver {
105
105
  };
106
106
  export { resolveAnsiStyle as n, resolveStyle as r, openStyle as t };
107
107
 
108
- //# sourceMappingURL=style-Cw_EuszU.mjs.map
108
+ //# sourceMappingURL=style-DTwmlkfR.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"style-Cw_EuszU.mjs","names":[],"sources":["../src/style/style.ts"],"sourcesContent":["import type { Theme } from \"../themes/types.ts\"\nimport type { AnsiColor, AnsiStyle, Color, Style } from \"./types.ts\"\n\nimport { openAnsi } from \"./ansi.ts\"\nimport { isHexColor } from \"./color.ts\"\nimport { shiftLightness } from \"./oklch.ts\"\n\n/**\n * Build the opening SGR escape for a style descriptor. Returns '' if nothing\n * would be emitted. Unresolvable colors (invalid or 'inherit') are dropped.\n *\n * When `theme` is provided, `fg`/`bg` values matching a theme color slot\n * (e.g. `\"primary\"`, `\"muted\"`) are resolved against it first. The output\n * ordering is attrs → fg → bg, combined into a single `\\x1b[...m` run.\n *\n * @internal\n */\nexport function openStyle(style: Style, theme?: Theme): string {\n return openAnsi(resolveAnsiStyle(style, theme))\n}\n\n/**\n * Resolve a style-slot reference into a `Style` object. A ref is either a\n * theme slot name (string), an inline `Style`, or `undefined`:\n *\n * - Inline `Style` → returned as-is (no slot lookup).\n * - String ref pointing at a **Color** slot → wrapped as `{ fg: <color> }`.\n * - String ref pointing at a **Style** slot → returned directly.\n * - String ref that doesn't match a slot → treated as a fg color\n * (`{ fg: <ref> }`) and resolved downstream by `colorParams`.\n * - `undefined` → `{}` (emits nothing).\n *\n * @internal\n */\nexport function resolveStyle(ref: string | Style | undefined, theme?: Theme): Style {\n return ThemeResolver.from(theme).getStyle(ref)\n}\n\n/** Resolve semantic style references and colors without emitting terminal escapes. */\nexport function resolveAnsiStyle(ref: string | Style | undefined, theme?: Theme): AnsiStyle {\n const resolver = ThemeResolver.from(theme)\n const { style: _, ...style } = resolver.getStyle(ref)\n return {\n ...style,\n bg: style.bg !== undefined ? resolver.getColor(style.bg, \"bg\") : undefined,\n fg: style.fg !== undefined ? resolver.getColor(style.fg, \"fg\") : undefined,\n }\n}\n\nfunction parseColor(c: string): { base: string; lightness?: number } {\n const m = c.match(/^(.+?)([+-]\\d{1,3})$/)\n if (!m) return { base: c }\n let lightness = Number(m[2])\n if (!Number.isFinite(lightness))\n throw new TypeError(`Invalid color step in color \"${c}\": ${m[2]}`)\n lightness = Math.abs(lightness) < 1 ? lightness : lightness / 100\n return { base: m[1], lightness }\n}\n\nclass ThemeResolver {\n static #cache = new Map<Partial<Theme>, ThemeResolver>()\n static #main = new ThemeResolver()\n #theme: Partial<Theme>\n #styleCache = new Map<string, Style>()\n #colorCache = new Map<string, string>()\n\n private constructor(theme: Partial<Theme> = {}) {\n this.#theme = theme\n }\n\n static from(theme?: Theme): ThemeResolver {\n if (theme === undefined) return this.#main\n let resolver = this.#cache.get(theme)\n if (!resolver) {\n resolver = new ThemeResolver(theme)\n this.#cache.set(theme, resolver)\n }\n return resolver\n }\n\n getStyle(ref?: string | Style, seen?: Set<string>): Style {\n if (ref === undefined) return {}\n if (typeof ref === \"object\")\n return ref.style ? { ...this.getStyle(ref.style, seen), ...ref } : ref\n\n let ret = this.#styleCache.get(ref)\n if (ret) return ret\n\n seen ??= new Set<string>()\n if (seen.has(ref)) throw new TypeError(`Circular dependency for theme slot \"${ref}\".`)\n seen.add(ref)\n\n const value = this.#theme[ref as keyof Theme]\n ret = value === undefined ? { fg: ref as Color } : this.getStyle(value, seen)\n this.#styleCache.set(ref, ret)\n return ret\n }\n\n getColor(ref?: string, kind: \"fg\" | \"bg\" = \"fg\", seen?: Set<string>): AnsiColor {\n if (ref === undefined) return \"inherit\"\n\n const key = `${kind}:${ref}`\n let ret = this.#colorCache.get(key)\n if (ret) return ret as AnsiColor\n\n seen ??= new Set<string>()\n if (seen.has(ref)) throw new TypeError(`Circular dependency for theme slot \"${ref}\".`)\n seen.add(ref)\n\n const { base, lightness } = parseColor(ref)\n\n let value = this.#theme[base as keyof Theme] ?? base\n if (typeof value === \"object\") value = this.getColor(value[kind], kind, seen)\n else if (value !== base) value = this.getColor(value, kind, seen)\n ret = lightness !== undefined && isHexColor(value) ? shiftLightness(value, lightness) : value\n this.#colorCache.set(key, ret)\n return ret as AnsiColor\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"style-DTwmlkfR.mjs","names":[],"sources":["../src/style/style.ts"],"sourcesContent":["import type { Theme } from \"../themes/types.ts\"\nimport type { AnsiColor, AnsiStyle, Color, Style } from \"./types.ts\"\n\nimport { openAnsi } from \"./ansi.ts\"\nimport { isHexColor } from \"./color.ts\"\nimport { shiftLightness } from \"./oklch.ts\"\n\n/**\n * Build the opening SGR escape for a style descriptor. Returns '' if nothing\n * would be emitted. Unresolvable colors (invalid or 'inherit') are dropped.\n *\n * When `theme` is provided, `fg`/`bg` values matching a theme color slot\n * (e.g. `\"primary\"`, `\"muted\"`) are resolved against it first. The output\n * ordering is attrs → fg → bg, combined into a single `\\x1b[...m` run.\n *\n * @internal\n */\nexport function openStyle(style: Style, theme?: Theme): string {\n return openAnsi(resolveAnsiStyle(style, theme))\n}\n\n/**\n * Resolve a style-slot reference into a `Style` object. A ref is either a\n * theme slot name (string), an inline `Style`, or `undefined`:\n *\n * - Inline `Style` → returned as-is (no slot lookup).\n * - String ref pointing at a **Color** slot → wrapped as `{ fg: <color> }`.\n * - String ref pointing at a **Style** slot → returned directly.\n * - String ref that doesn't match a slot → treated as a fg color\n * (`{ fg: <ref> }`) and resolved downstream by `colorParams`.\n * - `undefined` → `{}` (emits nothing).\n *\n * @internal\n */\nexport function resolveStyle(ref: string | Style | undefined, theme?: Theme): Style {\n return ThemeResolver.from(theme).getStyle(ref)\n}\n\n/** Resolve semantic style references and colors without emitting terminal escapes. */\nexport function resolveAnsiStyle(ref: string | Style | undefined, theme?: Theme): AnsiStyle {\n const resolver = ThemeResolver.from(theme)\n const { style: _, ...style } = resolver.getStyle(ref)\n return {\n ...style,\n bg: style.bg !== undefined ? resolver.getColor(style.bg, \"bg\") : undefined,\n fg: style.fg !== undefined ? resolver.getColor(style.fg, \"fg\") : undefined,\n }\n}\n\nfunction parseColor(c: string): { base: string; lightness?: number } {\n const m = c.match(/^(.+?)([+-]\\d{1,3})$/)\n if (!m) return { base: c }\n let lightness = Number(m[2])\n if (!Number.isFinite(lightness))\n throw new TypeError(`Invalid color step in color \"${c}\": ${m[2]}`)\n lightness = Math.abs(lightness) < 1 ? lightness : lightness / 100\n return { base: m[1], lightness }\n}\n\nclass ThemeResolver {\n static #cache = new Map<Partial<Theme>, ThemeResolver>()\n static #main = new ThemeResolver()\n #theme: Partial<Theme>\n #styleCache = new Map<string, Style>()\n #colorCache = new Map<string, string>()\n\n private constructor(theme: Partial<Theme> = {}) {\n this.#theme = theme\n }\n\n static from(theme?: Theme): ThemeResolver {\n if (theme === undefined) return this.#main\n let resolver = this.#cache.get(theme)\n if (!resolver) {\n resolver = new ThemeResolver(theme)\n this.#cache.set(theme, resolver)\n }\n return resolver\n }\n\n getStyle(ref?: string | Style, seen?: Set<string>): Style {\n if (ref === undefined) return {}\n if (typeof ref === \"object\")\n return ref.style ? { ...this.getStyle(ref.style, seen), ...ref } : ref\n\n let ret = this.#styleCache.get(ref)\n if (ret) return ret\n\n seen ??= new Set<string>()\n if (seen.has(ref)) throw new TypeError(`Circular dependency for theme slot \"${ref}\".`)\n seen.add(ref)\n\n const value = this.#theme[ref as keyof Theme]\n ret = value === undefined ? { fg: ref as Color } : this.getStyle(value, seen)\n this.#styleCache.set(ref, ret)\n return ret\n }\n\n getColor(ref?: string, kind: \"fg\" | \"bg\" = \"fg\", seen?: Set<string>): AnsiColor {\n if (ref === undefined) return \"inherit\"\n\n const key = `${kind}:${ref}`\n let ret = this.#colorCache.get(key)\n if (ret) return ret as AnsiColor\n\n seen ??= new Set<string>()\n if (seen.has(ref)) throw new TypeError(`Circular dependency for theme slot \"${ref}\".`)\n seen.add(ref)\n\n const { base, lightness } = parseColor(ref)\n\n let value = this.#theme[base as keyof Theme] ?? base\n if (typeof value === \"object\") value = this.getColor(value[kind], kind, seen)\n else if (value !== base) value = this.getColor(value, kind, seen)\n ret = lightness !== undefined && isHexColor(value) ? shiftLightness(value, lightness) : value\n this.#colorCache.set(key, ret)\n return ret as AnsiColor\n }\n}\n"],"mappings":";;;;;;;;;;;;;;AAiBA,SAAgB,UAAU,OAAc,OAAuB;CAC7D,OAAO,SAAS,iBAAiB,OAAO,KAAK,CAAC;AAChD;;;;;;;;;;;;;;AAeA,SAAgB,aAAa,KAAiC,OAAsB;CAClF,OAAO,cAAc,KAAK,KAAK,CAAC,CAAC,SAAS,GAAG;AAC/C;;AAGA,SAAgB,iBAAiB,KAAiC,OAA0B;CAC1F,MAAM,WAAW,cAAc,KAAK,KAAK;CACzC,MAAM,EAAE,OAAO,GAAG,GAAG,UAAU,SAAS,SAAS,GAAG;CACpD,OAAO;EACL,GAAG;EACH,IAAI,MAAM,OAAO,KAAA,IAAY,SAAS,SAAS,MAAM,IAAI,IAAI,IAAI,KAAA;EACjE,IAAI,MAAM,OAAO,KAAA,IAAY,SAAS,SAAS,MAAM,IAAI,IAAI,IAAI,KAAA;CACnE;AACF;AAEA,SAAS,WAAW,GAAiD;CACnE,MAAM,IAAI,EAAE,MAAM,sBAAsB;CACxC,IAAI,CAAC,GAAG,OAAO,EAAE,MAAM,EAAE;CACzB,IAAI,YAAY,OAAO,EAAE,EAAE;CAC3B,IAAI,CAAC,OAAO,SAAS,SAAS,GAC5B,MAAM,IAAI,UAAU,gCAAgC,EAAE,KAAK,EAAE,IAAI;CACnE,YAAY,KAAK,IAAI,SAAS,IAAI,IAAI,YAAY,YAAY;CAC9D,OAAO;EAAE,MAAM,EAAE;EAAI;CAAU;AACjC;AAEA,IAAM,gBAAN,MAAM,cAAc;CAClB,OAAO,yBAAS,IAAI,IAAmC;CACvD,OAAO,QAAQ,IAAI,cAAc;CACjC;CACA,8BAAc,IAAI,IAAmB;CACrC,8BAAc,IAAI,IAAoB;CAEtC,YAAoB,QAAwB,CAAC,GAAG;EAC9C,KAAK,SAAS;CAChB;CAEA,OAAO,KAAK,OAA8B;EACxC,IAAI,UAAU,KAAA,GAAW,OAAO,KAAK;EACrC,IAAI,WAAW,KAAK,OAAO,IAAI,KAAK;EACpC,IAAI,CAAC,UAAU;GACb,WAAW,IAAI,cAAc,KAAK;GAClC,KAAK,OAAO,IAAI,OAAO,QAAQ;EACjC;EACA,OAAO;CACT;CAEA,SAAS,KAAsB,MAA2B;EACxD,IAAI,QAAQ,KAAA,GAAW,OAAO,CAAC;EAC/B,IAAI,OAAO,QAAQ,UACjB,OAAO,IAAI,QAAQ;GAAE,GAAG,KAAK,SAAS,IAAI,OAAO,IAAI;GAAG,GAAG;EAAI,IAAI;EAErE,IAAI,MAAM,KAAK,YAAY,IAAI,GAAG;EAClC,IAAI,KAAK,OAAO;EAEhB,yBAAS,IAAI,IAAY;EACzB,IAAI,KAAK,IAAI,GAAG,GAAG,MAAM,IAAI,UAAU,uCAAuC,IAAI,GAAG;EACrF,KAAK,IAAI,GAAG;EAEZ,MAAM,QAAQ,KAAK,OAAO;EAC1B,MAAM,UAAU,KAAA,IAAY,EAAE,IAAI,IAAa,IAAI,KAAK,SAAS,OAAO,IAAI;EAC5E,KAAK,YAAY,IAAI,KAAK,GAAG;EAC7B,OAAO;CACT;CAEA,SAAS,KAAc,OAAoB,MAAM,MAA+B;EAC9E,IAAI,QAAQ,KAAA,GAAW,OAAO;EAE9B,MAAM,MAAM,GAAG,KAAK,GAAG;EACvB,IAAI,MAAM,KAAK,YAAY,IAAI,GAAG;EAClC,IAAI,KAAK,OAAO;EAEhB,yBAAS,IAAI,IAAY;EACzB,IAAI,KAAK,IAAI,GAAG,GAAG,MAAM,IAAI,UAAU,uCAAuC,IAAI,GAAG;EACrF,KAAK,IAAI,GAAG;EAEZ,MAAM,EAAE,MAAM,cAAc,WAAW,GAAG;EAE1C,IAAI,QAAQ,KAAK,OAAO,SAAwB;EAChD,IAAI,OAAO,UAAU,UAAU,QAAQ,KAAK,SAAS,MAAM,OAAO,MAAM,IAAI;OACvE,IAAI,UAAU,MAAM,QAAQ,KAAK,SAAS,OAAO,MAAM,IAAI;EAChE,MAAM,cAAc,KAAA,KAAa,WAAW,KAAK,IAAI,eAAe,OAAO,SAAS,IAAI;EACxF,KAAK,YAAY,IAAI,KAAK,GAAG;EAC7B,OAAO;CACT;AACF"}
package/dist/style.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { a as BrightAnsiColorName, c as HexColor, d as ThemeKey, i as AnyStyle, l as RGB, n as AnsiColorName, o as Color, r as AnsiStyle, s as ColorLightness, t as AnsiColor, u as Style } from "./types-ByMHEdCF.mjs";
2
1
  import { a as StyleBuilder, i as isMarkdown, n as inspect, o as styleBuilder, r as inspectFormat, t as InspectOpts } from "./inspect-hSl3U2BD.mjs";
2
+ import { a as BrightAnsiColorName, c as HexColor, d as ThemeKey, i as AnyStyle, l as RGB, n as AnsiColorName, o as Color, r as AnsiStyle, s as ColorLightness, t as AnsiColor, u as Style } from "./types-ByMHEdCF.mjs";
3
3
  export declare function toHex(c: RGB): HexColor;
4
4
  export declare function toHex(r: number, g: number, b: number): HexColor;
5
5
  export declare function parseHex(hex: HexColor): RGB;
package/dist/style.mjs CHANGED
@@ -1,4 +1,4 @@
1
+ import { t as styleBuilder } from "./builder-D8Sx5N8a.mjs";
1
2
  import { i as toHex, n as isHexColor, r as parseHex, t as blend } from "./color-Cr1VoL49.mjs";
2
- import { t as styleBuilder } from "./builder-BdYlK1Ew.mjs";
3
- import { n as inspectFormat, r as isMarkdown, t as inspect } from "./inspect-Cli1beu8.mjs";
3
+ import { n as inspectFormat, r as isMarkdown, t as inspect } from "./inspect-CxtcQch-.mjs";
4
4
  export { blend, inspect, inspectFormat, isHexColor, isMarkdown, parseHex, styleBuilder, toHex };
@@ -1,6 +1,6 @@
1
- import { S as unwrap } from "./reactive-DkP75TPk.mjs";
2
1
  import { t as Node } from "./node-CXNobGaP.mjs";
3
- import { o as formatText, t as calcLayout } from "./text-BEuhhxr7.mjs";
2
+ import { S as unwrap } from "./reactive-DkP75TPk.mjs";
3
+ import { o as formatText, t as calcLayout } from "./text-BLQXIh6Z.mjs";
4
4
  // src/widgets/text.ts
5
5
  var Text = class extends Node {
6
6
  async _render(ctx) {
@@ -29,4 +29,4 @@ function text(first, style) {
29
29
  }
30
30
  export { text as n, textContent as r, Text as t };
31
31
 
32
- //# sourceMappingURL=text-H_2kzwaz.mjs.map
32
+ //# sourceMappingURL=text-BKLHPMsQ.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"text-H_2kzwaz.mjs","names":[],"sources":["../src/widgets/text.ts"],"sourcesContent":["import type { MaybePromise } from \"@zaly/shared\"\nimport type { RenderCtx } from \"../core/ctx.ts\"\nimport type { Reactive } from \"../core/reactive.ts\"\nimport type { State } from \"../core/state.ts\"\nimport type { Style } from \"../style/types.ts\"\n\nimport { Node } from \"../core/node.ts\"\nimport { unwrap } from \"../core/reactive.ts\"\nimport { calcLayout, formatText } from \"../layout/text.ts\"\n\n/**\n * Text content — three forms, resolved at render time:\n *\n * 1. Plain string — static content.\n * 2. Reactive accessor (`signal()` / `memo()`) — re-reads on each\n * render and subscribes the node so signal writes invalidate.\n * 3. `(ctx) => string` — computed from the render context. Use this\n * for inline-styled spans via `ctx.style`.\n *\n * Branded accessors are picked up via `isAccessor`; any other function\n * is treated as the ctx-aware form. Plain strings pass through.\n *\n * ```ts\n * text(\"hello\")\n * text(name) // signal accessor\n * text(({ style }) => style.ok(`✓ ${count}`)) // ctx-aware\n * ```\n */\nexport type TextContent = Reactive<string> | ((ctx: RenderCtx) => MaybePromise<Reactive<string>>)\n\nexport interface TextStyle extends Style<false> {\n content: TextContent\n wrap?: \"word\" | \"char\" | \"none\"\n}\n\nexport class Text extends Node<TextStyle> {\n protected async _render(ctx: RenderCtx): Promise<string[]> {\n const content = await textContent(this.state.content, ctx)\n return formatText(content, {\n style: ctx.style.add(this.state),\n width: ctx.width,\n wrap: this.state.wrap,\n })\n }\n\n override async layout(ctx: RenderCtx) {\n return calcLayout(await textContent(this.state.content, ctx), { wrap: this.state.wrap })\n }\n}\n\nexport function textContent(content: TextContent, ctx: RenderCtx): Promise<string>\nexport function textContent(content: TextContent | undefined, ctx: RenderCtx): Promise<undefined>\nexport async function textContent(\n content: TextContent | undefined,\n ctx: RenderCtx\n): Promise<string | undefined> {\n if (content === undefined) return\n const raw = unwrap(content)\n return unwrap(typeof raw === \"string\" ? raw : await raw(ctx))\n}\n\n/**\n * Factory for `Text`. Content can be a plain string or a `(ctx) => string`\n * function that's called at render time — use the function form when you\n * want inline-styled spans via `ctx.style`.\n *\n * ```ts\n * text(\"hello\")\n * text(\"hello\", { fg: \"primary\", bold: true })\n * text({ content: \"hello\", fg: \"primary\" })\n * text(({ style }) => `ok: ${style.ok(\"yes\")}`)\n * ```\n */\nexport function text(content: TextContent, style?: Omit<State<TextStyle>, \"content\">): Text\nexport function text(style: State<TextStyle>): Text\nexport function text(\n first: TextContent | State<TextStyle>,\n style?: Omit<State<TextStyle>, \"content\">\n): Text {\n // TextContent: string | function (incl. reactive accessor) | …\n // TextStyle: plain object with a `content` field.\n // The TextStyle branch is picked only when `first` is a non-function\n // object — accessors are functions, so they go through the content path.\n if (typeof first === \"string\" || typeof first === \"function\") {\n return new Text({ content: first, ...style })\n }\n return new Text(first)\n}\n"],"mappings":";;;;AAmCA,IAAa,OAAb,cAA0B,KAAgB;CACxC,MAAgB,QAAQ,KAAmC;EACzD,MAAM,UAAU,MAAM,YAAY,KAAK,MAAM,SAAS,GAAG;EACzD,OAAO,WAAW,SAAS;GACzB,OAAO,IAAI,MAAM,IAAI,KAAK,KAAK;GAC/B,OAAO,IAAI;GACX,MAAM,KAAK,MAAM;EACnB,CAAC;CACH;CAEA,MAAe,OAAO,KAAgB;EACpC,OAAO,WAAW,MAAM,YAAY,KAAK,MAAM,SAAS,GAAG,GAAG,EAAE,MAAM,KAAK,MAAM,KAAK,CAAC;CACzF;AACF;AAIA,eAAsB,YACpB,SACA,KAC6B;CAC7B,IAAI,YAAY,KAAA,GAAW;CAC3B,MAAM,MAAM,OAAO,OAAO;CAC1B,OAAO,OAAO,OAAO,QAAQ,WAAW,MAAM,MAAM,IAAI,GAAG,CAAC;AAC9D;AAgBA,SAAgB,KACd,OACA,OACM;CAKN,IAAI,OAAO,UAAU,YAAY,OAAO,UAAU,YAChD,OAAO,IAAI,KAAK;EAAE,SAAS;EAAO,GAAG;CAAM,CAAC;CAE9C,OAAO,IAAI,KAAK,KAAK;AACvB"}
1
+ {"version":3,"file":"text-BKLHPMsQ.mjs","names":[],"sources":["../src/widgets/text.ts"],"sourcesContent":["import type { MaybePromise } from \"@zaly/shared\"\nimport type { RenderCtx } from \"../core/ctx.ts\"\nimport type { Reactive } from \"../core/reactive.ts\"\nimport type { State } from \"../core/state.ts\"\nimport type { Style } from \"../style/types.ts\"\n\nimport { Node } from \"../core/node.ts\"\nimport { unwrap } from \"../core/reactive.ts\"\nimport { calcLayout, formatText } from \"../layout/text.ts\"\n\n/**\n * Text content — three forms, resolved at render time:\n *\n * 1. Plain string — static content.\n * 2. Reactive accessor (`signal()` / `memo()`) — re-reads on each\n * render and subscribes the node so signal writes invalidate.\n * 3. `(ctx) => string` — computed from the render context. Use this\n * for inline-styled spans via `ctx.style`.\n *\n * Branded accessors are picked up via `isAccessor`; any other function\n * is treated as the ctx-aware form. Plain strings pass through.\n *\n * ```ts\n * text(\"hello\")\n * text(name) // signal accessor\n * text(({ style }) => style.ok(`✓ ${count}`)) // ctx-aware\n * ```\n */\nexport type TextContent = Reactive<string> | ((ctx: RenderCtx) => MaybePromise<Reactive<string>>)\n\nexport interface TextStyle extends Style<false> {\n content: TextContent\n wrap?: \"word\" | \"char\" | \"none\"\n}\n\nexport class Text extends Node<TextStyle> {\n protected async _render(ctx: RenderCtx): Promise<string[]> {\n const content = await textContent(this.state.content, ctx)\n return formatText(content, {\n style: ctx.style.add(this.state),\n width: ctx.width,\n wrap: this.state.wrap,\n })\n }\n\n override async layout(ctx: RenderCtx) {\n return calcLayout(await textContent(this.state.content, ctx), { wrap: this.state.wrap })\n }\n}\n\nexport function textContent(content: TextContent, ctx: RenderCtx): Promise<string>\nexport function textContent(content: TextContent | undefined, ctx: RenderCtx): Promise<undefined>\nexport async function textContent(\n content: TextContent | undefined,\n ctx: RenderCtx\n): Promise<string | undefined> {\n if (content === undefined) return\n const raw = unwrap(content)\n return unwrap(typeof raw === \"string\" ? raw : await raw(ctx))\n}\n\n/**\n * Factory for `Text`. Content can be a plain string or a `(ctx) => string`\n * function that's called at render time — use the function form when you\n * want inline-styled spans via `ctx.style`.\n *\n * ```ts\n * text(\"hello\")\n * text(\"hello\", { fg: \"primary\", bold: true })\n * text({ content: \"hello\", fg: \"primary\" })\n * text(({ style }) => `ok: ${style.ok(\"yes\")}`)\n * ```\n */\nexport function text(content: TextContent, style?: Omit<State<TextStyle>, \"content\">): Text\nexport function text(style: State<TextStyle>): Text\nexport function text(\n first: TextContent | State<TextStyle>,\n style?: Omit<State<TextStyle>, \"content\">\n): Text {\n // TextContent: string | function (incl. reactive accessor) | …\n // TextStyle: plain object with a `content` field.\n // The TextStyle branch is picked only when `first` is a non-function\n // object — accessors are functions, so they go through the content path.\n if (typeof first === \"string\" || typeof first === \"function\") {\n return new Text({ content: first, ...style })\n }\n return new Text(first)\n}\n"],"mappings":";;;;AAmCA,IAAa,OAAb,cAA0B,KAAgB;CACxC,MAAgB,QAAQ,KAAmC;EACzD,MAAM,UAAU,MAAM,YAAY,KAAK,MAAM,SAAS,GAAG;EACzD,OAAO,WAAW,SAAS;GACzB,OAAO,IAAI,MAAM,IAAI,KAAK,KAAK;GAC/B,OAAO,IAAI;GACX,MAAM,KAAK,MAAM;EACnB,CAAC;CACH;CAEA,MAAe,OAAO,KAAgB;EACpC,OAAO,WAAW,MAAM,YAAY,KAAK,MAAM,SAAS,GAAG,GAAG,EAAE,MAAM,KAAK,MAAM,KAAK,CAAC;CACzF;AACF;AAIA,eAAsB,YACpB,SACA,KAC6B;CAC7B,IAAI,YAAY,KAAA,GAAW;CAC3B,MAAM,MAAM,OAAO,OAAO;CAC1B,OAAO,OAAO,OAAO,QAAQ,WAAW,MAAM,MAAM,IAAI,GAAG,CAAC;AAC9D;AAgBA,SAAgB,KACd,OACA,OACM;CAKN,IAAI,OAAO,UAAU,YAAY,OAAO,UAAU,YAChD,OAAO,IAAI,KAAK;EAAE,SAAS;EAAO,GAAG;CAAM,CAAC;CAE9C,OAAO,IAAI,KAAK,KAAK;AACvB"}
@@ -1,4 +1,4 @@
1
- import { l as styleAnsi, n as ansiBg } from "./ansi-CxgRPLA2.mjs";
1
+ import { n as ansiBg, u as styleAnsi } from "./ansi-oiRnTQr9.mjs";
2
2
  import { clamp } from "@zaly/shared";
3
3
  import { hasAnsi, sliceAnsi, splitAnsi, stringWidth, stripAnsi, truncateAnsi, wrapAnsi } from "@zaly/shared/ansi";
4
4
  // src/layout/text.ts
@@ -108,4 +108,4 @@ function capitalize(s) {
108
108
  }
109
109
  export { formatLines as a, expandTabs as i, capitalize as n, formatText as o, countLines as r, calcLayout as t };
110
110
 
111
- //# sourceMappingURL=text-BEuhhxr7.mjs.map
111
+ //# sourceMappingURL=text-BLQXIh6Z.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"text-BEuhhxr7.mjs","names":[],"sources":["../src/layout/text.ts"],"sourcesContent":["import type { Layout } from \"../core/state.ts\"\nimport type { StyleBuilder } from \"../style/builder.ts\"\n\nimport { clamp } from \"@zaly/shared\"\nimport {\n hasAnsi,\n sliceAnsi,\n splitAnsi,\n stringWidth,\n stripAnsi,\n truncateAnsi,\n wrapAnsi,\n} from \"@zaly/shared/ansi\"\nimport { ansiBg, styleAnsi } from \"../style/ansi.ts\"\n\nexport type WrapMode = \"word\" | \"char\" | \"none\"\n\nconst ELLIPSIS = \"…\"\nconst TAB_WIDTH = 4\n\nexport function formatText(\n text: string,\n opts: {\n wrap?: WrapMode\n width: number\n style?: StyleBuilder\n /** When wrapping, preserve the indentation of the original text. */\n indent?: boolean\n /** When wrapping ANSI-styled text, pad wrapped fragments to `width`\n * using the background color active at the fragment's last cell.\n * Natural lines that already fit are left unchanged. */\n wrapBg?: boolean\n }\n): string[] {\n const mode = opts.wrap ?? \"word\"\n const lines = splitAnsi(expandTabs(text))\n const ret: string[] = []\n if (mode === \"none\") ret.push(...lines)\n else {\n for (const line of lines) {\n const sw = stringWidth(line)\n\n // Fast path for short lines that don't need wrapping\n if (sw <= opts.width) {\n ret.push(line)\n continue\n }\n\n const stripped = stripAnsi(line)\n\n // Long line that ends in (ansi) whitespace, so just strip\n if (stringWidth(stripped.trimEnd()) <= opts.width) {\n ret.push(sliceAnsi(line, 0, opts.width))\n continue\n }\n\n const indentWidth = opts.indent ? stringWidth(stripped.match(/^\\s*/)?.[0] ?? \"\") : 0\n const indent = indentWidth > 0 ? sliceAnsi(line, 0, indentWidth) : \"\"\n const bare = indent ? sliceAnsi(line, indentWidth) : line\n const wrapped = splitAnsi(wrapAnsi(bare, opts.width - indentWidth, { mode }))\n\n // * strip single leading space from wrapped lines after the first\n // * preserve indentation when enabled\n // * pad wrapped lines with bg color if padding is enabled and the line is short\n for (let r = 0; r < wrapped.length; r++) {\n let row = r > 0 && wrapped[r].startsWith(\" \") ? wrapped[r].slice(1) : wrapped[r]\n if (row === \"\" && r > 0 && r < wrapped.length - 1) continue\n if (indent) row = `${indent}${row}`\n if (opts.wrapBg) {\n const rowWidth = stringWidth(row)\n const bg = rowWidth > 0 ? ansiBg(row, rowWidth - 1) : undefined\n if (bg && rowWidth < opts.width) {\n row = `${row}${styleAnsi(\" \".repeat(opts.width - rowWidth), { bg })}`\n }\n }\n ret.push(row)\n }\n }\n }\n return ret.map((line) => (opts.style ? opts.style(line) : line))\n}\n\nexport function expandTabs(s: string, tabSize = TAB_WIDTH): string {\n if (!s.includes(\"\\t\")) return s\n const plain = hasAnsi(s) ? stripAnsi(s) : s\n const spaces: string[] = []\n let col = 0\n\n for (const ch of plain) {\n if (ch === \"\\t\") {\n const n = tabSize - (col % tabSize)\n spaces.push(\" \".repeat(n))\n col += n\n } else if (ch === \"\\n\" || ch === \"\\r\") {\n col = 0\n } else {\n col += stringWidth(ch)\n }\n }\n\n let i = 0\n return s.replaceAll(\"\\t\", () => spaces[i++] ?? \" \".repeat(tabSize))\n}\n\nexport function formatLines(\n text: string | string[],\n opts: {\n numbered?: boolean\n numberOffset?: number\n maxLineLength?: number\n offset?: number\n limit?: number\n more?: false | ((more: number, msg: string) => string)\n style?: StyleBuilder\n } = {}\n): string[] {\n const lines = (typeof text === \"string\" ? splitAnsi(text) : text).map((line) => expandTabs(line))\n const offset = clamp(opts.offset ?? 0, 0, lines.length - 1)\n const limit = clamp(opts.limit ?? lines.length, 1, lines.length - offset)\n const ellipsis = opts.style?.(ELLIPSIS) ?? ELLIPSIS\n let slice = lines\n .slice(offset, offset + limit)\n .map((line) => (opts.maxLineLength ? truncateAnsi(line, opts.maxLineLength, ellipsis) : line))\n\n const numberOffset = opts.numberOffset ?? offset + 1\n const gutterWidth = String(numberOffset + slice.length - 1).length + 2\n\n if (opts.numbered) {\n slice = slice.map((line, i) => {\n const n = numberOffset + i\n const lineo = `${String(n).padStart(gutterWidth - 2)} │`\n return `${opts.style?.(lineo) ?? lineo} ${line}`\n })\n }\n\n if (slice.length < lines.length && opts.more !== false) {\n const moreN = lines.length - slice.length\n let more = `+${moreN} more line${moreN > 1 ? \"s\" : \"\"}`\n more = opts.more?.(moreN, more) ?? more\n if (opts.numbered) {\n const moreGutter = `${\"…\".padStart(gutterWidth - 2)} │`\n slice.push(`${opts.style?.(moreGutter) ?? moreGutter} ${opts.style?.(more) ?? more}`)\n } else slice.push(opts.style?.(more) ?? more)\n }\n\n return slice\n}\n\nfunction maxContent(text: string): number {\n return text.split(\"\\n\").reduce((m, line) => Math.max(m, stringWidth(line)), 0)\n}\n\nfunction minContent(text: string, mode: WrapMode): number | undefined {\n switch (mode) {\n case \"none\": {\n return\n } // can't break, same as max\n case \"char\": {\n return 1\n } // can break anywhere → 1cell floor\n case \"word\": {\n // longest unbreakable run\n return text.split(/\\s+/).reduce((m, word) => Math.max(m, stringWidth(word)), 0)\n }\n default: {\n mode satisfies never // future modes get caught at type-check time\n return undefined\n }\n }\n}\n\nexport function calcLayout(text: string, opts: { wrap?: WrapMode } = {}): Layout {\n text = expandTabs(text)\n const width = maxContent(text)\n return {\n minWidth: minContent(text, opts.wrap ?? \"word\") ?? width,\n width,\n }\n}\n\nexport function countLines(text: string): number {\n let count = 0\n let pos = text.indexOf(\"\\n\")\n while (pos !== -1) {\n count++\n pos = text.indexOf(\"\\n\", pos + 1)\n }\n return count\n}\n\nexport function capitalize(s: string): string {\n return s.charAt(0).toUpperCase() + s.slice(1)\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"text-BLQXIh6Z.mjs","names":[],"sources":["../src/layout/text.ts"],"sourcesContent":["import type { Layout } from \"../core/state.ts\"\nimport type { StyleBuilder } from \"../style/builder.ts\"\n\nimport { clamp } from \"@zaly/shared\"\nimport {\n hasAnsi,\n sliceAnsi,\n splitAnsi,\n stringWidth,\n stripAnsi,\n truncateAnsi,\n wrapAnsi,\n} from \"@zaly/shared/ansi\"\nimport { ansiBg, styleAnsi } from \"../style/ansi.ts\"\n\nexport type WrapMode = \"word\" | \"char\" | \"none\"\n\nconst ELLIPSIS = \"…\"\nconst TAB_WIDTH = 4\n\nexport function formatText(\n text: string,\n opts: {\n wrap?: WrapMode\n width: number\n style?: StyleBuilder\n /** When wrapping, preserve the indentation of the original text. */\n indent?: boolean\n /** When wrapping ANSI-styled text, pad wrapped fragments to `width`\n * using the background color active at the fragment's last cell.\n * Natural lines that already fit are left unchanged. */\n wrapBg?: boolean\n }\n): string[] {\n const mode = opts.wrap ?? \"word\"\n const lines = splitAnsi(expandTabs(text))\n const ret: string[] = []\n if (mode === \"none\") ret.push(...lines)\n else {\n for (const line of lines) {\n const sw = stringWidth(line)\n\n // Fast path for short lines that don't need wrapping\n if (sw <= opts.width) {\n ret.push(line)\n continue\n }\n\n const stripped = stripAnsi(line)\n\n // Long line that ends in (ansi) whitespace, so just strip\n if (stringWidth(stripped.trimEnd()) <= opts.width) {\n ret.push(sliceAnsi(line, 0, opts.width))\n continue\n }\n\n const indentWidth = opts.indent ? stringWidth(stripped.match(/^\\s*/)?.[0] ?? \"\") : 0\n const indent = indentWidth > 0 ? sliceAnsi(line, 0, indentWidth) : \"\"\n const bare = indent ? sliceAnsi(line, indentWidth) : line\n const wrapped = splitAnsi(wrapAnsi(bare, opts.width - indentWidth, { mode }))\n\n // * strip single leading space from wrapped lines after the first\n // * preserve indentation when enabled\n // * pad wrapped lines with bg color if padding is enabled and the line is short\n for (let r = 0; r < wrapped.length; r++) {\n let row = r > 0 && wrapped[r].startsWith(\" \") ? wrapped[r].slice(1) : wrapped[r]\n if (row === \"\" && r > 0 && r < wrapped.length - 1) continue\n if (indent) row = `${indent}${row}`\n if (opts.wrapBg) {\n const rowWidth = stringWidth(row)\n const bg = rowWidth > 0 ? ansiBg(row, rowWidth - 1) : undefined\n if (bg && rowWidth < opts.width) {\n row = `${row}${styleAnsi(\" \".repeat(opts.width - rowWidth), { bg })}`\n }\n }\n ret.push(row)\n }\n }\n }\n return ret.map((line) => (opts.style ? opts.style(line) : line))\n}\n\nexport function expandTabs(s: string, tabSize = TAB_WIDTH): string {\n if (!s.includes(\"\\t\")) return s\n const plain = hasAnsi(s) ? stripAnsi(s) : s\n const spaces: string[] = []\n let col = 0\n\n for (const ch of plain) {\n if (ch === \"\\t\") {\n const n = tabSize - (col % tabSize)\n spaces.push(\" \".repeat(n))\n col += n\n } else if (ch === \"\\n\" || ch === \"\\r\") {\n col = 0\n } else {\n col += stringWidth(ch)\n }\n }\n\n let i = 0\n return s.replaceAll(\"\\t\", () => spaces[i++] ?? \" \".repeat(tabSize))\n}\n\nexport function formatLines(\n text: string | string[],\n opts: {\n numbered?: boolean\n numberOffset?: number\n maxLineLength?: number\n offset?: number\n limit?: number\n more?: false | ((more: number, msg: string) => string)\n style?: StyleBuilder\n } = {}\n): string[] {\n const lines = (typeof text === \"string\" ? splitAnsi(text) : text).map((line) => expandTabs(line))\n const offset = clamp(opts.offset ?? 0, 0, lines.length - 1)\n const limit = clamp(opts.limit ?? lines.length, 1, lines.length - offset)\n const ellipsis = opts.style?.(ELLIPSIS) ?? ELLIPSIS\n let slice = lines\n .slice(offset, offset + limit)\n .map((line) => (opts.maxLineLength ? truncateAnsi(line, opts.maxLineLength, ellipsis) : line))\n\n const numberOffset = opts.numberOffset ?? offset + 1\n const gutterWidth = String(numberOffset + slice.length - 1).length + 2\n\n if (opts.numbered) {\n slice = slice.map((line, i) => {\n const n = numberOffset + i\n const lineo = `${String(n).padStart(gutterWidth - 2)} │`\n return `${opts.style?.(lineo) ?? lineo} ${line}`\n })\n }\n\n if (slice.length < lines.length && opts.more !== false) {\n const moreN = lines.length - slice.length\n let more = `+${moreN} more line${moreN > 1 ? \"s\" : \"\"}`\n more = opts.more?.(moreN, more) ?? more\n if (opts.numbered) {\n const moreGutter = `${\"…\".padStart(gutterWidth - 2)} │`\n slice.push(`${opts.style?.(moreGutter) ?? moreGutter} ${opts.style?.(more) ?? more}`)\n } else slice.push(opts.style?.(more) ?? more)\n }\n\n return slice\n}\n\nfunction maxContent(text: string): number {\n return text.split(\"\\n\").reduce((m, line) => Math.max(m, stringWidth(line)), 0)\n}\n\nfunction minContent(text: string, mode: WrapMode): number | undefined {\n switch (mode) {\n case \"none\": {\n return\n } // can't break, same as max\n case \"char\": {\n return 1\n } // can break anywhere → 1cell floor\n case \"word\": {\n // longest unbreakable run\n return text.split(/\\s+/).reduce((m, word) => Math.max(m, stringWidth(word)), 0)\n }\n default: {\n mode satisfies never // future modes get caught at type-check time\n return undefined\n }\n }\n}\n\nexport function calcLayout(text: string, opts: { wrap?: WrapMode } = {}): Layout {\n text = expandTabs(text)\n const width = maxContent(text)\n return {\n minWidth: minContent(text, opts.wrap ?? \"word\") ?? width,\n width,\n }\n}\n\nexport function countLines(text: string): number {\n let count = 0\n let pos = text.indexOf(\"\\n\")\n while (pos !== -1) {\n count++\n pos = text.indexOf(\"\\n\", pos + 1)\n }\n return count\n}\n\nexport function capitalize(s: string): string {\n return s.charAt(0).toUpperCase() + s.slice(1)\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { X as Layout } from "./queries-Dmd3IjSd.mjs";
1
+ import { X as Layout } from "./queries-BqFMpQAf.mjs";
2
2
  import { a as StyleBuilder } from "./inspect-hSl3U2BD.mjs";
3
3
  type WrapMode = "word" | "char" | "none";
4
4
  declare function formatText(text: string, opts: {
@@ -28,4 +28,4 @@ declare function calcLayout(text: string, opts?: {
28
28
  declare function countLines(text: string): number;
29
29
  declare function capitalize(s: string): string;
30
30
  export { expandTabs as a, countLines as i, calcLayout as n, formatLines as o, capitalize as r, formatText as s, WrapMode as t };
31
- //# sourceMappingURL=text-DdkJXgoC.d.mts.map
31
+ //# sourceMappingURL=text-BnlU1Q9y.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"text-DdkJXgoC.d.mts","names":[],"sources":["../src/layout/text.ts"],"mappings":";;KAeY;iBAKI,WACd,cACA;EACE,OAAO;EACP;EACA,QAAQ;;EAER;;;;EAIA;;iBAmDY,WAAW,WAAW;iBAsBtB,YACd,yBACA;EACE;EACA;EACA;EACA;EACA;EACA,iBAAiB,cAAc;EAC/B,QAAQ;;iBA0DI,WAAW,cAAc;EAAQ,OAAO;IAAkB;iBAS1D,WAAW;iBAUX,WAAW"}
1
+ {"version":3,"file":"text-BnlU1Q9y.d.mts","names":[],"sources":["../src/layout/text.ts"],"mappings":";;KAeY;iBAKI,WACd,cACA;EACE,OAAO;EACP;EACA,QAAQ;;EAER;;;;EAIA;;iBAmDY,WAAW,WAAW;iBAsBtB,YACd,yBACA;EACE;EACA;EACA;EACA;EACA;EACA,iBAAiB,cAAc;EAC/B,QAAQ;;iBA0DI,WAAW,cAAc;EAAQ,OAAO;IAAkB;iBAS1D,WAAW;iBAUX,WAAW"}
package/dist/text.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { a as expandTabs, i as countLines, n as calcLayout, o as formatLines, r as capitalize, s as formatText, t as WrapMode } from "./text-DdkJXgoC.mjs";
1
+ import { a as expandTabs, i as countLines, n as calcLayout, o as formatLines, r as capitalize, s as formatText, t as WrapMode } from "./text-BnlU1Q9y.mjs";
2
2
  export { WrapMode, calcLayout, capitalize, countLines, expandTabs, formatLines, formatText };
package/dist/text.mjs CHANGED
@@ -1 +1 @@
1
- export { t as calcLayout, n as capitalize, r as countLines, i as expandTabs, a as formatLines, o as formatText } from "./text-BEuhhxr7.mjs";
1
+ export { t as calcLayout, n as capitalize, r as countLines, i as expandTabs, a as formatLines, o as formatText } from "./text-BLQXIh6Z.mjs";
@@ -1,4 +1,4 @@
1
- import { n as resolveAnsiStyle } from "./style-Cw_EuszU.mjs";
1
+ import { n as resolveAnsiStyle } from "./style-DTwmlkfR.mjs";
2
2
  import { hash } from "@zaly/shared";
3
3
  // src/shiki/theme.ts
4
4
  const syntaxScopes = [
@@ -57,4 +57,4 @@ function shikiTheme(theme, selection = "auto") {
57
57
  }
58
58
  export { syntaxScopes as n, shikiTheme as t };
59
59
 
60
- //# sourceMappingURL=theme-B8hb1lPU.mjs.map
60
+ //# sourceMappingURL=theme-CG51x7aG.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"theme-B8hb1lPU.mjs","names":[],"sources":["../src/shiki/theme.ts"],"sourcesContent":["import type { AnsiStyle } from \"../style/types.ts\"\nimport type { Theme } from \"../themes/types.ts\"\nimport type { GeneratedShikiTheme, ShikiSelection, ShikiThemeInput } from \"./types.ts\"\n\nimport { hash } from \"@zaly/shared\"\nimport { resolveAnsiStyle } from \"../style/style.ts\"\n\nexport const syntaxScopes = [\n [\"comment\", [\"comment\"]],\n [\"syntaxString\", [\"string\"]],\n [\"syntaxNumber\", [\"constant.numeric\"]],\n [\n \"syntaxBoolean\",\n [\"constant.language.boolean\", \"constant.language.true\", \"constant.language.false\"],\n ],\n [\"syntaxFunction\", [\"entity.name.function\", \"support.function\", \"variable.function\"]],\n [\n \"syntaxField\",\n [\n \"variable.other.property\",\n \"variable.other.object.property\",\n \"support.type.property-name\",\n \"meta.object-literal.key\",\n \"entity.other.attribute-name\",\n ],\n ],\n [\"syntaxConstant\", [\"constant\", \"variable.other.constant\"]],\n [\n \"syntaxSpecial\",\n [\n \"keyword\",\n \"storage\",\n \"entity.name.type\",\n \"support.type\",\n \"constant.language\",\n \"entity.name.tag\",\n ],\n ],\n [\"syntaxDelimiter\", [\"punctuation.separator\", \"punctuation.terminator\", \"punctuation.accessor\"]],\n [\"syntaxBracket\", [\"punctuation.section\", \"punctuation.definition\"]],\n] as const\n\nconst cache = new WeakMap<Theme, GeneratedShikiTheme>()\n\n/** Resolve highlighting independently of a theme's display name or origin. */\nexport function shikiTheme(theme: Theme, selection: ShikiSelection = \"auto\"): ShikiThemeInput {\n const selected = selection === \"auto\" ? theme.shiki : selection\n if (selected && selected !== \"auto\") return selected\n let generated = cache.get(theme)\n if (generated) return generated\n const styles: AnsiStyle[] = [\n resolveAnsiStyle({ fg: \"fg\" }, theme),\n ...syntaxScopes.map(([slot]) => resolveAnsiStyle(slot, theme)),\n ]\n const appearance = theme.appearance\n generated = { appearance, name: `zaly-${hash(JSON.stringify([appearance, styles]))}`, styles }\n cache.set(theme, generated)\n return generated\n}\n"],"mappings":";;;AAOA,MAAa,eAAe;CAC1B,CAAC,WAAW,CAAC,SAAS,CAAC;CACvB,CAAC,gBAAgB,CAAC,QAAQ,CAAC;CAC3B,CAAC,gBAAgB,CAAC,kBAAkB,CAAC;CACrC,CACE,iBACA;EAAC;EAA6B;EAA0B;CAAyB,CACnF;CACA,CAAC,kBAAkB;EAAC;EAAwB;EAAoB;CAAmB,CAAC;CACpF,CACE,eACA;EACE;EACA;EACA;EACA;EACA;CACF,CACF;CACA,CAAC,kBAAkB,CAAC,YAAY,yBAAyB,CAAC;CAC1D,CACE,iBACA;EACE;EACA;EACA;EACA;EACA;EACA;CACF,CACF;CACA,CAAC,mBAAmB;EAAC;EAAyB;EAA0B;CAAsB,CAAC;CAC/F,CAAC,iBAAiB,CAAC,uBAAuB,wBAAwB,CAAC;AACrE;AAEA,MAAM,wBAAQ,IAAI,QAAoC;;AAGtD,SAAgB,WAAW,OAAc,YAA4B,QAAyB;CAC5F,MAAM,WAAW,cAAc,SAAS,MAAM,QAAQ;CACtD,IAAI,YAAY,aAAa,QAAQ,OAAO;CAC5C,IAAI,YAAY,MAAM,IAAI,KAAK;CAC/B,IAAI,WAAW,OAAO;CACtB,MAAM,SAAsB,CAC1B,iBAAiB,EAAE,IAAI,KAAK,GAAG,KAAK,GACpC,GAAG,aAAa,KAAK,CAAC,UAAU,iBAAiB,MAAM,KAAK,CAAC,CAC/D;CACA,MAAM,aAAa,MAAM;CACzB,YAAY;EAAE;EAAY,MAAM,QAAQ,KAAK,KAAK,UAAU,CAAC,YAAY,MAAM,CAAC,CAAC;EAAK;CAAO;CAC7F,MAAM,IAAI,OAAO,SAAS;CAC1B,OAAO;AACT"}
1
+ {"version":3,"file":"theme-CG51x7aG.mjs","names":[],"sources":["../src/shiki/theme.ts"],"sourcesContent":["import type { AnsiStyle } from \"../style/types.ts\"\nimport type { Theme } from \"../themes/types.ts\"\nimport type { GeneratedShikiTheme, ShikiSelection, ShikiThemeInput } from \"./types.ts\"\n\nimport { hash } from \"@zaly/shared\"\nimport { resolveAnsiStyle } from \"../style/style.ts\"\n\nexport const syntaxScopes = [\n [\"comment\", [\"comment\"]],\n [\"syntaxString\", [\"string\"]],\n [\"syntaxNumber\", [\"constant.numeric\"]],\n [\n \"syntaxBoolean\",\n [\"constant.language.boolean\", \"constant.language.true\", \"constant.language.false\"],\n ],\n [\"syntaxFunction\", [\"entity.name.function\", \"support.function\", \"variable.function\"]],\n [\n \"syntaxField\",\n [\n \"variable.other.property\",\n \"variable.other.object.property\",\n \"support.type.property-name\",\n \"meta.object-literal.key\",\n \"entity.other.attribute-name\",\n ],\n ],\n [\"syntaxConstant\", [\"constant\", \"variable.other.constant\"]],\n [\n \"syntaxSpecial\",\n [\n \"keyword\",\n \"storage\",\n \"entity.name.type\",\n \"support.type\",\n \"constant.language\",\n \"entity.name.tag\",\n ],\n ],\n [\"syntaxDelimiter\", [\"punctuation.separator\", \"punctuation.terminator\", \"punctuation.accessor\"]],\n [\"syntaxBracket\", [\"punctuation.section\", \"punctuation.definition\"]],\n] as const\n\nconst cache = new WeakMap<Theme, GeneratedShikiTheme>()\n\n/** Resolve highlighting independently of a theme's display name or origin. */\nexport function shikiTheme(theme: Theme, selection: ShikiSelection = \"auto\"): ShikiThemeInput {\n const selected = selection === \"auto\" ? theme.shiki : selection\n if (selected && selected !== \"auto\") return selected\n let generated = cache.get(theme)\n if (generated) return generated\n const styles: AnsiStyle[] = [\n resolveAnsiStyle({ fg: \"fg\" }, theme),\n ...syntaxScopes.map(([slot]) => resolveAnsiStyle(slot, theme)),\n ]\n const appearance = theme.appearance\n generated = { appearance, name: `zaly-${hash(JSON.stringify([appearance, styles]))}`, styles }\n cache.set(theme, generated)\n return generated\n}\n"],"mappings":";;;AAOA,MAAa,eAAe;CAC1B,CAAC,WAAW,CAAC,SAAS,CAAC;CACvB,CAAC,gBAAgB,CAAC,QAAQ,CAAC;CAC3B,CAAC,gBAAgB,CAAC,kBAAkB,CAAC;CACrC,CACE,iBACA;EAAC;EAA6B;EAA0B;CAAyB,CACnF;CACA,CAAC,kBAAkB;EAAC;EAAwB;EAAoB;CAAmB,CAAC;CACpF,CACE,eACA;EACE;EACA;EACA;EACA;EACA;CACF,CACF;CACA,CAAC,kBAAkB,CAAC,YAAY,yBAAyB,CAAC;CAC1D,CACE,iBACA;EACE;EACA;EACA;EACA;EACA;EACA;CACF,CACF;CACA,CAAC,mBAAmB;EAAC;EAAyB;EAA0B;CAAsB,CAAC;CAC/F,CAAC,iBAAiB,CAAC,uBAAuB,wBAAwB,CAAC;AACrE;AAEA,MAAM,wBAAQ,IAAI,QAAoC;;AAGtD,SAAgB,WAAW,OAAc,YAA4B,QAAyB;CAC5F,MAAM,WAAW,cAAc,SAAS,MAAM,QAAQ;CACtD,IAAI,YAAY,aAAa,QAAQ,OAAO;CAC5C,IAAI,YAAY,MAAM,IAAI,KAAK;CAC/B,IAAI,WAAW,OAAO;CACtB,MAAM,SAAsB,CAC1B,iBAAiB,EAAE,IAAI,KAAK,GAAG,KAAK,GACpC,GAAG,aAAa,KAAK,CAAC,UAAU,iBAAiB,MAAM,KAAK,CAAC,CAC/D;CACA,MAAM,aAAa,MAAM;CACzB,YAAY;EAAE;EAAY,MAAM,QAAQ,KAAK,KAAK,UAAU,CAAC,YAAY,MAAM,CAAC,CAAC;EAAK;CAAO;CAC7F,MAAM,IAAI,OAAO,SAAS;CAC1B,OAAO;AACT"}
@@ -1,6 +1,6 @@
1
1
  import { S as unwrap, h as memo } from "./reactive-DkP75TPk.mjs";
2
+ import { n as select } from "./select-BlsSDBlV.mjs";
2
3
  import { t as widget } from "./widget-sFveyrZE.mjs";
3
- import { n as select } from "./select-CUmAFKJh.mjs";
4
4
  import { stringWidth } from "@zaly/shared/ansi";
5
5
  // src/widgets/tree.ts
6
6
  const icons = {
@@ -69,4 +69,4 @@ const tree = widget((props) => {
69
69
  });
70
70
  export { tree as t };
71
71
 
72
- //# sourceMappingURL=tree-D6NvMQx8.mjs.map
72
+ //# sourceMappingURL=tree-4aaQKFtF.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"tree-D6NvMQx8.mjs","names":[],"sources":["../src/widgets/tree.ts"],"sourcesContent":["import type { Reactive } from \"../core/reactive.ts\"\nimport type { Option, Select, SelectState } from \"./select.ts\"\n\nimport { stringWidth } from \"@zaly/shared/ansi\"\nimport { memo, unwrap } from \"../core/reactive.ts\"\nimport { select } from \"./select.ts\"\nimport { widget } from \"./widget.ts\"\n\nexport type TreeItem<T extends Option = Option> = T & {\n children?: TreeItem<T>[]\n icon?: string\n}\n\nexport type TreeProps<T extends TreeItem = TreeItem> = Omit<SelectState<T>, \"items\" | \"active\"> & {\n tree: Reactive<T>\n /** If true, the root node will be rendered and selectable. Defaults to false. */\n root?: boolean\n active?: T | ((item: T) => boolean)\n}\n\nconst icons = {\n // last: \"└─\",\n last: \"╰─\",\n middle: \"├─\",\n vertical: \"│ \",\n}\n\nexport type TreeNode<T extends TreeItem> = {\n last?: boolean\n parent?: T\n}\n\nclass Tree<T extends TreeItem> {\n nodes = new Map<T, TreeNode<T>>()\n items: T[] = []\n\n constructor(public root: T) {\n this.#build(root, undefined, true)\n }\n\n #build(item: T, parent?: T, last?: boolean) {\n this.nodes.set(item, { last, parent })\n this.items.push(item)\n const children = item.children ?? []\n for (let c = 0; c < children.length; c++) {\n const child = children[c] as T\n this.#build(child, item, c === children.length - 1)\n }\n }\n\n node(item: T) {\n return this.nodes.get(item)\n }\n}\n\nexport const tree = widget(\n <T extends TreeItem>(props: TreeProps<T>): Select<T> & { items: Reactive<T[]> } => {\n const builder = memo(() => new Tree(unwrap(props.tree)))\n const items = memo(() => (props.root === true ? builder().items : builder().items.slice(1)))\n\n const activeFn =\n typeof props.active === \"function\" ? props.active : (i: T) => i === props.active\n const active = props.active ? items().findIndex((i) => activeFn(i)) : -1\n\n const ret = select({ ...props, active: active === -1 ? 0 : active, items })\n\n ret.extendRenderer((prev) => (item, ctx) => {\n const t = builder()\n const path: string[] = []\n const s = ctx.style\n const itemNode = t.node(item)\n let n = t.node(item)\n while (n?.parent) {\n if (props.root !== true && n.parent === props.tree) break\n let icon = \"\"\n if (n !== itemNode) icon = n.last ? \" \" : icons.vertical\n else icon = n.last ? icons.last : icons.middle\n path.unshift(icon)\n n = t.node(n.parent)\n }\n const prefix = path.join(\"\")\n const prefixWidth = stringWidth(prefix)\n const text = prev(item, { ...ctx, prefixWidth, width: ctx.width - prefixWidth }).replace(\n /\\s/g,\n \" \"\n )\n return `${s.gutter(prefix)}${text}`\n })\n\n return Object.assign(ret, { items })\n }\n)\n"],"mappings":";;;;;AAoBA,MAAM,QAAQ;CAEZ,MAAM;CACN,QAAQ;CACR,UAAU;AACZ;AAOA,IAAM,OAAN,MAA+B;CAIV;CAHnB,wBAAQ,IAAI,IAAoB;CAChC,QAAa,CAAC;CAEd,YAAY,MAAgB;EAAT,KAAA,OAAA;EACjB,KAAK,OAAO,MAAM,KAAA,GAAW,IAAI;CACnC;CAEA,OAAO,MAAS,QAAY,MAAgB;EAC1C,KAAK,MAAM,IAAI,MAAM;GAAE;GAAM;EAAO,CAAC;EACrC,KAAK,MAAM,KAAK,IAAI;EACpB,MAAM,WAAW,KAAK,YAAY,CAAC;EACnC,KAAK,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;GACxC,MAAM,QAAQ,SAAS;GACvB,KAAK,OAAO,OAAO,MAAM,MAAM,SAAS,SAAS,CAAC;EACpD;CACF;CAEA,KAAK,MAAS;EACZ,OAAO,KAAK,MAAM,IAAI,IAAI;CAC5B;AACF;AAEA,MAAa,OAAO,QACG,UAA8D;CACjF,MAAM,UAAU,WAAW,IAAI,KAAK,OAAO,MAAM,IAAI,CAAC,CAAC;CACvD,MAAM,QAAQ,WAAY,MAAM,SAAS,OAAO,QAAQ,CAAC,CAAC,QAAQ,QAAQ,CAAC,CAAC,MAAM,MAAM,CAAC,CAAE;CAE3F,MAAM,WACJ,OAAO,MAAM,WAAW,aAAa,MAAM,UAAU,MAAS,MAAM,MAAM;CAC5E,MAAM,SAAS,MAAM,SAAS,MAAM,CAAC,CAAC,WAAW,MAAM,SAAS,CAAC,CAAC,IAAI;CAEtE,MAAM,MAAM,OAAO;EAAE,GAAG;EAAO,QAAQ,WAAW,KAAK,IAAI;EAAQ;CAAM,CAAC;CAE1E,IAAI,gBAAgB,UAAU,MAAM,QAAQ;EAC1C,MAAM,IAAI,QAAQ;EAClB,MAAM,OAAiB,CAAC;EACxB,MAAM,IAAI,IAAI;EACd,MAAM,WAAW,EAAE,KAAK,IAAI;EAC5B,IAAI,IAAI,EAAE,KAAK,IAAI;EACnB,OAAO,GAAG,QAAQ;GAChB,IAAI,MAAM,SAAS,QAAQ,EAAE,WAAW,MAAM,MAAM;GACpD,IAAI,OAAO;GACX,IAAI,MAAM,UAAU,OAAO,EAAE,OAAO,OAAO,MAAM;QAC5C,OAAO,EAAE,OAAO,MAAM,OAAO,MAAM;GACxC,KAAK,QAAQ,IAAI;GACjB,IAAI,EAAE,KAAK,EAAE,MAAM;EACrB;EACA,MAAM,SAAS,KAAK,KAAK,EAAE;EAC3B,MAAM,cAAc,YAAY,MAAM;EACtC,MAAM,OAAO,KAAK,MAAM;GAAE,GAAG;GAAK;GAAa,OAAO,IAAI,QAAQ;EAAY,CAAC,CAAC,CAAC,QAC/E,OACA,GACF;EACA,OAAO,GAAG,EAAE,OAAO,MAAM,IAAI;CAC/B,CAAC;CAED,OAAO,OAAO,OAAO,KAAK,EAAE,MAAM,CAAC;AACrC,CACF"}
1
+ {"version":3,"file":"tree-4aaQKFtF.mjs","names":[],"sources":["../src/widgets/tree.ts"],"sourcesContent":["import type { Reactive } from \"../core/reactive.ts\"\nimport type { Option, Select, SelectState } from \"./select.ts\"\n\nimport { stringWidth } from \"@zaly/shared/ansi\"\nimport { memo, unwrap } from \"../core/reactive.ts\"\nimport { select } from \"./select.ts\"\nimport { widget } from \"./widget.ts\"\n\nexport type TreeItem<T extends Option = Option> = T & {\n children?: TreeItem<T>[]\n icon?: string\n}\n\nexport type TreeProps<T extends TreeItem = TreeItem> = Omit<SelectState<T>, \"items\" | \"active\"> & {\n tree: Reactive<T>\n /** If true, the root node will be rendered and selectable. Defaults to false. */\n root?: boolean\n active?: T | ((item: T) => boolean)\n}\n\nconst icons = {\n // last: \"└─\",\n last: \"╰─\",\n middle: \"├─\",\n vertical: \"│ \",\n}\n\nexport type TreeNode<T extends TreeItem> = {\n last?: boolean\n parent?: T\n}\n\nclass Tree<T extends TreeItem> {\n nodes = new Map<T, TreeNode<T>>()\n items: T[] = []\n\n constructor(public root: T) {\n this.#build(root, undefined, true)\n }\n\n #build(item: T, parent?: T, last?: boolean) {\n this.nodes.set(item, { last, parent })\n this.items.push(item)\n const children = item.children ?? []\n for (let c = 0; c < children.length; c++) {\n const child = children[c] as T\n this.#build(child, item, c === children.length - 1)\n }\n }\n\n node(item: T) {\n return this.nodes.get(item)\n }\n}\n\nexport const tree = widget(\n <T extends TreeItem>(props: TreeProps<T>): Select<T> & { items: Reactive<T[]> } => {\n const builder = memo(() => new Tree(unwrap(props.tree)))\n const items = memo(() => (props.root === true ? builder().items : builder().items.slice(1)))\n\n const activeFn =\n typeof props.active === \"function\" ? props.active : (i: T) => i === props.active\n const active = props.active ? items().findIndex((i) => activeFn(i)) : -1\n\n const ret = select({ ...props, active: active === -1 ? 0 : active, items })\n\n ret.extendRenderer((prev) => (item, ctx) => {\n const t = builder()\n const path: string[] = []\n const s = ctx.style\n const itemNode = t.node(item)\n let n = t.node(item)\n while (n?.parent) {\n if (props.root !== true && n.parent === props.tree) break\n let icon = \"\"\n if (n !== itemNode) icon = n.last ? \" \" : icons.vertical\n else icon = n.last ? icons.last : icons.middle\n path.unshift(icon)\n n = t.node(n.parent)\n }\n const prefix = path.join(\"\")\n const prefixWidth = stringWidth(prefix)\n const text = prev(item, { ...ctx, prefixWidth, width: ctx.width - prefixWidth }).replace(\n /\\s/g,\n \" \"\n )\n return `${s.gutter(prefix)}${text}`\n })\n\n return Object.assign(ret, { items })\n }\n)\n"],"mappings":";;;;;AAoBA,MAAM,QAAQ;CAEZ,MAAM;CACN,QAAQ;CACR,UAAU;AACZ;AAOA,IAAM,OAAN,MAA+B;CAIV;CAHnB,wBAAQ,IAAI,IAAoB;CAChC,QAAa,CAAC;CAEd,YAAY,MAAgB;EAAT,KAAA,OAAA;EACjB,KAAK,OAAO,MAAM,KAAA,GAAW,IAAI;CACnC;CAEA,OAAO,MAAS,QAAY,MAAgB;EAC1C,KAAK,MAAM,IAAI,MAAM;GAAE;GAAM;EAAO,CAAC;EACrC,KAAK,MAAM,KAAK,IAAI;EACpB,MAAM,WAAW,KAAK,YAAY,CAAC;EACnC,KAAK,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;GACxC,MAAM,QAAQ,SAAS;GACvB,KAAK,OAAO,OAAO,MAAM,MAAM,SAAS,SAAS,CAAC;EACpD;CACF;CAEA,KAAK,MAAS;EACZ,OAAO,KAAK,MAAM,IAAI,IAAI;CAC5B;AACF;AAEA,MAAa,OAAO,QACG,UAA8D;CACjF,MAAM,UAAU,WAAW,IAAI,KAAK,OAAO,MAAM,IAAI,CAAC,CAAC;CACvD,MAAM,QAAQ,WAAY,MAAM,SAAS,OAAO,QAAQ,CAAC,CAAC,QAAQ,QAAQ,CAAC,CAAC,MAAM,MAAM,CAAC,CAAE;CAE3F,MAAM,WACJ,OAAO,MAAM,WAAW,aAAa,MAAM,UAAU,MAAS,MAAM,MAAM;CAC5E,MAAM,SAAS,MAAM,SAAS,MAAM,CAAC,CAAC,WAAW,MAAM,SAAS,CAAC,CAAC,IAAI;CAEtE,MAAM,MAAM,OAAO;EAAE,GAAG;EAAO,QAAQ,WAAW,KAAK,IAAI;EAAQ;CAAM,CAAC;CAE1E,IAAI,gBAAgB,UAAU,MAAM,QAAQ;EAC1C,MAAM,IAAI,QAAQ;EAClB,MAAM,OAAiB,CAAC;EACxB,MAAM,IAAI,IAAI;EACd,MAAM,WAAW,EAAE,KAAK,IAAI;EAC5B,IAAI,IAAI,EAAE,KAAK,IAAI;EACnB,OAAO,GAAG,QAAQ;GAChB,IAAI,MAAM,SAAS,QAAQ,EAAE,WAAW,MAAM,MAAM;GACpD,IAAI,OAAO;GACX,IAAI,MAAM,UAAU,OAAO,EAAE,OAAO,OAAO,MAAM;QAC5C,OAAO,EAAE,OAAO,MAAM,OAAO,MAAM;GACxC,KAAK,QAAQ,IAAI;GACjB,IAAI,EAAE,KAAK,EAAE,MAAM;EACrB;EACA,MAAM,SAAS,KAAK,KAAK,EAAE;EAC3B,MAAM,cAAc,YAAY,MAAM;EACtC,MAAM,OAAO,KAAK,MAAM;GAAE,GAAG;GAAK;GAAa,OAAO,IAAI,QAAQ;EAAY,CAAC,CAAC,CAAC,QAC/E,OACA,GACF;EACA,OAAO,GAAG,EAAE,OAAO,MAAM,IAAI;CAC/B,CAAC;CAED,OAAO,OAAO,OAAO,KAAK,EAAE,MAAM,CAAC;AACrC,CACF"}
@@ -1,5 +1,5 @@
1
- import { it as Reactive } from "./queries-Dmd3IjSd.mjs";
2
- import { i as Select, o as SelectState, t as Option } from "./select-BZCFXdjp.mjs";
1
+ import { it as Reactive } from "./queries-BqFMpQAf.mjs";
2
+ import { i as Select, o as SelectState, t as Option } from "./select-BeP7rFkP.mjs";
3
3
  type TreeItem<T extends Option = Option> = T & {
4
4
  children?: TreeItem<T>[];
5
5
  icon?: string;
@@ -18,4 +18,4 @@ declare const tree: <T extends TreeItem>(props: TreeProps<T>) => Select<T> & {
18
18
  items: Reactive<T[]>;
19
19
  };
20
20
  export { tree as i, TreeNode as n, TreeProps as r, TreeItem as t };
21
- //# sourceMappingURL=tree-Berzv8Rz.d.mts.map
21
+ //# sourceMappingURL=tree-DNAE_C7w.d.mts.map